最近在学习制作宝石材质时发现了一个 Unity 宝石的插件 R Gem Effect,第一次看这个视频的时候就觉得很惊艳,可惜这个插件在 Unity 商店里下架了。看视频可以发现,原作者使用了光线追踪,所以就想自己在 Unity 里实现这样的效果。
*项目中的模型来自 R Gem Effect Unity Plugin ,HDR 环境图来自 HDRIHaven
Github: github.com/Sorumi/UnityRayTracingGem
博文原文:sorumi.xyz/posts/unity-toon-shader/
Ray Tracing
光线追踪是指从摄像机出发的若干条光线,每条光线会和场景里的物体求交,根据交点位置获取表面的材质、纹理等信息,并结合光源信息计算光照。相对于传统的光栅化渲染,光线追踪可以轻松模拟各种光学效果,如反射、折射、散射、色散等。但由于在进行求交计算时需要知道整个场景的信息,其计算成本非常高。
关于如何在 Unity 中进行 Ray Tracing,我参考了 GPU Ray Tracing in Unity这个系列的文章,使用了 Compute Shader 来实现。
实时渲染宝石
实时渲染不同于离线渲染,不可能在整个场景中都使用光线追踪,又由于宝石材质的特殊性,我对其进行一下几点约束 (tricks):
- 整个场景使用光栅化渲染流程,只有在渲染宝石物体时,使用光线追踪,在片元着色器中从摄像机放射光线。
- 每个宝石物体在光线追踪时,只和自己的 Mesh 模型进行求交点的计算。
- 只使用光线追踪来计算光线的折射和反射。
- 假设宝石表面是完全光滑的,不考虑微表面,且内部无任何杂质。其表面只有 specular 项,无 diffuse 项。
- 光线仅在第一次与宝石表面相交时,被分为反射光线和折射光线,之后折射光线在宝石的内部进行全反射或其折射出宝石表面。
- 光线经过反射或折射,射出宝石表面后,对天空球进行采样。
由于我们在着色器中传递整个模型数据,需要使用 ComputeBuffer
,这一般是为 Compute Shader 提供的,要在一般的顶点像素着色器中使用,需要至少支持 shader model 4.5 。在 Shader 中,ComputeBuffer
映射的数据类型为 StructuredBuffer<T>
和 RWStructuredBuffer<T>
。
折射
通过入射光线方向、入射点法线方向、入射介质折射率、出射介质折射率来计算出射光线方向:
T = η 1 η 2 ( I + cos ( θ 1 ) N ) − N 1 − ( η 1 η 2 ) 2 ( 1 − cos 2 ( θ 1 ) ) T=\frac{\eta_{1}}{\eta_{2}}\left(I+\cos \left(\theta_{1}\right) N\right)-N \sqrt{1-\left(\frac{\eta_{1}}{\eta_{2}}\right)^{2}\left(1-\cos ^{2}\left(\theta_{1}\right)\right)} T=η2η1(I+cos(θ1)N)−N1−(