URP 渲染实战 / 第 8 章 环境光、光照贴图与反射探针 / 案例 8.11
案例 8.11Matcap 与环境光照的对比入门
目标:实现带透视修正的 Matcap,并通过移动相机说明它与真正的环境光照的本质区别。
Assets/Cookbook/Ch08/Matcap.shader(节选:matcap)
half4 frag(Varyings i) : SV_Target { float3 n = normalize(i.normalVS); float2 uv; if (_PerspectiveFix > 0.5) { // 透视修正:用“视线方向”构造一个局部坐标系,再把法线投影进去。 // 否则物体在画面边缘时,Matcap 会被明显拉扯(只有正交相机下 n.xy 才是准确的) float3 v = normalize(i.positionVS); // 观察空间里从相机指向表面 float3 r = cross(v, n); uv = float2(-r.y, r.x); } else { uv = n.xy; // 经典写法:直接取观察空间法线的 xy } uv = uv * 0.5 + 0.5; half3 c = SAMPLE_TEXTURE2D(_MatCap, sampler_MatCap, uv).rgb * _Tint.rgb; return half4(c, 1); }
void main() { vec3 n = normalize(normalVS); vec2 uv; if (_PerspectiveFix > 0.5) { // 透视修正:用“视线方向”构造一个局部坐标系,再把法线投影进去。 // 否则物体在画面边缘时,Matcap 会被明显拉扯(只有正交相机下 n.xy 才是准确的) vec3 v = normalize(positionVS); // 观察空间里从相机指向表面 vec3 r = cross(v, n); uv = vec2(-r.y, r.x); } else { uv = n.xy; // 经典写法:直接取观察空间法线的 xy } uv = uv * 0.5 + 0.5; vec3 c = texture(_MatCap, uv).rgb * _Tint.rgb; fragColor = vec4(c, 1.0); }
经典写法 uv = n.xy * 0.5 + 0.5 只在正交相机下准确;透视相机下,处在画面边缘的物体,视线方向与相机前方不一致,Matcap 会被明显拉扯。修正的思路是用“从相机指向该点的方向”构造局部坐标系:cross(v, n) 得到一个与视线和法线都垂直的向量,旋转 90° 后作为 UV。物体在画面中心时,它与经典写法完全一致。

| Matcap | SH + 反射探针(GILit) | |
|---|---|---|
| 开销 | 一次纹理采样 | SH 求值 + Cubemap 采样 + BRDF |
| 光照与场景 | 固定在相机上,换方向不变 | 来自世界,随物体位置和朝向变化 |
| 阴影、遮挡 | 没有 | 实时阴影、AO、光照贴图 |
| 适合 | 雕刻预览、UI 里的 3D 图标、风格化角色、低端设备的特效 | 需要融入场景的一切物体 |
Matcap 并非“错误”的技术——它的可控性极强,美术画什么就是什么,第 15 章还会把它用于风格化渲染。只是要清楚它不是环境光照:它不知道物体在场景里的哪里、周围是什么,也不会和其他物体产生任何光照上的联系。
本案例出自《URP 渲染实战》第 8 章「环境光、光照贴图与反射探针」。在章节中阅读上下文 →