我编写了一个3D应用程序来管理聚光灯的阴影映射。为此,我使用了经典的阴影映射技术(在第一个渲染通道中填充深度纹理,在第二个渲染通道中比较从光源到第一个遮挡物的距离和从光源到顶点位置的距离,以确定我的片段是否处于阴影中)。
这是一个截图(聚光灯/2D深度纹理阴影映射): 在这个例子中,我使用PCF阴影映射技术,并使用函数“textureProjOffset”。这是我的片段着色器中的一段代码:
使用的采样器:
我还成功地管理了基本的立方体贴图阴影映射,目前应用于点光源的全方向阴影映射。为了在第一个渲染通道中实现此功能,我使用几何着色器来分发由6个阴影视锥提供的投影和视图矩阵(全部在一个通道中!这与填充6个单独纹理的技术不同,这次有6个渲染状态)。
以下是截图(聚光灯/立方体深度纹理阴影映射):
请参见以下代码片段,其中包含从片段着色器到深度值的转换过程:
如您所见,这只是硬阴影映射。为了恢复编码到立方体贴图中的深度值,这次我必须使用函数'texture'(对于'samplerCube'和'samplerCubeShadow','textureProj'不存在)。接下来,我需要计算世界空间中光位置和顶点位置之间的距离,然后将其转换为剪辑空间,因为纹理中包含的深度值已经处于剪辑空间中。
采样器使用:
关于使用立方体贴图实现PCF软阴影,我进行了一些研究,似乎没有任何函数可以像在简单的2D纹理中使用'sampler2DShadow'关键字那样恢复纹理偏移量。我错了吗?(希望如此!)
如果不存在使用立方体贴图的解决方案,我认为我有一个解决方案:显然,要恢复纹理偏移量,我将不得不使用6个单独的纹理(因此是大小为6的'sampler2DShadow'数组,而不是'samplerCubeShadow')。所以我将同样作为均匀变量使用一个matrix4x4数组,表示光空间中世界的表示,就像我在第一种情况下为聚光灯阴影映射所做的那样。然后,我将使用'textureProjOffset'方法对6个纹理进行操作。
那么,你认为呢?使用立方体贴图是否可能实现PCF软阴影?如果不是这种情况,我的解决方案是否正确?是否可以使用类似于'samplerCube'或'samplerCubeShadow'的'textureProjOffset'函数?还是有其他替代方案?
非常感谢您提前的帮助!
这是一个截图(聚光灯/2D深度纹理阴影映射): 在这个例子中,我使用PCF阴影映射技术,并使用函数“textureProjOffset”。这是我的片段着色器中的一段代码:
使用的采样器:
sampler2DShadow Shadow2DSampler[MAX_LIGHTS_COUNT];
对于硬阴影:
shadowFactor = textureProj(Shadow2DSampler[idx], ShadowCoords[idx]);
对于PCF软阴影:
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软阴影,我进行了一些研究,似乎没有任何函数可以像在简单的2D纹理中使用'sampler2DShadow'关键字那样恢复纹理偏移量。我错了吗?(希望如此!)
如果不存在使用立方体贴图的解决方案,我认为我有一个解决方案:显然,要恢复纹理偏移量,我将不得不使用6个单独的纹理(因此是大小为6的'sampler2DShadow'数组,而不是'samplerCubeShadow')。所以我将同样作为均匀变量使用一个matrix4x4数组,表示光空间中世界的表示,就像我在第一种情况下为聚光灯阴影映射所做的那样。然后,我将使用'textureProjOffset'方法对6个纹理进行操作。
那么,你认为呢?使用立方体贴图是否可能实现PCF软阴影?如果不是这种情况,我的解决方案是否正确?是否可以使用类似于'samplerCube'或'samplerCubeShadow'的'textureProjOffset'函数?还是有其他替代方案?
非常感谢您提前的帮助!
samplerCubeShadow
和GL_LINEAR
滤镜,则会自动执行2x2 PCF。然而, 2x2窗口相当小,因此您应该将硬件PCF与一些偏移量结合使用以增加有效的窗口大小。该文章由于年代久远未利用硬件进行2x2 PCF,但通常情况下应该采用这种方法来解决问题。如果利用这一点,您可以使用4个查找而不是16个查找来实现4x4 PCF。 - Andon M. Coleman