OpenGL 3.30 / GLSL 3.30 - MRT 输出黑色纹理

Posted

技术标签:

【中文标题】OpenGL 3.30 / GLSL 3.30 - MRT 输出黑色纹理【英文标题】:OpenGL 3.30 / GLSL 3.30 - MRT outputting black textures 【发布时间】:2013-08-02 20:05:35 【问题描述】:

我已经被这个问题困扰了大约四天了。我正在尝试将我的几何图形渲染为具有三种纹理(反照率、法线、深度)的 FBO(G 缓冲区)。到目前为止,我已经“有点”实现了 MRT 功能,但是当我使用 gDEBugger 检查纹理时,它们只是显示为黑色。无论我改变什么,它们都会产生纯黑色。输出的实际值是正确的,我通过禁用 MRT 以使片段着色器输出到后台缓冲区进行检查。纹理正在正确初始化,gDEBugger 正确显示了我为它们设置的参数。但它们都只有纯黑色 (0, 0, 0, 255) 填充。

几乎没有关于 GLSL 3.30 的 MRT 的详细信息。我完全依赖这里已回答的问题,以及网络上的 OpenGL/GLSL 文档和教程(已过时,但我更新了代码)。我可能花了一整天的时间在 Google 上寻找这个问题的解决方案。如果代码顺序或语法有问题,请指出。我什至不知道这个实现是否正确......

我正在使用 Visual C++ 2010、OpenGL 3.30 和 GLSL 3.30(如标题中所述)。对于我的库,GLFW 3.0 用于窗口、输入和 OpenGL 上下文,GLEW 1.10.0 用于扩展。

请记住,所有这些代码都取自我的包装类。代码的顺序是它在运行时是如何运行的(换句话说,就像我没有包装类,所有的代码都在 main() 中)。

初始化阶段

// Initialize textures
glGenTextures (3, tex_ids);

glEnable (GL_TEXTURE_2D);

glBindTexture (GL_TEXTURE_2D, tex_ids[0]); // Diffuse
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D  (GL_TEXTURE_2D, 0, GL_RGB8, res.x, res.y, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);

glBindTexture (GL_TEXTURE_2D, tex_ids[1]); // Normal
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D  (GL_TEXTURE_2D, 0, GL_RGB8, res.x, res.y, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);

glBindTexture (GL_TEXTURE_2D, tex_ids[2]); // Depth
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D  (GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, res.x, res.y, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);

glBindTexture (GL_TEXTURE_2D, 0);
glDisable (GL_TEXTURE_2D);


// Initialize FBO
glEnable (GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex_ids[0]);
glFramebufferTexture2D ( GL_FRAMEBUFFER, 
             GL_COLOR_ATTACHMENT0, 
             GL_TEXTURE_2D, 
             tex_ids[0], 
             0 ); // diffuse

glBindTexture(GL_TEXTURE_2D, tex_ids[1]);
glFramebufferTexture2D ( GL_FRAMEBUFFER, 
             GL_COLOR_ATTACHMENT1, 
             GL_TEXTURE_2D, 
             tex_ids[1], 
             0 ); // normal

glBindTexture(GL_TEXTURE_2D, tex_ids[2]);
glFramebufferTexture2D ( GL_FRAMEBUFFER, 
             GL_DEPTH_ATTACHMENT, 
             GL_TEXTURE_2D, 
             tex_ids[2], 0 ); // depth
glBindFramebuffer (GL_FRAMEBUFFER, 0);
glDisable (GL_TEXTURE_2D);

// Initialize shaders

// Snipped out irrelevant code relating to getting shader source & compiling shaders
glBindFragDataLocation (renderer_1prog, GL_COLOR_ATTACHMENT0, "diffuse_out");
glBindFragDataLocation (renderer_1prog, GL_COLOR_ATTACHMENT1, "normal_out");
glBindFragDataLocation (renderer_1prog, GL_DEPTH_ATTACHMENT, "depth_out");
// More snipped out code relating to linking programs and finalizing

Draw Stage - 在每一帧调用

// Bind everything
glUseProgram (renderer_1prog);
glBindFramebuffer (GL_DRAW_FRAMEBUFFER, fbo_id);
GLenum targ [3] =  GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_DEPTH_ATTACHMENT ;
glDrawBuffers (3, targ);

// Draw mesh
glEnable (GL_CULL_FACE);
glEnable (GL_DEPTH_TEST);

teshmesh.draw ();

// Unbind fbo
glDisable (GL_CULL_FACE);
glDisable (GL_DEPTH_TEST);

