ccoder83
ccoder83

Reputation: 504

Loading a texture by passing RGB floating point pixel data to glTexImage2D

I have a 2D floating point array with values mapped within the range 0.0f to 1.0f. I load it into OpenGL using a single channel i.e

glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_FLOAT, data);

which works fine. However, I'm trying to add two more channels in order to eventually convert it into RGB colours, as below:

// Get the current grid
Array2D<real_t> currentGrid = m_Continuum->getCurrentGrid();
float R, G, B;

std::vector<GLfloat> image;
image.resize(currentGrid.size()*3, 0.0f);

for (size_t i = 0; i != currentGrid.sizeWd(); ++i)
{
    for (size_t j = 0; j != currentGrid.sizeHt(); ++j)
    {
        // I have to switch i and j in currentGrid due to the way the Array2D type is layed out
        image[( i * currentGrid.sizeWd() + j) + 0] = currentGrid(j, i);
        image[( i * currentGrid.sizeWd() + j) + 1] = currentGrid(j, i);
        image[( i * currentGrid.sizeWd() + j) + 2] = currentGrid(j, i);
    }
}

Now, when I update and use glTexImage2D:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, width, height, 0, GL_RGB, GL_FLOAT,data);

the image is malformed, as shown in the comparison below: Single Channel Image

RGB Image

My texture loading function is below. I believe I've used the correct pixelstore and texture mapping parameters.

bool Texture::load(const size_t width, const size_t height, const float *data)
{
    glPixelStoref(GL_UNPACK_ALIGNMENT, 1);

    // Allocate a texture name
    //glGenTextures(1, &m_TextureObj); called in another function

    // select current texture
    glBindTexture(GL_TEXTURE_2D, m_TextureObj);

    // select replace to ensure texture retains each texel's colour
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    // if texture wraps over at the edges
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT,data);

    glGenerateMipmap(GL_TEXTURE_2D);

    m_Loaded = true;
    return true;
}

Any ideas of what I could try? Here's what I've looked up:

  1. Here's a similar question on the topic, which is what I've tried following, but to no avail.
  2. My hunch is there may be a problem with the layout of the data I'm passing, such as this question. I've tried that, but it basically squashes the single channel image to the left third of the texture image area.

EDIT:

Updated resulting image, based on @Podgorskiy answer, by changing

( i * currentGrid.sizeWd() + j) + c

to

( 3 * i * currentGrid.sizeWd() + j) + c

where c is the channel 0,1,2. Resulting image below: RGB Image updated result

Upvotes: 3

Views: 1988

Answers (1)

Pidhorskyi
Pidhorskyi

Reputation: 1582

You access elements by the index that you calculate as:

( i * currentGrid.sizeWd() + j) + c

Where c is a channel, and it takes the values of: 0, 1, 2.

However, this expression likely to be wrong. From this expression follows that two neighboring texels have offset of one float, but should have offset of three floats. Try this instead:

3 * ( i * currentGrid.sizeWd() + j) + c

Upvotes: 3

Related Questions