渲染到立方体贴图

12
根据ARB_geometry_shader4,可以使用几何着色器将场景渲染到立方体纹理的6个面上,并将立方体纹理附加到帧缓冲对象上。我想使用这种方法创建阴影贴图。然而,似乎存在一个无法解决的冲突:
  1. 只能将内部类型为GL_DEPTH_COMPONENT的纹理附加到GL_DEPTH_ATTACHMENT_EXT上。
  2. 深度纹理只能是1D或2D的。
  3. 如果我要附加一个立方体贴图,则所有其他附加的纹理也必须是立方体贴图。
因此,当我想要渲染到立方体纹理时,似乎无法使用任何深度测试。或者说我在这里漏掉了什么?
编辑:看起来新的Nvidia驱动程序(180.48)支持深度立方体贴图。

我不确定将渲染到立方体贴图与几何着色器有什么关系,它感觉完全独立,但是我没有答案。 - falstro
1
几何着色器可以为每个输入三角形创建6个输出三角形,并将其重定向到每个立方体贴图面(参见“分层渲染”)。如果没有着色器,我必须附加每个面并渲染6次几何图形。 - Maurice Gilden
我在想,你能否粘贴创建带有立方体纹理的帧缓冲区的代码?我对此很感兴趣。 - shoosh
为什么不为立方体的每个面使用6个单独的帧缓冲区呢?你是如何在着色器内绑定立方体贴图的不同面的? - shoosh
1个回答

13

当然可以使用6个帧缓冲对象(FBOs),每个面一个。或者在绘制之前使用一个FBO并附加每个面。在这两种情况下,立方体贴图面将像任何其他2D纹理一样进行处理,您可以与普通的2D纹理或渲染缓冲一起使用它。如果硬件支持所有可能的方式,可能没有太大的区别。

但是,也可以一步完成所有绘制操作,因此我很好奇如何完成这个过程,于是我做了一些研究。

要创建一个带有所有立方体贴图面附加到单个附加点的FBO,我使用了以下代码(用D语言编写):

// depth cube map
glGenTextures(1, &tDepthCubeMap);
glBindTexture(GL_TEXTURE_CUBE_MAP, tDepthCubeMap);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
for (uint face = 0; face < 6; face++) {
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_DEPTH_COMPONENT24,
        width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, null);
}

// color cube map
glGenTextures(1, &tColorCubeMap);
glBindTexture(GL_TEXTURE_CUBE_MAP, tColorCubeMap);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
for (uint face = 0; face < 6; face++) {
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_RGBA,
        width, height, 0, GL_RGBA, GL_FLOAT, null);
}

// framebuffer object
glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
glFramebufferTextureARB(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, tDepthCubeMap, 0);
glFramebufferTextureARB(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, tColorCubeMap, 0);

glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);

if (!isValidFBO()) {
    glDeleteFramebuffersEXT(1, &fbo);
    fbo = 0;
}
  • 如果您只想要深度图,您需要在验证之前(以及绘制之前)将glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);更改为glDrawBuffer(GL_NONE);
  • MIN和MAG过滤器必须设置为有效值(默认情况下为GL_NEAREST_MIPMAP_LINEAR)
  • 所有纹理的宽度和高度必须相同

要渲染立方体贴图的面,您需要一个几何着色器。以下着色器缺少一些旋转,但应该清楚它所做的事情。gl_Layer用于将基元定向到正确的面(0 = +X,1 = -X,...)。

#version 120
#extension GL_EXT_geometry_shader4 : enable

void main(void) {
    int i, layer;
    for (layer = 0; layer < 6; layer++) {
        gl_Layer = layer;
        for (i = 0; i < 3; i++) {
            gl_Position = gl_PositionIn[i];
            EmitVertex();
        }
        EndPrimitive();
    }
}

你知道是哪个扩展使得可以使用GL_TEXTURE_CUBE_MAP_POSITIVE_X和GL_DEPTH_COMPONENT24调用glTexImage2D吗?GL_EXT_depth_texture明确禁止这样做。我需要知道可以检查哪个GL扩展来确定是否可以使用此功能。我在标准扩展注册表中没有看到这个扩展。谢谢。 - gman
那是我的最初问题。似乎没有任何地方明确提到允许这样做(虽然可能已经改变,我还没有再次检查)。您可以检查 ARB_geometry_shader4 然后看看设置 FBO 是否会生成错误。 - Maurice Gilden
5
我尝试使用核心OpenGL 3.3来运行它,但失败了。当我从立方体贴图中读取时,得到的只是噪点。如果你能提供一个可运行的示例,那就太好了。 - user618401
我在我的引擎中使用它,似乎对GTX 970及以上的版本有效,但是当尝试在GTX 880上使用时,结果是黑屏,而在Intel上尝试使用时则会崩溃。 - Tab

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