2

I have a 3D scene with some triangle meshes and I am performing an offscreen rendering to draw them onto three textures:

  1. An RGBA color texture to render my 3D scene as usual.
  2. 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.
  3. 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?

  • did you try to only render to your integer texture, or separate both render to two separate pass ? – Paltoquet Nov 09 '20 at 20:37
  • It's very interesting that the first item is successful but others are not. I wonder if you've changed your GL state somehow between the first item and subsequent items? This could be an Intel-specific driver bug. You could try using a non-integer texture to check if that works around the issue. – prideout Nov 09 '20 at 20:55
  • @DraykoonD No, I haven't tried any of those. I am going too. Thanks. – Suellen Motta Nov 10 '20 at 00:47
  • @prideout I have tried to render the second texture in an RGBA texture too, and that works on both cards. I could work with that, but I really wanted to figure out what is wrong. – Suellen Motta Nov 10 '20 at 00:47
  • Rendering to texture on Intel is well known bug for years and Intel does not repair their drivers ... it only works in some cases when the driver considers your texture format complete but to achieve that its not easy and only for some formats (never got it to work myself)... the only reliable way of off screen rendering on Intel I know of is to render to normal frame buffer (and not swap buffers) and use `glReadPixels` .... I know its slow but it works ... see [OpenGL Scale Single Pixel Line](https://stackoverflow.com/a/43654398/2521214) – Spektre Nov 10 '20 at 06:54
  • One of the sad things is that the robust and reliable old GL api is being depreceated and increasingly unreliable on newer drivers while the new stuff is still not fully supported as it should so it breaks down to 1. detect gfx vendor and type 2. imply workarounds into pipeline 3. hope something not break in a year ... Of coarse if you use 3th party 3D engines or only standard rendering techniques all should be fine as they did all for you but once you do custom stuff then you usually hit a wall for non nVidia cards pretty soon. And if not then your customers especially on laptops... – Spektre Nov 10 '20 at 06:59

0 Answers0