andrea
andrea

Reputation: 899

Create OpenGL textures using Eigen

A single channel R32F texture can be created quite easily (and safely) in Eigen:

    glGenTextures(1, &_tex);
    glBindTexture(GL_TEXTURE_2D, _tex);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    int rows = 480, cols = 640;
    static Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> A(rows,cols);
    A.setConstant(rows, cols, 0.0f);
    for(int row=0; row<A.rows(); row++)
        for(int col=0; col<A.cols(); col++)
            A(row,col) = .5f + .5*sin( 10* /*period*/ 2*3.14*row/A.rows() );
    glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, cols, rows, 0, GL_RED, GL_FLOAT, A.data());

The code above generates this image: striped along columns

A similar approach can be used to generate RGB32F textures:

    glGenTextures(1, &_tex);
    glBindTexture(GL_TEXTURE_2D, _tex);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    int rows = 480;
    int cols = 640;
    static Eigen::Matrix<Eigen::Vector3f, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> A(rows,cols);
    for(int row=0; row<A.rows(); row++)
        for(int col=0; col<A.cols(); col++)
            A(row,col) = vec3(row/((float)A.rows()), col/((float)A.cols()), 0);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, cols, rows, 0, GL_RGB, GL_FLOAT, A.data());

The code above generates this image: quad colored according to x and y:

Everything seems to work well on my machine, however, can this procedure result in any problem? especially considering what is mentioned in the Eigen documentation: http://eigen.tuxfamily.org/dox/TopicCustomizingEigen.html#user_defined_scalars

Upvotes: 1

Views: 238

Answers (2)

ggael
ggael

Reputation: 29225

As Avi said, such use case is perfectly fine.

For the fun, here are loop-less versions:

Array<float,Dynamic,Dynamic,RowMajor> A;
A.colwise() = 0.5f + 0.5*sin(ArrayXf::LinSpaced(rows,0,10*2*3.14));

and:

Array<Array3f,Dynamic,Dynamic,RowMajor> A(rows,cols);
A.block(0,0,rows,cols) = A.NullaryExpr(rows, cols, [&] (long i, long j) { return Array3f(float(i)/float(rows), float(j)/float(cols), 0); });

The second one can also be achieved through some setup to get a view for each channel:

typedef Array<float,Dynamic,Dynamic,RowMajor> RowArrayXXf;
typedef Map<RowArrayXXf,0,Stride<Dynamic,3> > Channel;
Channel A_red(  A.data()->data()+0, rows, cols, Stride<Dynamic,3>(3*cols,3));
Channel A_green(A.data()->data()+1, rows, cols, Stride<Dynamic,3>(3*cols,3));
Channel A_blue( A.data()->data()+2, rows, cols, Stride<Dynamic,3>(3*cols,3));

and then, you get all the power of Eigen's API to work on individual channels:

A_red.colwise() = ArrayXf::LinSpaced(rows,0,1);
A_green.rowwise() = ArrayXf::LinSpaced(cols,0,1).transpose();
A_blue.setZero();

In your case that's overkill, but might be useful to perform more complicated operation, or to write a small wrapper around Array<Array3f> for images.

Upvotes: 4

Avi Ginsburg
Avi Ginsburg

Reputation: 10596

It is all fine and legal. However, there may (sometimes) be some issues. In your case, all you did with A(i,j) was assign. When attempting to use arithmetic operations, some issues sometimes arise (e.g. subtracting a Vector3d from the entire matrix). You may not run into any such issues, depending on your use.

Upvotes: 2

Related Questions