Jarra McIntyre
Jarra McIntyre

Reputation: 1275

GL_32F and glReadPixels

In OpenGL I'm trying to output an unscaled float from my fragment shader to a FBO color attachment for mouse over value picking. However I am unable to get my fragment shader code to correctly write the value.

I add a color attachment for storing the picking values to the framebuffer I draw to as follows:

// ... Bind FBO .etc.
glTexImage2D(
    GL_TEXTURE_2D,
    0,
    GL_R32F,
    DrawTextureDims.width(),
    DrawTextureDims.height(),
    0,
    GL_RED,
    GL_FLOAT,
    0);
glFramebufferTexture2D(
    GL_FRAMEBUFFER,
    GL_COLOR_ATTACHMENT2,
    GL_TEXTURE_2D,
    pointsMeshData->magnitudeTexture,
    0);

And setup the draw buffers prior to drawing as follows:

    // ...
    GLenum drawBufs[2] {
        GL_COLOR_ATTACHMENT0,
        GL_COLOR_ATTACHMENT2
    };
    glDrawBuffers(2,drawBufs);

    GLfloat clearMagnitude[4] { 0,0,0,0 };
    glClearBufferfv(GL_COLOR,1,clearMagnitude);

    // Bind VAO and shader. Setup uniforms and call glDrawElements()

And finally read back as follows:

...
glBindFramebuffer(GL_READ_FRAMEBUFFER,drawData->renderFBO.handle());
glReadBuffer(GL_COLOR_ATTACHMENT2);
glBindBuffer(GL_PIXEL_PACK_BUFFER,0);

*magnitude = 0.f;
glReadPixels(x,y,1,1,GL_RED,GL_FLOAT,magnitude);
...

However when I output to the 2nd color attachment using the following fragment shader nothing is drawn. I get back the color I cleared with (clearMagnitude) from glReadPixels()

#version 330

in float scale;
uniform sampler1D uPalette;
layout(location=0) out vec4 color;
layout(location=1) out float oScale;

void main(void)
{
    color = texture(uPalette,scale);
    oScale = scale;
}

On the other hand when I output using the following (clearly wrong) fragment shader I get a scaled (0-1) value back in glReadPixels():

#version 330

in float scale;
uniform sampler1D uPalette;
layout(location=0) out vec4 color;
layout(location=1) out vec4 oScale;

void main(void)
{
    color = texture(uPalette,scale);
    oScale = vec4(scale,scale,scale,1);
}

What am I doing incorrectly? How can I output and read back a single unscaled float in GLSL?

Upvotes: 1

Views: 527

Answers (1)

Nicol Bolas
Nicol Bolas

Reputation: 473517

I output using the following (clearly wrong) fragment shader

There's nothing wrong with that fragment shader. Just like vertex attributes, fragment shader output component counts do not have to match the actual destination image's component counts. If your output image has fewer components than the corresponding fragment shader variable, then it will simply take the components that match the image and ignore the rest.

However, you don't have to output a vec4 just to write to a single channel image. Your float example should work fine, so there's likely a driver bug at play.

As for the scaling problem, that's the fault of a different thing: read color clamping. You must use glClampColor to tell OpenGL not to clamp floating-point reads. Like this:

glClampColor(GL_CLAMP_READ_COLOR, GL_FIXED_ONLY);

This prevents clamping when reading FBO attached images that have fixed-point formats.

This is not part of the FBO's state; it's just a context value. So you can just set it once and forget about it.

Upvotes: 2

Related Questions