如何使用OpenGL渲染到多个纹理?

5
这是我对于多纹理渲染的基本步骤的理解。
1)绑定着色器位置以进行渲染。
m_uihDiffuseMap = glGetUniformLocation( m_iShaderProgramHandle, "diffuseMap" );

if( m_uihDiffuseMap != -1 )
    glUniform1i( m_uihDiffuseMap, 0 );

m_uihNormalMap = glGetUniformLocation( m_iShaderProgramHandle, "normalMap" );

if( m_uihNormalMap != -1 )
    glUniform1i( m_uihNormalMap, 1 );

2) 绑定到您想渲染的位置

glBindFramebuffer( GL_FRAMEBUFFER, m_uifboHandle );

//diffuse texture binding
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_uiTextureHandle1, 0);

//normal texture binding
                                   (or GL_COLOR_ATTACHMENT1)
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+1, m_uiTextureHandle2, 0);

3) 清除缓冲区并指定要绘制到哪些缓冲区

glClearColor( 1.0f, 1.0f, 1.0f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
glDrawBuffers(2, buffers);

4) 设置渲染用的着色器程序

glUseProgram( m_uiShaderProgramHandle );

5) 将变量传递到着色器,就像我们的两个不同纹理一样。

glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, uihDiffuseMap );

               //or(GL_TEXTURE1)
glActiveTexture( GL_TEXTURE0+1 );
glBindTexture( GL_TEXTURE_2D, uihNormalMap );

6) 进行呈现调用操作

//Draw stuff

7) 如果您有其他渲染过程使用其他内容,则将其设置回默认值

glBindFramebuffer( GL_FRAMEBUFFER, 0 );
glUseProgram( 0 );

------------------------------片段着色器-----------------------------------

在片段着色器中,您需要按照以下方式输出2个结果,对吗?

#version 330

in vec2 vTexCoordVary;

uniform sampler2D diffuseMap;
uniform sampler2D normalMap;

out vec4 fragColor[2];

void main( void )
{
    fragColor[0] = texture( diffuseMap, vTexCoordVary );
    fragColor[1] = texture( normalMap, vTexCoordVary );
};

我已经仔细检查了:
- 我的漫反射贴图和法线贴图都加载正常。如果我将我的法线贴图作为使用TEXTURE0的纹理传递,它将显示出来。 - 我可以很好地获取fragColor [0]。当我将fragColor [1] 显示在屏幕上时,我得到的结果与第一个颜色相同。但是我还在着色器中硬编码了fragColor [1]以返回实心灰色作为测试用例,并且测试通过。
因此,我的假设是当我将纹理传递给着色器时,它会认为“normalMap”是“diffuseMap”? 这是我唯一能想到的原因,为什么在fragColor [0]和[1]中得到相同的结果。

我有两个纹理,它们只是用于绘制在盒子上的纹理。这两个结果应该是: 1)使用盒子纹理1绘制的带盒子的纹理 2)使用纹理2绘制的盒子纹理 - Franky Rivera
我不是很理解,请您详细说明一下吗? - Alexander Gessler
一个盒子需要两个纹理(漫反射贴图和法线贴图)。有两个纹理需要填充(结果1和结果2)。在屏幕上显示结果1,一切正常。在屏幕上显示结果2,我得到的结果与结果1相同。 - Franky Rivera
期望的结果应该是.. 结果1应该显示盒子的漫反射颜色 结果2应该显示盒子的正常颜色 - Franky Rivera
我觉得我需要一些解释...我添加了更多的glError()检查,现在一切都正常了......这显然没有任何意义。但是我已经调试了这个小项目将近2个小时,而且我也重建了几次。没有改变任何部分。现在我添加了glError()检查,一切都好了 -_-。 - Franky Rivera
显示剩余2条评论
3个回答

1

是的,现在缺少有关您采样器映射到纹理槽的信息,导致两者都引用漫反射贴图。使用glUniform1i()将正确纹理的索引绑定到每个统一槽。


抱歉我忘记发布了。我已经更新了信息。现在应该是第一步了。谢谢你的注意 =] - Franky Rivera

0

如果有人像我一样通过搜索引擎偶然来到这里,我在写入多个纹理时遇到了一个笔误。我的帧缓冲初始化代码如下:

glGenFramebuffers(1, &renderer.gbufferFboId);
glBindFramebuffer(GL_FRAMEBUFFER, renderer.gbufferFboId);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,  GL_TEXTURE_2D, renderer.gbufferDepthTexId, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderer.gbufferColorPositionId, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, renderer.gbufferColorColorId, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, renderer.gbufferColorNormalId, 0);
opengl::fbo_check_current_status();

const GLenum drawBuffers[]
{
    GL_COLOR_ATTACHMENT0,
    GL_COLOR_ATTACHMENT1,
    GL_COLOR_ATTACHMENT2
};
glDrawBuffers(1, drawBuffers);

你能发现错误吗?这是在glDrawBuffer调用中的一个小错别字。它当然应该等同于缓冲区的数量:
glDrawBuffers(3, drawBuffers);

0

看起来步骤1和步骤4的顺序错了。这是在步骤1中:

if( m_uihDiffuseMap != -1 )
    glUniform1i( m_uihDiffuseMap, 0 );

if( m_uihNormalMap != -1 )
    glUniform1i( m_uihNormalMap, 1 );

而这就是第4步:

glUseProgram( m_uiShaderProgramHandle );

glUniform*() 调用适用于当前活动的程序。因此,在调用 glUniform1i() 之前必须先调用 glUseProgram()

还可以明确设置 out 变量的位置,这可能是一个好主意:

layout(location = 0) out vec4 fragColor[2];

我不认为这会导致你的问题,但是我在规范中没有看到链接器分配从0开始的位置,如果它们没有明确指定。


布局位置放置是OpenGL 4的事情。我使用3.3只是为了给自己一个小限制。另外,我认为可能是在着色器中预定义纹理位置时出了问题。我有一个LinkProgram()调用,但我忘记立即调用glUseProgram。我不知道为什么我认为LinkProgram仍然绑定了我的程序。所以实际上并不是4错了,而是我还需要在此之前进行那个调用。 - Franky Rivera
布局位置限定符在GLSL版本330中可用。那么将glUseProgram()调用提前是否解决了问题? - Reto Koradi
我在设置这些变量之前添加了glUseProgram,目前看起来一切都很好。 - Franky Rivera

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接