本文最后更新于 2025年5月8日 晚上
【基于物理的渲染(3)】基于图片的渲染
上述 CookTorrance 公式中还缺少环境光的处理,在 PBR 中环境光是用 IBL 实现的。
IBL 中由于光来自一个完整的球面,因此需要对球面积分计算,但这样工作量太大了。考虑到物体表面受到的环境光不会改变,因此可以提前预处理,将部分光照提前计算存放到环境贴图中。因此对于间接光,不能直接使用直接光的反射率方程。
在Unity中:预计算的漫射光使用SH存储;镜射光使用立方体纹理存储,并根据不同粗糙度存储了多份放在了mipmap中。
漫射光最简单,从SH中取出的就是辐射率,直接乘上漫射的反射率即可。镜射光则需要根据不同的粗糙度采样不同mipmap的立方体贴图来获得进行一定处理后的辐射率,然后乘上反射衰减和高光颜色(反射光)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| float3 GlobalIlluminationDiffuse_Unity(float3 n, float3 diffuse) { half3 radiance = SampleSH(n);
return diffuse * radiance; }
float3 GlobalIlluminationSpecular_Unity(float3 n, float3 v, float3 specular, float metallic, float smoothness) { float perceptualRoughness = 1 - smoothness; float roughness = max(pow(1 - smoothness, 2),HALF_MIN_SQRT); float roughness2 = roughness * roughness;
float3 radiance = GlossyEnvironmentReflection(reflect(-v, n), perceptualRoughness, 1);
//反射衰减(确保能量守恒) float surfaceReduction = 1.0 / (roughness2 + 1.0);
//镜射光反射率 float fresnel = Pow4(1.0 - saturate(dot(n, v))); //菲涅尔效应导致光全反射 float ks = lerp(0.04, 1, metallic); //镜射率 float3 finalSpecular = lerp(specular, saturate(ks + smoothness), fresnel);
return finalSpecular * radiance * surfaceReduction; }
HLSL
|