如何在 OpenGL 中使用立方体贴图数组来渲染带有阴影贴图的多个点光源?

Á. *_*ton 4 c++ opengl glsl

我阅读并实现了以下教程:https://learnopengl.com/Advanced-Lighting/Shadows/Point-Shadows

现在我想将其概括为在场景中渲染多个点光源,我该怎么做?我听说立方体贴图数组可以用于类似的事情,它们到底是如何工作的?有人能给我举个例子吗?

(我正在为自己和后代回答这个问题,因为目前还没有关于如何使用立方体贴图数组的简单教程。)

Á. *_*ton 6

如果您想将多个立方体贴图阴影贴图传递给着色器,并且您事先不知道到底有多少,那么立方体贴图数组是一个很好的解决方案。它们的工作方式类似于 3D 纹理,其中每一层都是一个立方体贴图。在片段着色器中,您可以为它们创建一个采样器,如下所示:

uniform samplerCubeArray cubeMapArray;
Run Code Online (Sandbox Code Playgroud)

您可以通过以下方式将数组纹理绑定到它:

glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, m_PointLightDepthMaps.m_DepthTexture);
Run Code Online (Sandbox Code Playgroud)

您可以像从立方体贴图一样从 SamplerCubeArray 中进行采样,但在这种情况下,您的向量会获得第四个元素,即要从中采样的层。例如:

texture(cubeMapArray, vec4(dir, 3)).r
Run Code Online (Sandbox Code Playgroud)

将从数组中的第四个立方体贴图进行采样。要创建一个用作深度纹理的立方体贴图数组,您可以使用以下模板:

void Renderer::initCubemapDepthMap(CubemapDepthMap& map)
{
    glGenTextures(1, &map.m_DepthTexture);
    glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, map.m_DepthTexture);
    glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
    glTexImage3D(
        GL_TEXTURE_CUBE_MAP_ARRAY, 0, GL_DEPTH_COMPONENT, m_ShadowCubeMapResolution, m_ShadowCubeMapResolution, 6 * m_MaxPointLights + 6 * m_MaxSpotLights, 0,
        GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
    glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, 0);

    glGenFramebuffers(1, &map.m_FrameBuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, map.m_FrameBuffer);
    glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, map.m_DepthTexture, 0);
    glDrawBuffer(GL_NONE);
    glReadBuffer(GL_NONE);

    const int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if (status != GL_FRAMEBUFFER_COMPLETE)
    {
        std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!\n";
        throw 0;
    }

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
Run Code Online (Sandbox Code Playgroud)

请注意,您需要使用 GL_TEXTURE_CUBE_MAP_ARRAY 作为纹理类型,并且需要使用 glTexImage3D。当调用 glTexImage3D 时,层数是您需要的立方体贴图数量乘以 6,因为每个立方体贴图面都像单独的层一样分配。在片段着色器中采样时不需要考虑这一点!

渲染阴影贴图时,您可以像绑定任何其他缓冲区一样绑定缓冲区。当您将深度纹理传递给着色器时,您将传递整个立方体贴图数组,无需弄乱单独的层。