unity 阴影

初步了解unity 阴影

为了让场景看起来更加真实,具有深度信息,我们通常希望光源可以吧一些物体的阴影投射在其他物体上。

我们可以先考虑真实生活中阴影是如何产生的。当一个光源发射的一条光线遇到一个不明物体时,这条光线就不可以再继续照亮其他物体。因此,这个物体就会向它旁边的物体投射阴影,那些阴影的区域产生是因为光线无法到达这些区域。

在实时渲染中,我们最常使用的一种技术名为shadow map的技术。这种技术很简单,它会首先把摄像机位置放在与光源重合的位置上,那么场景中该光源的阴影区域就是摄像机看不到的地方。而unity就是使用这种技术。

在前向渲染(Base Pass【ForwardBase】和Additional Pass【ForwardAdd】)路径中,如果场景中最重要的平行光开启了阴影,unity就会为该光源计算它的阴影映射纹理,这张阴影映射纹理本质上也是一张深度图,他记录了从该光源的位置出发。能看到的场景中距离它最近的表面位置(深度信息)。

那么,在计算阴影映射纹理时,我们如何判断距离它最近的表面位置呢?一种方法是,先把摄像机放置到光源的位置上,然后按正常的渲染流程,即调用Base Pass和Additional Pass 来更新深度信息,得到阴影的映射纹理,但这种方法会对性能造成一定的浪费,因为我们实际上仅仅需要深度信息而已,而Base Pass和Additional Pass中往往涉及很多复杂的光照模型计算。因此unity选择使用一种额外的Pass来专门更新光源的阴影映射纹理,这个Pass就是LightMode标签被设置为ShadowCaster的Pass。这个Pass的渲染目标不是帧缓存,二十几阴影映射纹理(或深度纹理),unity首先把摄像机放置到光源的位置上,然后调用改Pass块,通过对定点变换后得到光源空间下的位置,并据此来输出深度信息到阴影映射纹理中。因此,当开了光源的阴影效果后,底层渲染引擎首先会在当前渲染物体的unity shader中找到LightMode为shadowCaster的pass,如果没有,它就会在Fallback指定的unityshader中继续寻找如果仍然没有找到,该物体就无法向其他物体投射阴影(但他仍然可以接受来自其他物体的阴影)。当找到了一个LightMode为ShadowCaster的Pass后,unity会使用该Pass来更新光源的阴影映射纹理。

在传统的阴影映射的视线中,我们会在正常渲染的Pass中把顶点位置变换到光源空间下,方便得到它在光源空间中的三维信息。然后我们使用xy分量对阴影纹理进行采样,得到阴影映射纹理中该位置的深度信息。如果该深度值小于该顶点的深度值(通常由z分量得到),说明该点在阴影中。但在unity5中,unity使用了不同于这种传统的阴影采样技术,即屏幕空间阴影映射技术,屏幕空间的阴影映射原本是延迟渲染中产生的阴影的方法,需要注意的是,并不是所有的平台unity都会使用这种技术,这是因为。屏幕空间的阴影映射需要显卡支持MRT,而有些移动平台不支持。

当使用了屏幕空间的阴影映射技术,unity首先会通过调用LightMode为shadowCaster的Pass来得到可投射阴影光源的阴影映射纹理以及摄像机的深度纹理。然后根据光源的阴影映射纹理和摄像机的深度纹理来得到屏幕空间的阴影图。如果摄像机的深度图中记录的表面深度大于转换到阴影映射纹理中的深度值,就说明该表面是可见的。但是却处于该光源的阴影中。通过这样的方式阴影图就包含了所有的阴影区域。如果我们想要一个物体接受来自其他物体的阴影,只需要在shader中对阴影图进行采样。由于阴影图是屏幕空间下的,因此我们首先需要把表面坐标从模型转换到屏幕空间中,然后使用这个坐标对阴影图进行采样即可。

总结:

1.如果我想要这个物体接受来自其他物体的阴影,就必须在shader中对阴影映射纹理(包括屏幕空间的阴影图)进行采样.把采样结果和最后的光照效果相乘来得到阴影效果.

2.如果我们想要一个物体向其他物体投射阴影,就必须把该物体加入到光源的阴影映射纹理的计算中,从而让其他物体在对阴影映射纹理采样时可以得到该物体的相关信息。在unity中,这个过程是通过为该物体执行LightMode为ShadowCaster的Pass块来实现的。吐过使用了屏幕的投影映射技术,unity还会使用中了这个Pass产生一张摄像机的深度图。

不透明物体的阴影

1.让物体投射阴影

在unity中我们可以选择是否让一个物体投射或者接受阴影,这是通过设置Mesh Render组件中Cast Shadow 和Receive Shadows属性来实现的。Cast Shadow可以设置为开启或者关闭。如果开启了Cast Shadow属性,那么unity 就会把该物体加入到光源的阴影映射纹理的计算中,从而让其他物体在对阴影映射纹理采样时可以得到该物体的相关信息。这个过程通过执行物体的ShadowCaster 的Pass来实现的。Receive Shadows 则可以选择是否让物体接受来自其他物体的阴影。如果没有开启Receive Shadows,那么当我们调用unity的内置宏和变量计算阴影时,这些宏通过判断该物体没有开启接受阴影的功能,就不会再内部为我们计算阴影了。

LightMode为ShadowCaster的Pass实现。这种自定义的Pass可以让我们更加灵活的控制阴影的产生,但是由于这个Pass的功能通常是可以在多个unityshader间通用的因此直接Fallback是一个更加方便的用法。

让物体接受阴影,首先在BasePass包含有进一个新的内置文件#include “AutoLight.cginc”.计算阴影所用的宏都是在这个文件中声明的。在顶点着色器的输出结构体v2f中添加了一个内置宏SHADOW_COORDS这个宏的作用就是声明一个用于对纹理采样的坐标。需要注意的是,这个宏的参数需要时下一个可用的插值寄存器的索引值,在下面的代码设置为4.在定点着色器计算返回之前添加另一个内置宏TRANSFR_SHADOW这个宏用于在定点着色器计算上一步声明的阴影纹理坐标。最后我们在片元着色器中计算阴影之,这样使用一个内置宏SHADOW_ATTENUATION;




猜你喜欢

转载自blog.csdn.net/qq_41179365/article/details/80855665