之前已在简书上发过,这里重新整理了一下,并附上实现代码。
在unity中实现阴影的文章网上看了不少,包括常用的shadowMap,或直接投射Rendertexture等。比如unity中实现shadowmap,可以通过投射灯光空间的深度图,并在投射物体上进行深度比较,判断是否处于阴影的范围,以此来渲染阴影。将深度图投射到接受阴影的物体上的效果如图所示:
你所需要做的就是在灯光空间渲染一张深度纹理,并投射到接受阴影的物体上,并和接受阴影的物体上对应像素位置的深度(灯光空间)进行比较,来确定当前像素是否处于阴影即可,此外还要考虑深度图的精度以及以此会造成的ZFighting等,当然这并不是本文讨论的重点。
这边我主要介绍一种直接投射灯光空间摄像机的Rendertexture来实现阴影的方法,并将在稍后将其和projector结合。当然同时熟悉这两项技术的开发者应该已经清楚,使用projector实现阴影意味着你将会消耗额外的drawcall,实际上被投射projector并且未在shader中使用"IgnoreProjector"="true"的物体都会在自身shader渲染完(也可能是渲染前,具体看自身渲染队列和projector的shader的渲染队列的先后顺序)后再次使用projector的shader渲染一次,这表示当被projector投射且未标记忽略投影机或不处于投影机忽略的层的物体会再次使用projector的material渲染,所以如果将projector应用在某些场景,比如拥有复杂的场景元素,且大部分是单独的物体而不是合并的,会占用较多drawcall,当然如果projector只影响一小部分元素,比如projector只影响单独模型的地面,则可以不必担心drawcall的问题。
首先比较一下这种技术和shadowmap技术,实际上个人感觉很大程度上两者的技术其实差不多,都需要用到屏幕投影,只不过shadowmap投射的是深度图(深度缓冲),而本文介绍的是直接投射屏幕纹理(帧缓冲),因此投射的纹理是带Alpha通道的。
和shadowmap不同的是,灯光空间的摄像机应该只看到投射阴影的物体:
此时投射后的效果大致如图所示: