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

标签 c++ opengl game-engine

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

当将深度缓冲区渲染到纹理时,我得到了一些预期的结果,但图像充满了奇怪的伪像(颜色目标工作正常)。我试过各种深度和模板位配置、不同的绑定(bind)方法,但我一无所获。

我将发布我的结果以及我拥有的导致“最接近”正确结果的相关代码。

场景是大量的大炮,大炮前面有一个摄像头位置,摄像头前面有一架飞机。飞机的纹理是第二个围绕大炮旋转的相机的渲染结果。我希望飞机大部分是红色的,在物体靠近第二个摄像头的地方有一些较暗的红色区域。

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

这是我从 GL 得到的结果:[2]: http://i.imgur.com/vH9u1bq.png “奇怪的结果”

我不知道黑色部分是从哪里来的。通过一些着色器调试,我可以看出未渲染区域仍为 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),基于模板也会导致各种问题(即使我更改代码以考虑模板)。

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

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

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

我已经尝试了多种将渲染目标绑定(bind)到帧缓冲区的方法,但问题似乎永远不会消失。任何帮助将不胜感激。现在,我必须放弃引擎的 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;
       }

最佳答案

不要那么快放弃 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 之前绑定(bind)到帧缓冲区

    glBindFramebuffer(GL_FRAMEBUFFER, fbo);

以后要渲染贴图到屏幕时绑定(bind)贴图

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

关于c++ - 在 OpenGL 中将深度渲染到纹理时出现奇怪的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20930639/

相关文章:

c++ - 计算边界框的面积

opengl - 在 Haskell 中用 opengl 画线

opengl - 片段着色器 - 绘制曲线

c++ - 使用像素坐标的 OpenGL 子图像

c++ - 基于组件的游戏引擎中的序列化

c++ - 程序在新抛出 bad_alloc 之前中止

c++ - `copy`实现示例中的运算符优先级

algorithm - 计算和应用摩擦力

c# - C++ C# 包装器相关。如何从 C# 窗口获取 hwnd 并将其传递给 C++?

c++ - 如何在 makefile 中只编译一个 .h 文件?