在 OpenGL 中将深度渲染到纹理时出现奇怪的结果

Posted

技术标签:

【中文标题】在 OpenGL 中将深度渲染到纹理时出现奇怪的结果【英文标题】:Strange Results when rendering depth to texture in OpenGL 【发布时间】:2014-01-05 05:54:30 【问题描述】:

我正在对图形引擎的纹理组件进行渲染。我花了几个小时在 DX 上实现它,它按预期工作,我在 OpenGL 实现上花了几天时间,但它拒绝工作。

将深度缓冲区渲染到纹理时,我得到了一些预期的结果,但图像完全是奇怪的伪影(颜色目标工作正常)。我尝试过各种深度和模板位配置,不同的绑定方法,但我无处可去。

我将发布我的结果是什么以及我有哪些相关代码导致了“最接近”的正确结果。

场景是大量的加农炮,加农炮前面有一个摄像头位置,摄像头前面有一个平面。飞机的纹理是围绕大炮旋转的第二个摄像机的渲染结果。我预计飞机大部分是红色的,并且在物体靠近第二个摄像头的地方有一些较深的红色区域。

这是我在 DX 中得到的结果(这是我所期望的):[1]:http://i.imgur.com/Zfchzq3.png"Good Result"

这是我从 GL 得到的结果:[2]:http://i.imgur.com/vH9u1bq.png"Odd Result"

我不知道黑色部分是从哪里来的。通过一些着色器调试,我可以看出未渲染区域保持 1.0(深度清除值),非黑色区域接近 1.0,但从未达到(如我所料)。黑色区域是...随机的。

我用来创建纹理的代码是:

glGenTextures(1, &textureID);
dim = GL_TEXTURE_2D;
wth = width;
hgt = height;
iFormat = _glTranslateFormat(fmt, format, type);
glBindTexture(dim, textureID);
glTexStorage2D(dim, 1, iFormat, width, height);

_glTranslateFormat 将原生格式转换为 GL 格式,这将返回 GL_DEPTH_COMPONENT16 atm。我尝试过其他格式,它们给出了更奇怪的结果。 32 和 32F 允许采样值远远超出 0 和 1 的范围(例如高于 1000000000),基于模板也会导致各种问题(即使我更改代码以考虑模板)。

我用来将它绑定到帧缓冲区的代码是:

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, d->_exposeTexture()->_exposeAPI(), 0);

_exposeAPI 返回纹理的 ID。每次代码要求将深度缓冲区绑定到不同的帧缓冲区时都会发生这种情况(帧缓冲区将事先绑定)。

我尝试了各种将渲染目标绑定到帧缓冲区的方法,但问题似乎永远不会消失。任何帮助将不胜感激。现在我将不得不放弃引擎的 OpenGL 组件并使用 DX,直到找到解决此问题的方法。

编辑:根据要求,我添加了负责从纹理采样的着色器,文件末尾的内容只是我玩过的调试代码。深度纹理作为漫反射纹理传入。

    #version 430

    struct Light
       
       vec4 diffuse;
       vec4 specular;
       vec4 attenuation;
       vec3 spot;
       uint nID;
       uint type;
       ;

    layout (std140, binding = 9) uniform singleLight
       
       Light light;
       ;

    struct BasicFSInput
       
       vec4 position;
       vec3 normal;
       vec2 uv;
       vec4 fragPos;
       vec3 toLight;
       ;

    layout(binding = 1) uniform sampler2D diff1;
    layout(binding = 2) uniform sampler2D amb1;
    layout(binding = 3) uniform sampler2D spec1;

    layout (location = 0) in BasicFSInput fin;
    layout (location = 0) out vec4 color;

    layout(std140, binding = 10) uniform material
       
       float specular;
       float shininess;
       ;

    void BasicFragmentShader()
       
       vec4 dTexel = texture(diff1, fin.uv).rgba;
       vec4 aTexel = texture(amb1, fin.uv).rgba;
       vec4 sTexel = texture(spec1,fin.uv).rgba;

       vec3 lightDir = normalize(fin.toLight);
       vec3 n = normalize(fin.normal);
       float NdotL = max(dot(n, lightDir),0.0);
       vec4 col = NdotL * light.diffuse;
       vec4 ambContrib = aTexel;
       vec4 diffContrib = dTexel * col;

       vec3 refl = 2.0 * NdotL * n + lightDir;
       float NdotR = max(dot(normalize(refl), normalize(-fin.fragPos.xyz)),0.0);
       float specContrib = sTexel * specular * pow(NdotR, shininess);

       color = ambContrib + diffContrib + specContrib;/*
       if(dTexel.r < -1.0)
          color.r = 1.0f;
       if(dTexel.r > 1.0)
          color.b = 1.0f;
       if(dTexel.r == 1.0f)
          color.g = 1.0f;*/
       //color.r = dTexel.r;

       /*if(dTexel.r < 0.5f)
          color.b = 1.0f;
       if(dTexel.r > 0.5f)
          color.r = 1.0f;*/
       /*if(dTexel.r < -10000000.0f)
          color.g = 1.0f;*/
       //color.a = 1.0f;
       

