You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

延迟渲染中方向阴影映射实现故障求助

问题分析与修正方案

看起来你遇到的核心问题是阴影图存储的深度值与光照阶段使用的深度值完全不匹配,导致所有像素都被判定为在阴影中(lit_factor=0),所以画面全黑。下面我会一步步拆解问题并给出修正方案:

1. 阴影生成阶段的深度计算错误

你的阴影顶点着色器里手动缩放深度值的逻辑是错误的:

depth = (lightViewMat * vert).z / (500 * 0.2);

这里有两个关键问题:

  • 方向光使用正交投影,光源空间的z值不需要这种手动缩放,而且这个缩放后的范围和光照阶段计算的currentDepth(齐次坐标z值)完全不在一个尺度上。
  • 正确的做法应该是基于正交投影后的NDC(标准化设备坐标)深度来生成阴影图,这样才能和光照阶段的投影结果对齐。

修改后的阴影生成着色器

顶点着色器

#version 330 compatibility
uniform mat4 lightViewProjMat; // lightView * lightProj
in vec3 in_vertex;
out float depth;

void main() {
    vec4 vertLightSpace = lightViewProjMat * vec4(in_vertex, 1.0);
    // 将NDC的z值(范围[-1,1])转换到[0,1]范围,方便存储和采样
    depth = (vertLightSpace.z / vertLightSpace.w) * 0.5 + 0.5;
    gl_Position = vertLightSpace;
}

像素着色器

#version 330
in float depth;
out vec2 out_depth;

void main() {
    // 直接存储深度值和深度平方,为后续VSM做准备
    out_depth = vec2(depth, depth * depth);
}

2. 光照阶段的深度值匹配问题

原来的光照像素着色器中,currentDepth直接使用了fragPosLightSpace.z,这是齐次坐标下的z值(范围由你的正交投影矩阵的near/far决定),和阴影图中存储的[0,1]范围深度值完全不匹配,导致currentDepth始终大于lightViewDepth,所有像素都被判定为阴影。

修改后的光照像素着色器

#version 330
in vec2 texCoord;
out vec3 fragColor;

uniform mat4 lightViewProjMat;
uniform sampler2D sceneTexture;
uniform sampler2D shadowMapTexture;
uniform sampler2D scenePosTexture;

void main() {
    vec3 fragPos = texture(scenePosTexture, texCoord).xyz;
    vec4 fragPosLightSpace = lightViewProjMat * vec4(fragPos, 1.0);
    
    // 投影纹理映射:转换到[0,1]纹理坐标范围
    vec3 coord = fragPosLightSpace.xyz / fragPosLightSpace.w;
    coord = coord * 0.5 + 0.5;
    
    // 检查坐标是否在阴影图纹理范围内,超出则视为不在阴影中
    if (coord.x < 0.0 || coord.x > 1.0 || coord.y < 0.0 || coord.y > 1.0) {
        fragColor = texture(sceneTexture, texCoord).rgb;
        return;
    }
    
    // 获取阴影图中的深度矩
    vec2 moments = texture(shadowMapTexture, coord.xy).xy;
    float lightViewDepth = moments.x;
    
    // 将当前像素的深度转换到[0,1]范围,和阴影图匹配
    float currentDepth = (fragPosLightSpace.z / fragPosLightSpace.w) * 0.5 + 0.5;
    
    // 基础阴影判断(加入微小偏移解决阴影 acne,后续可替换为VSM的方差计算)
    float lit_factor = 0.0;
    if (currentDepth <= lightViewDepth + 0.0001) {
        lit_factor = 1.0;
    }
    
    fragColor = texture(sceneTexture, texCoord).rgb * lit_factor;
}

3. 额外注意事项

  • 阴影 acne 解决:我在判断中加入了+0.0001的偏移,这是因为深度值的精度问题,可能导致表面自身被判定为阴影,这个偏移值可以根据你的场景尺度调整。
  • 正交投影矩阵设置:确保你的lightViewProjMat中的正交投影矩阵lightProj的near和far参数设置正确,覆盖你的场景范围,否则会出现深度值溢出的问题。
  • 纹理过滤:当前阶段可以使用GL_NEAREST过滤,后续切换到VSM时需要改为GL_LINEAR,因为VSM需要线性采样矩值。

内容的提问来源于stack exchange,提问作者Manh Nguyen Tien

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:03:05