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

Shadow Mapping空间变换异常问题排查求助

Shadow Mapping 空间变换错误排查与修正

核心问题定位

阴影随相机位置变化,说明世界空间位置计算错误,或光源深度缓冲区存储/采样的范围不匹配,导致阴影判断逻辑依赖了观察者视角(相机)的错误空间数据。

具体错误点与修正方案

1. 视图空间转世界空间的矩阵乘法顺序错误

HLSL 中矩阵默认是列主序,向量需作为列向量参与乘法。逆视图矩阵(invV)的作用是将视图空间位置转换为世界空间位置,正确的乘法顺序应为矩阵在前,向量在后:

原错误代码:

float4 pixelPosWorld = mul(pixelPosView, invV);

修正后:

float4 pixelPosWorld = mul(invV, pixelPosView);

原因:mul(矩阵, 列向量)才是正确的线性变换顺序,原写法将向量作为行向量计算,会导致空间变换完全错误,最终世界空间位置随相机位置偏移,进而影响阴影判断。

2. 光源深度存储时未转换到[0..1]范围

Pass1 中,直接将光源视角下的 NDC 深度(z/w,范围[-1..1])存入纹理通道,但纹理的像素值范围是[0..1],负数深度会被截断为0,导致深度数据丢失:

原错误代码:

output.lightDepths.r = input.lightDepth.x / input.lightDepth.y;

修正后:

// 将 NDC 深度 [-1..1] 转换为 [0..1] 后存储
output.lightDepths.r = (input.lightDepth.x / input.lightDepth.y) * 0.5 + 0.5;

同时,阴影计算时currentDepth已经转换为[0..1],修正后采样到的closestDepth范围与之匹配,比较逻辑才正确。

3. 确认深度转视图空间的Y轴翻转逻辑

在depthToViewSpace中,Y轴翻转代码:

float y = (1 - xy.y) * 2 - 1;

这一步是因为纹理坐标Y轴与NDC Y轴方向相反,结合你使用XMMatrixPerspectiveFovLH(左手坐标系投影矩阵),该逻辑是正确的,可保留。

4. 光源视图投影矩阵转置验证

CPP代码中对light.viewProj的转置存储是正确的:

XMStoreFloat4x4(&_cLightBuffer.light.viewProj, XMMatrixTranspose(XMMatrixMultiply(lightView, lightProj)));

HLSL 用列主序矩阵,DirectX的XMMatrix默认行主序,转置后传入Shader符合要求,此步骤无问题。

测试建议

  1. 优先修正矩阵乘法顺序和光源深度存储范围,再测试相机Z轴翻转后的阴影效果;
  2. 在Pass2中输出pixelPosWorld的RGB值,可视化世界空间位置是否稳定(物体世界空间位置不应随相机移动而变化);
  3. 暂时关闭阴影比较逻辑,直接输出projCoords.z和closestDepth的灰度值,检查两者范围是否一致。

内容的提问来源于stack exchange,提问作者vK 3 1 RON

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 23:01:34