【问题讨论】:

你的着色器在哪里?如果您尝试从当前用于绘图的同一深度缓冲区进行采样,您可能会得到这样奇怪的结果。 @AndonM.Coleman 我不相信我在写作时从同一个深度缓冲区中采样,但我会看看,谢谢。我会将着色器添加到问题的末尾,它并不过分复杂。 你设置了深度纹理采样模式吗?即 GL_LEQUAL @NathanWride:这只对包含比较的采样器很重要。 (例如sampler2DShadow)。那是测试功能,而不是模式。模式为GL_TEXTURE_COMPRE_TO_REF。但是如果你设置了这个然后尝试使用常规的sampler2D 对纹理进行采样,结果将是不确定的。 【参考方案1】:

不要那么快放弃 OpenGL :)

您确定要将深度缓冲区渲染到纹理而不是将颜色缓冲区渲染到纹理吗?

也许以下内容可能会有所帮助(如果您已经知道这一点,我们深表歉意)。 (取自 OpenGL Superbible 第 6 版。)

设置帧缓冲

    glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    //texture for the colour buffer
glGenTextures(1, &colourTexture);
glBindTexture(GL_TEXTURE_2D, colourTexture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    //texture for the depth buffer
glGenTextures(1, &depthTexture);
glBindTexture(GL_TEXTURE_2D, depthTexture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT32F, width, hwight);

glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colourTexture, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0);

const GLenum drawBuffers[] =  GL_COLOR_ATTACHMENT0 ;
glDrawBuffers(1, drawBuffers);

然后在调用 glDrawArrays / Elements 之前绑定到帧缓冲区

    glBindFramebuffer(GL_FRAMEBUFFER, fbo);

稍后,当你想将纹理渲染到屏幕上时,绑定纹理

     glBindTexture(GL_TEXTURE_2D, colourTexture);

在渲染纹理时需要在片段内部使用采样器。

#version 430 core 
uniform sampler2D tex;  
in VS_OUT
 
    vec2 texcoord;
 fs_in;
out vec4 color;
void main(void)

color = texture(tex, fs_in.texcoord);

【讨论】:

感谢您的回答。我确实已经有色彩渲染工作了,我正在努力让深度工作。 Pic of it working. 别担心,我已经编写了这个引擎来支持 DX 和 GL,我并没有完全放弃 GL,只是暂时放弃这个任务。

以上是关于在 OpenGL 中将深度渲染到纹理时出现奇怪的结果的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL - 在 NVIDIA 卡上渲染到纹理时出现 FBO 黑屏

在渲染纹理上绘制时出现问题。 (OpengL 3.3)

渲染到纹理时出现黑屏

OpenGL渲染到纹理透明度问题

Opengl渲染到深度纹理 - 红色?

OpenGL(FBO)中的普通后台缓冲区+渲染到深度纹理