Shadow Map深度纹理必须用GL_DEPTH_COMPONENT,因其支持硬件深度比较(GL_COMPARE_REF_TO_TEXTURE)和PCF滤波;若用GL_R32F等格式则需手动比较,性能差且无法启用PCF。

为什么 shadow map 的深度纹理要用 GL_DEPTH_COMPONENT?
因为 OpenGL 的 shadow mapping 依赖硬件的深度比较(GL_COMPARE_REF_TO_TEXTURE),只有 GL_DEPTH_COMPONENT 格式的纹理才能启用这个特性。用 GL_R32F 或 GL_RG32F 存深度,虽然能写入,但 texture() 在 shader 中不会触发深度比较,你得手动写 compare 逻辑——这既慢又容易出错,还失去 PCF(百分比渐近过滤)支持。
正确做法:
- 创建纹理时指定
internalFormat = GL_DEPTH_COMPONENT,format = GL_DEPTH_COMPONENT - 绑定后调用
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE) - shader 中采样函数必须是
texture(sampler2DShadow, vec3),第三个分量是compare值(即 frag depth)
如何避免 shadow acne(阴影失真/条纹)?
这是最常被忽略的实操痛点:不是“加 bias 就完事”,而是要区分 bias 的来源和适用场景。
常见错误是只在 fragment shader 里统一加一个固定 0.005 偏移,结果导致靠近光的物体漏阴影、远处物体过深。
推荐组合方案:
- 在生成 shadow map 时,用
glPolygonOffset(1.0, 1000.0)渲染深度图(仅对正向渲染的 depth pass 生效) - 在 shadow shader 中,用斜率缩放 bias:
float bias = max(0.05 * (1.0 - dot(N, L)), 0.005);,其中N是世界法线,L是光源方向 - 如果用的是 directional light,建议在 light space 中做 bias(即 view-proj 变换后,对 z 值加偏移),而非 screen space
shadow map 分辨率太低导致锯齿严重,怎么平衡性能和质量?
64×64 肯定糊,2048×2048 在中低端 GPU 上可能掉帧——关键不在“设多大”,而在“给谁用”。
实际项目中应按光源类型分级处理:
- directional light(如太阳):用 1024×1024 或 2048×2048,配合 cascaded shadow map(CSM)分 3–4 层,每层分辨率可递减(如 2048→1024→512)
- point light:改用
GL_TEXTURE_CUBE_MAP+textureCubeShadow,单面建议 512×512,总内存开销是 6×512²×4B ≈ 6MB - spot light:512×512 通常够用;若锥角窄,可进一步缩到 256×256 并开启
GL_LINEARfilter
注意:glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 对 shadow map 有效,但 GL_NEAREST 会彻底关闭 PCF。
fragment shader 里 texture(sampler2DShadow, coords) 返回值为什么总是 0 或 1?
这不是 bug,是正常行为——sampler2DShadow 的 texture() 默认返回的是“比较通过率”(fraction of texels passing depth test),在无 filtering 时就是 0/1;开启 GL_LINEAR 后才是 [0,1] 浮点值。
检查以下三点:
-
coords.z必须是归一化设备坐标(NDC)范围的深度值(-1 到 1),且已从 [-1,1] 映射到 [0,1](常用(coords.z * 0.5 + 0.5)) - 传入 shader 的
coords.xy必须是 [0,1] 范围(即做完viewport变换后的裁剪坐标);漏了w除法会导致扭曲 - 确保 texture unit 绑定的是 depth 纹理,且该纹理的
GL_TEXTURE_COMPARE_MODE已设为GL_COMPARE_REF_TO_TEXTURE
最容易被忽略的是 NDC → [0,1] 的深度映射——漏掉这步,90% 的 shadow map 都会全黑或全白。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











