带有立方体贴图的 OpenGL 点光阴影映射

Posted

技术标签:

【中文标题】带有立方体贴图的 OpenGL 点光阴影映射【英文标题】:OpenGL Pointlight Shadowmapping with Cubemaps 【发布时间】:2013-10-30 16:01:34 【问题描述】:

我想通过以下两个通道计算我的点光源的阴影:

首先,我使用场景对象的模型空间、立方体贴图面的相应视图矩阵和具有 90 度 FOV 的投影矩阵将场景从点光源的视图渲染到所有六个方向的立方体贴图中。然后我将顶点和光照位置之间的距离存储在世界空间中(这是相机的位置,所以只是在世界空间中渲染的顶点的长度)。 把世界空间放在这里合适吗?

立方体贴图是 GL_DEPTH_COMPONENT 类型的纹理。对于定向和聚光灯,阴影效果很好,但它们是单个 2D 纹理

这是我尝试存储距离的着色器:

顶点着色器:

#version 330
layout(location = 0) in vec3 vertexPosition;

uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;

out vec4 fragmentPosition_ws;

void main()
    gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(vertexPosition, 1.0);
    fragmentPosition_ws = modelMatrix * vec4(vertexPosition, 1.0);

片段着色器:

#version 330

// Ouput data
layout(location = 0) out float fragmentdist;

in vec4 fragmentPosition_ws;

void main()
    fragmentdist = length(fragmentPosition_ws.xyz);

在第二步中,当渲染照明本身时,我尝试像这样获取这些距离值:

float shadowFactor = 0.0;
vec3 fragmentToLightWS = lightPos_worldspace - fragmentPos_worldspace;

float distancerad = texture(shadowCubeMap, vec3(fragmentToLightWS)).x;

if(distancerad + 0.001 > length(fragmentToLightWS))
    shadowFactor = 1.0;

注意事项: shadowCubeMap 是 samplerCube 类型的采样器

lightPos_worldspace 是世界空间中的灯光位置(灯光已经在世界空间中 - 没有模型矩阵)

fragmentPos_worldspace是世界空间中的片段位置(*模型矩阵)

结果是,一切都被点亮了。不在阴影中。我敢肯定,渲染到阴影贴图中是有效的。我尝试了几种计算阴影的实现,有时还看到了类似阴影的东西,它可能是物体。但这是使用 NDC 阴影深度而不是距离方法。所以也要检查一下是否有错误。

【问题讨论】:

在渲染深度值时没有viewMatrix?您如何确定深度值进入立方体贴图的哪个面?此外,对于单个导出,layout(location = 0) 是不必要的,因为它是默认设置。 @thokra 不,写入纹理时没有距离值的视图矩阵。在代码中,我在将帧缓冲区绑定后选择我的脸: glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, face, _cubeMap, 0); face 是 GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,其中 i 从 0 到 5 将距离值与 viewmatrix 相乘效果不佳。一切仍然亮着。另外还有投影矩阵。 嗯,离光源的距离就是深度。您仍然需要正确定位顶点,以便将它们转换为光空间后的距离存储在正确的面内。因此,需要乘以当前光源的 viewMatrix。 说到在纹理中存储距离,这样做是在浪费内存带宽。更好的解决方案是使用常规的旧深度立方体贴图,然后在片段着色器中使用 float VectorToDepthValue(vec3 Vec) 中的 this question 之类的东西来解决比较问题。这将使您获得更好的阴影贴图吞吐量;添加执行比较的指令比增加内存带宽要求更可取,这已经严重占用了阴影。 【参考方案1】:

所以,我终于成功了。我有阴影:)

解决办法: 我按照建议使用了带有深度值的旧阴影贴图技术。我从立方体贴图中采样仍然使用光与顶点的差异(都在世界空间中),但我将值与提到的另一个问题中的 vertexToDepth() 方法进行了比较。

感谢您的帮助和澄清要点

重点是:始终确保比较相同的值!当 depthmap 存储 worldspace-depth 时,也与这样的值进行比较。

【讨论】:

以上是关于带有立方体贴图的 OpenGL 点光阴影映射的主要内容,如果未能解决你的问题,请参考以下文章

使用立方体贴图(OpenGL/GLSL)的点光源是不是可以实现软阴影?

OpenGL:渲染天空盒立方体贴图问题

CUDA 立方体贴图纹理

全向阴影贴图

Opengl:渲染到立方体贴图?

使用立方体贴图(不是反射贴图)对球体进行纹理处理