feat: CSM 级联阴影(3 级联 × 1024²,实用分割 + 纹素对齐)

- SceneRenderer::ComputeCascades:相机视锥实用分割(λ=0.6)→ 反投影
  取切片角点 → 光空间 AABB 拟合 → 纹素对齐(消除相机移动时阴影边缘
  闪烁)→ [0,1] 深度重映射
- Shadow pass 单 pass 渲 3 个 region,每级联 push 各自光空间 VP
- Forward:UBO lightSpace[3]+cascadeSplits(视图深度选级联),Set2
  三张级联图按 binding 0/1/2 采样;vertex 输出 fragViewDepth
- 光源视锥剔除用最远级联(覆盖全阴影范围);双视锥独立剔除铁律保留
- 旧单张 2048 全场景图退役;近处级联分辨率 ~128px/unit(约 2× 提升)
- 编译零错误、validation 零警告、8 秒冒烟通过(10 pass 全活跃)
This commit is contained in:
2026-09-23 13:48:43 +08:00
parent 27b7f8785c
commit 0328d4aaeb
13 changed files with 250 additions and 141 deletions
+9 -8
View File
@@ -14,8 +14,8 @@ layout(location = 2) in vec2 inUV;
layout(location = 0) out vec2 fragUV;
layout(location = 1) out vec3 fragNormal;
layout(location = 2) out vec3 fragWorldPos;
layout(location = 3) out vec3 fragLightSpacePos;
layout(location = 4) out vec2 fragVelocity; // TAA:clip 空间运动向量
layout(location = 3) out float fragViewDepth; // CSM:视图深度(级联选择)
layout(location = 4) out vec2 fragVelocity; // TAA:clip 空间运动向量
// GPUDriven:模型矩阵从实例缓冲按实例索引取。
// 同一 mesh 的 N 个实体 = 1 次 drawIndexed(instanceCount=N),
@@ -31,12 +31,13 @@ layout(std430, set = 0, binding = 2) readonly buffer PrevObjectBuffer {
layout(set = 0, binding = 0) uniform UniformBufferObject {
mat4 view;
mat4 proj; // 抖动后(光栅化)
mat4 lightSpace;
mat4 proj;
mat4 lightSpace[3]; // CSM 各级联光空间 VP
vec4 cascadeSplits; // xyz = 级联 0..2 远边界(视图深度)
vec4 ambientColor;
Light lights[MAX_LIGHTS];
mat4 projNoJitter; // 未抖动(velocity 当前帧)
mat4 prevView; // velocity 上一帧
mat4 projNoJitter;
mat4 prevView;
mat4 prevProj;
} ubo;
@@ -54,8 +55,8 @@ void main() {
fragVelocity = (currClip.xy / currClip.w - prevClip.xy / prevClip.w) * 0.5;
fragWorldPos = worldPos.xyz;
// 光空间坐标(含 Vulkan [0,1] 深度重映射,与 shadow pass 写入端共用同一矩阵)
fragLightSpacePos = (ubo.lightSpace * worldPos).xyz;
// CSM:视图深度(正值,与 cascadeSplits 同尺度)
fragViewDepth = -(ubo.view * worldPos).z;
mat3 normalMatrix = mat3(transpose(inverse(model)));
fragNormal = normalize(normalMatrix * inNormal);