Shader笔记——8.光照和阴影

Unity中的光照与阴影

光照

渲染路径

实际开发中的游戏场景往往不止一个光源,而渲染路径Render Path就是决定了光照是如何被应用到Shader中的,所以在与多个光源打交道时需要为每个Pass指定它使用的渲染路径,只有为Pass设定了正确的渲染路径,Shader的光照计算才会被正确执行,如果没有在Pass中设置正确的渲染路径,则会被当做默认的顶点照明渲染路径,造成一些光照变量不能被正确赋值且计算出错误的光照效果。

Unity支持多种渲染路径,主要包括,前向渲染路径Forward Rendering Path延迟渲染路径Deferred Rendering Path顶点照明渲染路径Vertex Lit Rendering Path

前向渲染路径

  • 原理:一个Base Pass(也可以有多个Base Pass,例如双面渲染效果)一个Additional Pass,一个Base Pass仅执行一次(有多个Base Pass则执行多个Base Pass)渲染对象图元,通过深度缓冲Depth Buffer / Z-Buffer判断对象图元的每个片元是否可见,如果可见就进行光照计算并更新颜色缓冲区的颜色值;一个Additional Pass会根据影响该物体的其他逐像素光源的数目进行多次调用,即每有一个逐像素光源就执行一此Additional Pass渲染,并且该Pass开启混合模式Blend One One使每个Additional Pass结算结果可以与上一次光照结果进行叠加。

  • 优缺点:每个对象对于影响它的每个光源都以通道Pass形式呈现,所以每个对象可能会执行多个Pass,执行次数次数取决于该对象所在范围内有多少个光源,这种方法的优点是非常快,硬件要求低于延迟渲染,并且提供了可定制的阴影模型,可以快速处理透明度。缺点是需要为每个光源付出渲染成本,即影响对象的光源越多,渲染性能越慢。如果可以在游戏中管理灯光的数量,则向前渲染是一个非常快速的解决方案。

  • Unity中的前向渲染路径:unity的前向渲染路径中有三种处理光源的方式:逐像素处理、逐顶点处理、球谐函数SH处理,具体规则:场景中影响物体的最亮的几个光源使用逐像素光照模式。其次,最多有4个点光源会以逐顶点渲染的方式被计算。剩余其他光源将以球谐函数SH方式进行计算,球谐函数SH计算很快但只能得到近似值。可以在光源Light组件下的Render Mode选项进行更改设置为Important或者Not important。

延迟渲染路径

延迟渲染是一种更古老的渲染方法,因为前向渲染的性能瓶颈问题,所以又被重视,除了前向渲染使用的深度和颜色缓冲区之外,还使用了额外的缓冲区G-Buffer缓冲,G缓冲区储存了我们所关心表面的其他信息

  • 原理:两个Pass,第一个Pass不进行光照计算,仅通过深度缓冲区计算哪些片元是可见,将可见片元的相关信息储存在G缓冲区G-Buffer;然后第二个Pass,利用G缓冲区储存的各个片元信息(表面法线、视角方向、漫反射系数、材质属性等)进行真正的光照计算。

  • 优缺点:延迟渲染路径使用的Pass通常只有两个,其渲染的效率不依赖于场景的复杂度,适合在场景光源数目较多,在使用前向渲染时会引发渲染性能瓶颈时使用,并且延迟渲染路径中的每个光源都可以按照逐像素的方式处理,缺点是,不能够支持真正的抗锯齿anti-aliasing功能、不能够处理透明物体并且对显卡有一定要求

  • Unity中的延迟渲染路径:在Unity中使用延迟渲染路径,要求我们提供两个Pass,第一个用于把物体的漫反射颜色、高光反射颜色、平滑度、法线、自发光、深度缓存等信息渲染到屏幕空间的G缓冲区,对于每个物体这个Pass仅会执行一次;第二个Pass,用于计算真正的光照模型,这个Pass会使用上一个Pass中渲染的数据来计算最终的颜色并存储到帧缓冲区中

顶点照明渲染路径

  • 原理:实际上只使用了逐顶点的方式计算了光照,所以并不支持那些需要进行逐像素处理才能得到的效果,例如阴影、法线映射、高精度高光反射等

  • 优缺点:对硬件配置的需求最少、运算性能最高,但是得到的渲染效果较差

  • Unity中的顶点照明路径:unity的顶点照明渲染路径通常在一个Pass中就可以完成对物体的渲染,在这个Pass中会通过逐顶点处理计算出所有光源对该物体的照明,所以这个渲染路径计算快速兵器支持广泛

大多数情况下,一个项目只是用一种渲染路径,可以在Unity Player Setting中设置Rendering Path,也可以在Camera的Camera组件下设置该Camera特有的Rendering Path来覆盖掉Project Setting中的渲染路径设置

阴影

物体投射阴影

光源的阴影映射纹理

实时渲染常使用Shadow Map技术来渲染阴影,即将摄像机放在光源位置上,摄像机看不到的地方就是该光源的阴影区域

光源开启了阴影效果光源影响下的物体开启了投射阴影Caster Shadows属性,Unity引擎就会把该物体加入到光源的阴影映射纹理的计算中,从而让其他需要接受阴影的物体在对光源的阴影映射纹理进行采样时可以获得该物体的信息,Unity将物体加入到光源的阴影映射纹理这一步骤就是通过物体的Shader中LightMode设置为ShadowCaster的Pass来实现的,如果没有找到则该物体无法向其他物体投射阴影,找到的话则使用该Pass来更新光源的阴影映射纹理

传统阴影映射技术

把顶点位置变换到光源空间下得到光源空间下顶点的位置信息,然后对光源的阴影映射纹理xy分量进行采样,得到阴影映射纹理中该位置的深度信息,如果该深度值小于该顶点的深度值(DNC的Z分量),则说明该点位于阴影中

屏幕空间的阴影映射技术

当使用屏幕空间的阴影映射技术时,unity首先会通过调用LightMode为ShadowCaster的Pass,来得到摄像机的深度纹理光源的阴影映射纹理,然后根据这两项来得到屏幕空间的阴影图。得到的阴影图就包含了屏幕空间所有的阴影区域,此时,如果一个物体要接受来自其他物体的阴影,只需要在Shader中对阴影图进行采样即可

屏幕空间的阴影映射技术Screen Space Shadow Map,原本是延迟渲染路径中产生阴影的方法,因为这种方法需要显卡支持MRT,所以有些移动平台不支持这种特性

物体接受阴影

如果想要一个物体接受来自其他物体的阴影,就必须在该物体的Shader中对光源的阴影映射纹理进行采样,把采样结果和光照计算的结果相乘产生接收阴影效果

REF

文档:

https://docs.unity3d.com/Manual/class-RenderTexture.html

书籍:

OpenGL宝典、Unity Shader入门

原文地址:https://www.cnblogs.com/sylvan/p/13621329.html