noteForOpenGL 点光源阴影进阶:多Pass方案与几何着色器方案深度对比

📅 2026/8/23 10:51:32
noteForOpenGL 点光源阴影进阶:多Pass方案与几何着色器方案深度对比
noteForOpenGL 点光源阴影进阶多Pass方案与几何着色器方案深度对比【免费下载链接】noteForOpenGLOpenGL学习脚印配套代码项目地址: https://gitcode.com/gh_mirrors/no/noteForOpenGLnoteForOpenGL 是一个 OpenGL 学习脚印配套代码项目本教程带你掌握点光源阴影Point Light Shadow的两条主流路线基于CubeMap 深度图的多 Pass 渲染方案以及用几何着色器Geometry Shader一次绘制六面的高性能方案并附软阴影 PCF 与新手避坑清单。为什么点光源阴影比平行光更难平行光阴影只需要一张 2D 深度图而点光源向四面八方发光必须从 6 个方向±X、±Y、±Z各拍一张深度图存进一个CubeMap 立方体贴图里。渲染时着色器只需把片元→光源的方向向量直接作为坐标去采样 CubeMap就能拿到光源看到的最近距离与片元到光源的真实距离一比就知道这个片元是否在阴影里。这个对比是点光源阴影相对平行光最优雅的地方方向即坐标采样即阴影。方案一多Pass渲染六张深度图多 Pass 方案思路直白把场景从光源视角渲染 6 遍每一遍绑定 CubeMap 的一个面for (GLuint i 0; i 6; i) { glUniformMatrix4fv(..., lightVPMatrix, ..., shadowTransforms[i]); glBindFramebuffer(GL_FRAMEBUFFER, depthFBOId); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X i, depthCubeMapTextId, 0); glClear(GL_DEPTH_BUFFER_BIT); renderScene(depthMapShader); }核心细节6 个方向矩阵每个面用透视投影 × lookAt合成6 个方向的 up 向量各不相同例如朝 Z 方向时 up 取 (0,-1,0)手动写深度片元着色器不用默认的gl_FragCoord.z而是手动计算片元到光源距离 / far_plane 写入gl_FragDepth这样深度图里存的就是真实距离法线反转深度 Pass 中关闭背面剔除并翻转法线因为从光源视角看原来朝向光源的面反而是背面边界处理CubeMap 必须用GL_CLAMP_TO_EDGE且边框颜色设为白色距离最远处否则阴影边缘会出错运行效果如下按 B 键可开关阴影P 键切换 PCF 软阴影优点逻辑简单容易调试。缺点同一个场景画了 6 遍几何量大时 CPU 端 6 次 draw call 状态切换开销明显。方案二几何着色器一次绘制六面几何着色器方案把6 个 Pass压缩成1 个 Pass、1 次 draw calllayout (triangles) in; layout (triangle_strip, max_vertices 18) out; uniform mat4 shadowMatrices[6]; void main() { for (int face 0; face 6; face) { gl_Layer face; // 指定写入 CubeMap 的第几面 for (int i 0; i 3; i) { FragPos gl_in[i].gl_Position; gl_Position shadowMatrices[face] * FragPos; EmitVertex(); } EndPrimitive(); } }两个关键机制gl_Layer几何着色器的超能力指定当前图元写入纹理数组的哪一层CubeMap 恰好是 6 层6 个矩阵数组CPU 端把 6 个方向的 View-Projection 矩阵一次性传给着色器每个输入三角形被复制成 6 份分别变换到 6 个面代价是顶点被放大了 6 倍1 个三角形 → 18 个顶点对 GPU 顶点吞吐有压力但省掉了 5 次 draw call 和 CPU 状态切换。几何量小、CPU 瓶颈明显时GS 方案更快几何量极大时反而多 Pass 更划算这是典型的 GPU/CPU 权衡。片元着色器与多 Pass 方案完全相同手动gl_FragDepth说明两方案只是深度图生成方式不同阴影计算逻辑通用。效果升级PCF 软阴影与距离感知采样硬阴影边缘锯齿明显noteForOpenGL 用Percentage-Closer FilteringPCF生成软阴影在光源方向上取 20 个采样点构成圆盘统计落在阴影中的比例作为连续阴影值。float diskRadius (1.0 (viewDistance / far_plane)) / 25.0;注意采样半径会随观察距离变化避免近处过软、远处过硬。效果对比如下新手避坑清单点光源阴影3个高频错误坑 1投影矩阵忘记转弧度glm::perspective的 FOV 参数是弧度传入角度值比如 90.0会让视锥严重变形典型症状是 CubeMap 面之间出现黑边或阴影断裂务必写成glm::radians(90.0f)坑 2Shadow Acne阴影痤疮浮点精度导致表面自我遮挡产生斑点状条纹。解法是在比较时减去一个偏置量bias注意 PCF 的 bias 通常要比硬阴影大如 0.05 → 0.15。坑 3Peter Panning彼得潘效应bias 开太大阴影会漂离物体。多 Pass 方案靠精度足够的高程深度图控制GS 方案还要额外注意 6 层写入时max_vertices必须设为 18。模块路径速查两个方案的完整可运行代码都在advancedLighting/pointShadow/目录下方案目录说明多 Pass立方体场景advancedLighting/pointShadow/multiPassPointShadow/含shadowMapping.cpp、depthMap.vertex、depthMap.frag多 Pass模型场景advancedLighting/pointShadow/multiPassPointShadowWithModel/加载纳米战斗服模型几何着色器方案advancedLighting/pointShadow/geometryShader-PointShadow/核心文件depthMap.gs关键文件一览深度 Pass 片元手动写gl_FragDepthadvancedLighting/pointShadow/multiPassPointShadow/depthMap.frag几何着色器gl_Layer六面写入advancedLighting/pointShadow/geometryShader-PointShadow/depthMap.gs场景着色器CubeMap 采样 PCF 软阴影advancedLighting/pointShadow/multiPassPointShadow/scene.frag主程序6 个方向矩阵与两 Pass 流程advancedLighting/pointShadow/multiPassPointShadow/shadowMapping.cpp配套基础平行光阴影、PCF、bias 调试可参考advancedLighting/shadowMapping/目录下的 shadowMapping1/2 示例纹理资源位于resources/textures/如wood.png。总结怎么选想快速理解原理先读多 Pass 方案6 次循环把 CubeMap 深度图流程讲得明明白白追求性能换用几何着色器1 次 draw call 搞定记得max_vertices 18阴影要好看上 PCF20 点圆盘采样 距离感知半径软阴影立现效果不对先查glm::radians没加、CubeMap 边界不是 CLAMP_TO_EDGE、bias 取值失衡三件套排查 90% 的问题点光源阴影是阴影映射从入门迈向进阶的关键一步把 CubeMap、几何着色器、PCF 三块积木搭好你就具备了实现全局动态阴影CSM、点光源集群的全部基础。【免费下载链接】noteForOpenGLOpenGL学习脚印配套代码项目地址: https://gitcode.com/gh_mirrors/no/noteForOpenGL创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考