首先,光源到纹理空间中片段的方向是:
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 )是当前片段的高度:
currentLayerDepth
float currentDepthMapValue = texture(heightMap, currentTexCoords).r; float currentLayerDepth = currentDepthMapValue;
由于深度毛是反深度图(1.0是低),如果有任何层深度,则片段处于阴影中( currentLayerDepth )小于或等于当前高度( currentDepthMapValue )。如果达到最大深度(最小值0.0),则必须中止采样。 注意,深度递减( currentLayerDepth -= layerDepth )并且纹理样本以相反的方向拍摄( currentTexCoords += deltaTexCoords )比较 ParallaxMapping 算法:
currentDepthMapValue
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;
由于z分量的划分( P = lightDir.xy / lightDir.z ) P 因此 deltaTexCoords ,始终指向光源(当然在投影到纹理)。 如果是z分量的 lightDir 大于0.0,表面从背面照亮。这导致早期中止的条件:
P = lightDir.xy / lightDir.z
P
deltaTexCoords
lightDir
if ( lightDir.z >= 0.0 ) return 0.0;
功能齐全 ShadowCalc 功能可能如下所示:
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; }