
反射
屏幕空间反射(Screen Space Reflections, SSR)是现代游戏引擎中实现实时反射的常用技术,尤其适用于处理水面、湿滑地面或金属等光滑表面的反射。
相比于传统的反射探针(Reflection Probes),它的优势在于能够捕捉场景中的动态变化,且反射效果在几何上更精确。
1. SSR 的核心原理
SSR 的本质是在屏幕空间(2D 缓冲区)中模拟光线投射的过程。它的工作流程主要分为以下几个步骤:
第一步:计算反射向量
对于屏幕上的每一个像素,根据观察方向 和该点的表面法线
(从深度图或 G-Buffer 中获取),计算出反射光线的方向向量
。
第二步:步进追踪 (Ray Marching)
这是 SSR 最耗性能的一步。
- 从当前像素的深度出发,沿着反射向量
在屏幕坐标系中一点点向远方“行走”。
- 每次移动一小步,就对比当前光线所在的深度值与该位置深度图(Z-Buffer)记录的深度值。
第三步:相交判定
- 如果光线的深度值大于深度图中记录的值,说明光线被场景中的物体挡住了,即找到了反射点。
- 通过相交点的屏幕坐标,直接去颜色缓冲(Color Buffer/Scene Color)中采样该点的颜色。
第四步:混合与衰减
将采样的颜色与原始像素颜色混合。为了让效果更自然,通常会根据光线传播距离、反射角以及屏幕边缘进行淡出处理(因为屏幕边缘外的物体无法被反射)。
2. Unity URP 是否有默认支持?
在 Unity URP 中,SSR 的支持情况经历了一些变化:
- 旧版本 (URP 12 以前): 官方没有提供默认的 SSR 实现。开发者通常需要去 Asset Store 购买插件(如 KPP)或自己写 Scriptable Render Feature。
- 新版本 (Unity 2022.2 / URP 14 及以上): Unity 引入了 Screen Space Reflections 作为官方支持的功能,但它有一定的前置条件:
- 必须使用延迟渲染路径 (Deferred Rendering Path)。在 Forward 渲染下,由于缺乏法线和深度信息的完整 G-Buffer,原生 SSR 无法直接工作。
- 需要在 Universal Render Pipeline Asset 中开启相关配置,并在 Volume 系统中添加 SSR 覆盖。
3. 如何在 URP 中实现或开启?
方式一:使用官方原生功能(推荐)
- 设置渲染器: 找到你的 Universal Renderer Data 资源,将 Rendering Path 改为 Deferred。
- 添加 Render Feature: 点击下方的 Add Render Feature,选择 Screen Space Reflections。
- 配置 Volume: 在场景的 Global Volume 中添加 Screen Space Reflections 组件,调节 Distance、Edge Fade 等参数。
方式二:手动实现(自定义渲染特性)(TODO 还没实现)
如果你必须在 Forward (前向渲染) 下使用,或者想追求极致性能,你需要通过 ScriptableRenderPass 编写自定义 Shader:
- 获取深度和法线: 在 C# 中开启 _CameraDepthTexture 和 _CameraNormalsTexture。
- 编写 Ray Marching Shader: * 在 Fragment Shader 中进行屏幕空间的射线步进。
- 使用 LinearEyeDepth 转换深度进行比较。
- 为了性能,通常会使用 Hierarchical Z-Buffer (Hi-Z) 追踪技术,即通过多级 Mipmap 深度图来跳过空旷区域。
4. SSR 的局限性
虽然 SSR 看起来很美,但它有几个“硬伤”:
- 屏幕外缺失: 如果反射的物体不在当前相机的视野内(例如你脚下的地板反射天花板,但你没抬头),SSR 就失效了。通常需要配合 Reflection Probes 作为兜底。
- 遮挡问题: 如果光线被面前的物体遮挡,反射就会出现空洞(Self-occlusion)。
- 性能消耗: Ray Marching 对 GPU 压力较大,尤其是在高分辨率下。
您是正在尝试为某个特定场景(如雨夜地面或室内水池)配置反射吗?我可以为您提供更具体的 Shader 思路或配置建议。
相关名词解释
G-Buffer
G-Buffer 就是一组存储在显存中的纹理图片,它们共同记录了摄像机视野中,每一个可见像素的“几何信息”和“材质属性”。
想象你在拍一张照片,拍完之后,你不仅得到了一张普通的彩色照片(颜色缓冲),还得到了几张“魔法底片”:
- 一张黑白底片:记录照片里每个点离你有多远(深度 Buffer)。
- 一张彩色底片:记录照片里每个点的表面朝向(法线 Buffer,也就是你问的这张)。
- 一张灰度底片:记录照片里每个点表面有多粗糙或多光滑(粗糙度 Buffer)。
- 一张彩色底片:记录每个点本来的颜色,不受光照影响(基础色 Buffer)。
这一组底片,就是 G-Buffer。