glBindFramebuffer (GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer (GL_DRAW_FRAMEBUFFER, 0);

顶点着色器

#version 330
layout(location = 0)in vec4 v;
layout(location = 1)in vec3 c;
layout(location = 2)in vec3 n;
out vec4 pos;
out vec3 col;
out vec3 nrm;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 world;
void main () 
    gl_Position = projection * view * world * v;
    pos = view * world * v;
    pos.z = -pos.z / 500.0;
    col = c.xyz;
    nrm = n;

片段着色器

#version 330
in vec3 col;
in vec3 nrm;
in vec4 pos;
layout(location = 0) out vec3 diffuse_out;
layout(location = 1) out vec3 normal_out;
layout(location = 2) out vec3 depth_out;
out vec3 o;
void main () 
    diffuse_out = col;
    normal_out = (nrm / 2.0) + 0.5;
    depth_out = vec3 (pos.z, pos.z, pos.z);

【问题讨论】:

我建议您使用 ARB_debug_output 实时查看 OpenGL 发出的错误。 【参考方案1】:

这里有一些问题。从最小的开始:

glBindFragDataLocation (renderer_1prog, GL_COLOR_ATTACHMENT0, "diffuse_out");
glBindFragDataLocation (renderer_1prog, GL_COLOR_ATTACHMENT1, "normal_out");
glBindFragDataLocation (renderer_1prog, GL_DEPTH_ATTACHMENT, "depth_out");

这些毫无意义。您在着色器中使用了layout(location) 语法来指定这一点,而that takes priority over OpenGL-provided location settings。

另外,这些是错误的。您不要将 FBO 缓冲区附件名称放入该位置;您将 index 放入该位置。所以即使你没有使用layout(location),这也是不正确的。 glBindFragDataLocation 将发出 OpenGL 错误,因为该位置肯定会大于 GL_MAX_DRAW_BUFFERS​

考虑到您的代码应该发出多少 OpenGL 错误,我很惊讶您使用 gDEBugger 并没有告诉您这些错误。


glTexImage2D  (GL_TEXTURE_2D, 0, GL_RGB8, res.x, res.y, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);

GL_RGB8 不是required image formats for render targets 之一。因此,不需要实现来支持它;它可能,但不是必须的。而且由于您从未打扰过check the completeness of the FBO(仅供参考:您应该始终这样做),因此您没有测试这种格式组合是否有效。

永远不要渲染为 3 分量图像。请选择 4、2 或 1。


GLenum targ [3] =  GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_DEPTH_ATTACHMENT ;
glDrawBuffers (3, targ);

这可能是您的主要问题:您的glDrawBuffers call fails。 glDrawBufferssets the color buffer outputs。深度缓冲区不是颜色缓冲区。深度缓冲区只有一个,无需设置。

要写入深度缓冲区...好吧,您不应该将用户计算的值写入深度缓冲区。只需让常规深度缓冲区写入处理它即可。但是如果你想(让我再次提醒你,你不想),你写信给gl_FragDepth。这就是它的用途。

【讨论】:

我需要一个用户定义的深度图,因为我将在着色器正在使用的片段之外使用片段深度。无论如何,我修复并删除了有问题的代码,它工作正常。虽然,我注意到一些几何图形不正确地显示在其他几何图形的前面,所以我需要进行深度测试。不幸的是,当我将渲染缓冲区附加到 FBO 时,所有纹理现在都变为白色(深度纹理为红色,因为 GL_R16)。我添加的唯一代码是渲染缓冲区生成/绑定调用。 gDEBugger 没说什么,FBO 状态好像还可以。有什么想法吗? @JarrodB: "我需要一个用户定义的深度图,因为..." 这并不能解释为什么你必须一个用户定义的 value 到深度缓冲区,而不是让光栅化器生成的深度通过。这可能就是你的深度被搞砸的原因;因为你搞砸了你的深度。 好吧,我不明白将用户定义的值写入颜色缓冲区会如何影响实际的深度测试。 @JarrodB:好的,我看不到你新修改的代码,所以我不知道你在写什么或者没有写到深度缓冲区。但如果像上面那样,那么你并没有改变写入深度缓冲区的正常值。 所以我必须在片段着色器的某个地方写入 gl_FragDepth?通常,这只是 gl_FragCoord.z,对吧?

以上是关于OpenGL 3.30 / GLSL 3.30 - MRT 输出黑色纹理的主要内容,如果未能解决你的问题,请参考以下文章

错误:不支持GLSL 3.30。支持的版本包括:1.10,1.20,1.30,1.00 ES,3.00 ES,3.10 ES和3.20 ES [关闭]

错误:不支持 GLSL 3.30。支持的版本有:1.10、1.20、1.30、1.00 ES、3.00 ES、3.10 ES 和 3.20 ES [关闭]

超过一个字符指针时的GLSL编译错误(glShaderSource)

.3.30下午背单词,分析长句

3.30上午

3.30下午