首先,纹理空间中光源到片段的方向是:
vec3 lightDir = TBN_norm * normalize(o_worldPos - light_pos);
float dc = max(0.0, dot(-lightDir, normal));
要检查片段是否处于自阴影中,您必须从“视差”纹理像素开始跟踪到光源的光线。
float shadow = dc > 0.0 ? ShadowCalc(currentTex, lightDir) : 0.0;
初始高度(currentLayerDepth
) 是当前片段的高度:
float currentDepthMapValue = texture(heightMap, currentTexCoords).r;
float currentLayerDepth = currentDepthMapValue;
由于深度 mao 是逆深度图(1.0 较低),因此如果任何层深度(currentLayerDepth
) 小于或等于当前高度 (currentDepthMapValue
)。如果达到最大深度(最小值 0.0),则必须中止采样。
请注意,深度会递减(currentLayerDepth -= layerDepth
)并且纹理样本是在相反的方向上获取的(currentTexCoords += deltaTexCoords
) 比较ParallaxMapping
算法:
while (currentLayerDepth <= currentDepthMapValue && currentLayerDepth > 0.0)
{
currentTexCoords += deltaTexCoords;
currentDepthMapValue = texture(heightMap, currentTexCoords).r;
currentLayerDepth -= layerDepth;
}
float r = currentLayerDepth > currentDepthMapValue ? 0.0 : 1.0;
由于除以 (P = lightDir.xy / lightDir.z
), P
因此deltaTexCoords
,始终指向光源(当然是在投影到纹理时)。
如果 z 分量lightDir
大于0.0,表面从背面照亮。这会导致提前中止的条件:
if ( lightDir.z >= 0.0 )
return 0.0;
功能齐全ShadowCalc
函数可能如下所示:
float ShadowCalc(vec2 texCoord, vec3 lightDir)
{
if ( lightDir.z >= 0.0 )
return 0.0;
float minLayers = 0;
float maxLayers = 32;
float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0, 0.0, 1.0), lightDir)));
vec2 currentTexCoords = texCoord;
float currentDepthMapValue = texture(heightMap, currentTexCoords).r;
float currentLayerDepth = currentDepthMapValue;
float layerDepth = 1.0 / numLayers;
vec2 P = lightDir.xy / lightDir.z * heightScale;
vec2 deltaTexCoords = P / numLayers;
while (currentLayerDepth <= currentDepthMapValue && currentLayerDepth > 0.0)
{
currentTexCoords += deltaTexCoords;
currentDepthMapValue = texture(heightMap, currentTexCoords).r;
currentLayerDepth -= layerDepth;
}
float r = currentLayerDepth > currentDepthMapValue ? 0.0 : 1.0;
return r;
}