首页 > 解决方案 > 使用 INTEL 显卡在单通道整数纹理上的离屏渲染问题

问题描述

我有一个带有一些三角形网格的 3D 场景,我正在执行屏幕外渲染以将它们绘制到三个纹理上:

  1. 像往常一样渲染我的 3D 场景的 RGBA 颜色纹理。
  2. 一个单通道 INTEGER 纹理,用于用鼠标选择我渲染的项目。每个项目都有自己唯一的整数 id。当用户点击屏幕上的一个像素时,我可以检查在该位置写入了哪个值,以找出点击了哪个项目。
  3. 深度纹理。

我正在创建一个framebuffer,创建纹理,并按以下方式格式化它们:

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);

片段着色器中,颜色和项目 ID 被写入布局:

...
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;
}

每次渲染调用后,场景纹理都会复制到屏幕上。
并且拾取纹理应该始终存在,当用户需要选择一个项目时可用。

在渲染场景中的所有项目之前,以这种方式清理纹理:

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);

为了读取写在点击位置 (x, y)的 id ,我这样做:

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);

问题是:我的 NVIDIA GeForce MX250 一切正常。但是当我使用 Intel(R) UHD Graphics 时,我的行为最奇怪。

每个渲染的项目都有一个glDrawElements调用。渲染项目 X 时,其唯一 ID 被传递给着色器,着色器将其写入项目所在片段中的拾取纹理上。

现在,我只能选择渲染的第一个项目。当我在屏幕上单击它时,我使用 glReadPixels 成功获取了它的 ID。对于我点击的其他任何地方(甚至在其他项目上),我都会得到我设置的“明确值”。

有人知道我可能做错了什么吗?我做了什么不标准的事情吗?

标签: c++opengl

解决方案


推荐阅读