Unity shader阴影
参考书籍:《Unity Shader入门精要》
阴影是如何实现的
在实时渲染中,我们最常使用的是一种名为Shadow Map的技术。这种技术的原理是将摄像机放到与光源重合的位置上,那么场景中该光源的阴影区域就是那些摄像机看不到的地方。Unity使用的就是这种技术。
在前向渲染路径中,如果场景中最重要的平行光开启了阴影,unity就会为该光源计算它的阴影映射纹理(shadowMap)。这张阴影映射纹理本质上也是一张深度图,它记录了从该光源的位置出发、能看到的场景中距离它最近的表面位置。
在计算阴影映射纹理时,unity选择使用一个额外的Pass来专门更新光源的阴影映射纹理,这个Pass就是标签为ShadowCaster的Pass。这个Pass的渲染目标不是帧缓存,而是阴影映射纹理。当光源开启了阴影效果后,渲染引擎首先会在当前渲染物体的Unity Shader中查找标签为ShadowCaster的Pass,如果没有找到,就在Fallback中查找,如果最终仍未找到,那么该物体就无法向其他物体投射阴影。
Unity的阴影映射纹理是通过屏幕空间的阴影映射技术来实现的。unity使用这种技术需要显卡支持MRT。
*屏幕空间的阴影映射技术:当使用这种技术时,Unity会首先通过调用LightMode为shadowCaster的Pass来得到可投射阴影的光源的阴影映射纹理以及摄像机的深度纹理。然后,根据光源的阴影映射纹理和摄像机的深度纹理来得到屏幕空间的阴影图。如果摄像机的深度图中记录的表面深度大于转换得到阴影映射纹理中的深度值,就说明该表面虽然是可见的,但是却处于该光源的阴影中。通过这样的方式,阴影图就包含了屏幕空间中所有有阴影的区域。如果我们想要一个物体接收来自其他物体的阴影,只需要在Shader中对阴影图进行采样。由于阴影图是屏幕空间下的,因此,我们首先需要把表面坐标从模型空间变换到屏幕空间中,然后使用这个坐标对阴影图进行采样即可。
总结:
一个物体接受来自其他物体的阴影,以及它向其他物体投射阴影是两个过程:
- 如果我们想要一个物体接受来自其他物体的阴影,就必须在shader中对阴影映射纹理进行采样,最后把采样结果和最后的光照结果相乘来得到阴影效果
- 如果我们想要让物体向其他物体投射阴影,就必须把该物体加入光源的阴影映射纹理的计算中,从而让其他的物体能对阴影映射纹理采样时得到该物体的信息,这个过程是通过为该物体执行LightMode为ShadowCaster的Pass来实现的。
让物体投射阴影
修改Mesh Renderer下的Cast Shadows来控制物