I have a 3D scene with some triangle meshes and I am performing an offscreen rendering to draw them onto three textures:
- An RGBA color texture to render my 3D scene as usual.
- A single channel INTEGER texture to be used for picking my rendered items with the mouse. Each item has its own unique integer id. When the user clicks over a pixel on the screen, I can check which value was written at that position to find out which item was clicked.
- The Depth texture.
I am creating a framebuffer, creating the textures, and formating them the following way:
glGenFramebuffers(1, &_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
glGenTextures(1, &_sceneTex );
glGenTextures(1, &_pickingTex );
glGenTextures(1, &_depthTex );
glBindTexture(GL_TEXTURE_2D, _sceneTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _sceneTex, 0);
glBindTexture(GL_TEXTURE_2D, _pickingTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32I, width, height, 0, GL_RED_INTEGER, GL_INT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, _pickingTex, 0);
glBindTexture(GL_TEXTURE_2D, _depthTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _depthTex, 0);
GLenum drawBuffers[2] = {GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT1};
glDrawBuffers(2, drawBuffers);
In the fragment shader, the color and the item ID are written to the layouts:
...
uniform int itemID;
layout( location = 0 ) out vec4 fragmentColor;
layout( location = 1 ) out int pickingInfo;
...
void main()
{
//Compute the fragment color somehow and write to fragmentColor variable.
fragmentColor = vec4(color, 1.0f);
pickingInfo = itemID;
}
The scene texture is copied to the screen after every render call.
And the picking texture is supposed to be always there, available for when the user needs to select an item.
Before rendering all items on the scene, textures are cleaned this way:
float backColor[4] = {_backgroundColor.red() / 255.f,
_backgroundColor.green() / 255.f,
_backgroundColor.blue() / 255.f,
_backgroundColor.alpha() / 255.f};
glClearBufferfv(GL_COLOR, GL_COLOR_ATTACHMENT0, backColor);
int invalidID = -1;
glClearBufferiv(GL_COLOR, GL_COLOR_ATTACHMENT1, &invalidID);
For reading the id written in the clicked position (x, y), I do:
glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
glReadBuffer(GL_COLOR_ATTACHMENT1);
int value = -1;
int x = static_cast<int>(screenPoint.x());
int y = height() - static_cast<int>(screenPoint.y());
glReadPixels(x, y, 1, 1, GL_RED_INTEGER, GL_INT, &value);
The problem is: everything works completely fine with my NVIDIA GeForce MX250. But I have the weirdest behavior when I work with my Intel(R) UHD Graphics.
There is a glDrawElements
call for each item rendered. When item X is rendered, its unique ID is passed to the shader which writes it onto the picking texture in the fragments the item is positioned.
Right now, I am only able to pick the first item rendered. I successfully get its ID with glReadPixels when I click over it on the screen. For anywhere else I click (even on other items), I get the "clear value" I set.
Does someone have any idea of what I might be doing wrong? Am I doing anything that is not standard?