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

Posted

技术标签:

【中文标题】使用立方体贴图(OpenGL/GLSL)的点光源是不是可以实现软阴影?【英文标题】:Are soft shadows possible with point light using cubemap (OpenGL/GLSL)?使用立方体贴图(OpenGL/GLSL)的点光源是否可以实现软阴影? 【发布时间】:2014-11-22 15:43:30 【问题描述】:

我编写了一个 3D 应用程序来管理聚光灯阴影映射。为此,我使用了经典的阴影映射技术(我在第一个渲染通道中填充了深度纹理,在第二个渲染通道中,我比较了从灯光到第一个遮挡物的距离以及从灯光到顶点位置的距离,以了解我的片段是否在阴影中)。

这是一个屏幕截图(聚光灯/2D 深度纹理阴影映射):

在这个例子中,我使用了函数“textureProjOffset”的 PCF 阴影映射技术。这是我的片段着色器中的一段代码:

使用的采样器:

sampler2DShadow Shadow2DSampler[MAX_LIGHTS_COUNT];

对于硬阴影:

shadowFactor = textureProj(Shadow2DSampler[idx], ShadowCoords[idx]);

对于 PCF SOFT 阴影:

for (int idy = offset; idy >= -offset; idy--)
                for (int idx = -offset; idx <= offset; idx++)
                    shadowFactor += textureProjOffset(
                        Shadow2DSampler[idz], ShadowCoords[idz], ivec2(idx, idy)); 

我还管理了基本的立方体贴图阴影贴图,以管理当前应用于点光源的全向阴影贴图。为了在第一个渲染通道中执行此操作,我使用几何着色器来调度由 6 个阴影截头体提供的投影和视图矩阵(全部在一个通道中!这与这次用 6 个渲染状态填充 6 个单独纹理的技术不同)。

这是一个截图(聚光灯/立方体深度纹理阴影映射):

如您所见,这只是硬阴影贴图。为了恢复编码到立方体贴图中的深度值,这次我必须使用函数'texture'('samplerCube'和'samplerCubeShadow'不存在textureProj)。接下来我必须计算世界空间中光源位置和顶点位置之间的距离,然后将其转换为剪辑空间,因为纹理中包含的深度值已经在剪辑空间中。

这是片段着色器中的一段代码,可以查看该过程:

使用的采样器:

samplerCubeShadow ShadowCubeSampler[MAX_LIGHTS_COUNT];

对于硬阴影:

float ConvertDistToClipSpace(vec3 lightDir_ws)

    vec3 AbsVec = abs(lightDir_ws);
    float LocalZcomp = max(AbsVec.x, max(AbsVec.y, AbsVec.z));

    float NormZComp = (NearFar.y + NearFar.x)/(NearFar.y - NearFar.x)
        - (2.0f * NearFar.y * NearFar.x)/(LocalZcomp * NearFar.y - NearFar.x);

    return ((NormZComp + 1) * 0.5f);


float GetBiased_Cube_Hard_ShadowFactor(vec3 vertexPosition_ws, int idx)

    vec3 lightToVertexDir_ws = vertexPosition_ws - LightPos_ws.xyz;
    float LightToVertexClipDist = ConvertDistToClipSpace(lightToVertexDir_ws);

    float LightToOccluderClipDist = texture(
        ShadowCubeSampler[idx], vec4(lightToVertexDir_ws, LightToVertexClipDist));

    if (LightToOccluderClipDist < LightToVertexClipDist)
        return (0.0f);
    return (1.0f);

知道,使用立方体贴图的 PCF SOFT 阴影怎么样?我做了一些研究,显然它不存在任何恢复纹理偏移的功能,就像使用简单的 2D 纹理和在片段着色器中使用关键字“sampler2DShadow”一样。我错了吗 ? (希望如此!)。

我想我有一个解决方案(当然如果它不存在立方体贴图的任何解决方案):

显然,要恢复纹理偏移,我将不得不使用 6 个单独的纹理(因此,一个大小为 6 的“sampler2DShadow”数组而不是“samplerCubeShadow”)。因此,我将拥有一个同样均匀的矩阵 4x4 数组来表示光空间中的世界表示,就像我在第一个案例中对聚光灯阴影映射所做的那样。然后我将使用“textureProjOffset”方法来处理这 6 个纹理。

那么,你怎么看?是否可以使用立方体贴图进行 PCF 软阴影?如果不是这样,我的解决方案是否正确?是否可以使用“samplerCube”或“samplerCubeShadow”来使用“textureProjOffset”之类的函数?或者有其他选择吗?

非常感谢您的帮助!

【问题讨论】:

【参考方案1】:

我知道为立方体贴图实现 PCF 软阴影的唯一方法是使用小偏移量多次查询纹理。这个方法例如在这个GPU Gems article (12.4)中描述。

【讨论】:

非常感谢您的回答。再见。 在现代 AMD 和 NV 驱动程序上,如果您使用 samplerCubeShadowGL_LINEAR 作为过滤器,它将自动执行 2x2 PCF。不过 2x2 窗口非常小,因此您可能应该将硬件 PCF 与一些偏移量结合起来以增加有效窗口大小。由于年代久远,那篇文章没有利用硬件执行 2x2 PCF 的能力,但这通常是您解决问题的方式。如果利用这一点,您可以使用 4 个查找而不是 16 个查找来实现 4x4 PCF。

以上是关于使用立方体贴图(OpenGL/GLSL)的点光源是不是可以实现软阴影?的主要内容,如果未能解决你的问题,请参考以下文章

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

在立方体贴图中跨摄像机渲染点精灵

OpenGL中的单色渲染到帧缓冲区对象?

提高点光源的阴影贴图性能?

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

9 UE4光照和雾的制作