OpenGL方向光伪全向阴影实现异常:近太阳行星错误遮挡其余行星
异常产生原因
- 阴影贴图与光照空间矩阵不匹配:你为每个行星单独生成了专属的
lightSpaceMatrix,但所有行星共用同一张阴影贴图。若阴影贴图是使用距离太阳最近的行星的光照空间矩阵渲染生成,其他行星使用自身矩阵采样这张阴影贴图时坐标完全不对应,就会出现最近行星的深度信息覆盖所有采样结果的情况,导致误判遮挡。 - 正交投影参数错误:构造光源正交投影时直接使用了相机的近远平面作为阴影投影的近远面,没有使用光源空间下所有物体的实际深度范围,导致深度计算偏差。且投影的宽高范围仅设置为当前行星半径的3倍,无法覆盖其他可能投射阴影的远距离行星,超出范围的物体会被错误裁切。
- 缺少阴影采样范围校验:片元着色器的阴影计算逻辑没有对投影坐标做范围判断,当片元不在当前阴影贴图的覆盖范围内时,会采样到阴影贴图边缘的错误深度值,导致误判为有阴影。
- 深度缓冲逻辑不一致:场景渲染使用了对数深度缓冲,如果阴影贴图渲染阶段没有使用相同的对数深度计算逻辑,会导致阴影贴图存储的深度值与场景渲染时计算的
currentDepth不匹配,出现阴影误判。
修复方案
- 调整阴影贴图生成逻辑
若保留每个行星单独光照空间矩阵的实现方案,需要为每个行星分配独立的阴影贴图:渲染阴影贴图时,遍历每个行星,切换到该行星对应的lightSpaceMatrix,将场景中所有行星、卫星都渲染到该行星专属的阴影贴图中。如果场景范围过大,更推荐改用级联阴影贴图(CSM)方案,针对方向光统一生成多档深度的阴影贴图,不需要为每个行星单独维护阴影资源,性能更优。 - 修正正交投影参数
构造光源正交投影时不要使用相机的近远平面:先计算当前光源空间下所有需要投射阴影的物体的AABB包围盒,使用包围盒的最小、最大Z值作为正交投影的近远面;同时适当扩大正交投影的宽高范围,确保覆盖所有可能投射阴影到当前行星的物体,不要限制为当前行星半径的3倍。 - 增加阴影采样范围校验
在CalculateShadow函数开头添加坐标范围判断,超出范围的片元直接返回无阴影:float CalculateShadow(vec4 fragPosLightSpace) { // Perform perspective divide vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w; // 新增:超出阴影覆盖范围直接返回无阴影 if(projCoords.z > 1.0 || projCoords.x < 0.0 || projCoords.x > 1.0 || projCoords.y < 0.0 || projCoords.y > 1.0) { return 0.0; } // Transform to [0,1] range projCoords = projCoords * 0.5 + 0.5; // 原有后续逻辑保持不变 ... } - 统一深度缓冲逻辑
阴影贴图渲染阶段的顶点着色器也需要添加和场景渲染相同的对数深度缓冲计算代码,保证两边生成的深度值一致。
内容的提问来源于stack exchange,提问作者Глеб Труфанов
相关产品推荐
相关产品推荐

