问题 渲染到立方体贴图


根据 ARB_geometry_shader4 可以使用几何着色器和连接到帧缓冲对象的立方体贴图将场景渲染到立方体贴图的6个面上。我想用这种方式创建一个阴影贴图。但是,我似乎无法解决冲突:

  1. 我只能将GL_DEPTH_COMPONENT作为内部类型的纹理附加到GL_DEPTH_ATTACHMENT_EXT。
  2. 深度纹理只能是1D或2D。
  3. 如果我想附加立方体贴图,则所有其他附加纹理也必须是立方体贴图。

因此,当我想渲染到立方体贴图时,看起来我无法使用任何深度测试。或者我到底错过了什么?

编辑: 看起来更新的Nvidia驱动程序(180.48)支持深度立方体贴图。


1449
2018-01-20 19:26


起源

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


答案:


好的,回答其他一些问题:

当然可以使用6个FBO,每个面部一个。或者在绘制之前使用一个FBO并附上每个面。在这两种情况下,立方体贴图面将被视为任何其他2D纹理,您可以将其与普通2D纹理或Renderbuffers一起使用。并且所有可能的方式(如果硬件支持它们)可能没有太大区别。

然而,也可以一步一步地绘制所有内容,因为我很好奇这是如何完成的,我做了一些研究。

要创建一个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();
    }
}

12
2018-01-30 15:34



你知道什么扩展可以用GL_TEXTURE_CUBE_MAP_POSITIVE_X和GL_DEPTH_COMPONENT24调用glTexImage2D吗? GL_EXT_depth_texture明确禁止这样做。我需要知道我可以查看的GL扩展名,以了解我是否可以使用此功能。我没有在标准扩展注册表中看到一个。谢谢。 - gman
那是我原来的问题。似乎没有任何地方特别提到它是允许的(虽然可能已经改变,但我没有再次检查)。您可以检查ARB_geometry_shader4,然后查看设置FBO是否不会产生错误。 - Maurice Gilden
我尝试使用核心opengl 3.3,但失败了。从立方体贴图中读取的所有内容都是噪音。如果你能提供一个有效的例子,那将是非常好的。