C++ 使用英特尔图形卡在单通道整数纹理上进行屏幕外渲染时出现问题

C++ 使用英特尔图形卡在单通道整数纹理上进行屏幕外渲染时出现问题,c++,opengl,C++,Opengl,我有一个带有一些三角形网格的3D场景,我正在执行屏幕外渲染,将它们绘制到三种纹理上: 一个RGBA颜色纹理,可以像往常一样渲染我的3D场景 用于使用鼠标拾取渲染项目的单通道整数纹理。每个项目都有自己唯一的整数id。当用户单击屏幕上的一个像素时,我可以检查在该位置写入的值,以找出单击的项目 深度纹理 我正在创建一个帧缓冲区,创建纹理,并按以下方式对其进行格式化: glGenFramebuffers(1, &_fbo); glBindFramebuffer(GL_FRAMEBUFFER, _

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

  • 一个RGBA颜色纹理,可以像往常一样渲染我的3D场景
  • 用于使用鼠标拾取渲染项目的单通道整数纹理。每个项目都有自己唯一的整数id。当用户单击屏幕上的一个像素时,我可以检查在该位置写入的值,以找出单击的项目
  • 深度纹理
  • 我正在创建一个帧缓冲区,创建纹理,并按以下方式对其进行格式化:

    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\u FRAMEBUFFER,\u fbo);
    glReadBuffer(GL\u COLOR\u附件1);
    int值=-1;
    int x=静态_转换(screenPoint.x());
    int y=height()-静态投影(screenPoint.y());
    glReadPixels(x、y、1、1、GL\u RED\u INTEGER、GL\u INT和value);
    
    问题是:我的NVIDIA GeForce MX250一切正常。 但当我使用我的英特尔(R)超高清图形时,我有最奇怪的行为

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

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


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

    您是否尝试只渲染到整数纹理,或将两个渲染分离到两个单独的过程?非常有趣的是,第一个项目成功,而其他项目则没有成功。我想知道您是否在第一项和后续项之间以某种方式更改了总账状态?这可能是英特尔特定的驱动程序错误。您可以尝试使用非整数纹理来检查这是否能解决问题。@Draykond不,我没有尝试过任何一种。我也要去。谢谢。@prideout我也尝试过在RGBA纹理中渲染第二个纹理,这对两张卡都有效。我可以解决这个问题,但我真的很想找出问题所在。在英特尔上渲染纹理是多年来众所周知的错误,英特尔不会修复他们的驱动程序。。。它只在某些情况下工作,当驱动程序认为你的纹理格式完整,但要做到这一点并不容易,只对某些格式(从来没有得到它的工作我自己)。。。据我所知,在英特尔上进行屏幕外渲染的唯一可靠方法是渲染到普通帧缓冲区(而不是交换缓冲区),并使用
    glReadPixels
    。。。。我知道它很慢,但它能工作。。。看见
    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);