一、渲染路径
1、unity支持的渲染路径:前向渲染路径(Forword)、延迟渲染路径(Deferred)、顶点照明渲染路径(Vertex Lit)。
2、可以在项目上设置、也可以在摄相机上设置或者在Shader上设置,在shader上利用LightMode标签实现。
3、Pass的LightMode标签支持的渲染路径设置选项。
标签名 | 描述 |
Always | 不管使用那种渲染路径,该pass总是会被渲染,但不计算任何光照 |
ForwardBase | 用于前向渲染,该Pass会计算环境光、最重要的平行光、逐顶点/SH光源和Lightmaps |
ForwardAdd | 用于前向渲染,该Pass会计算额外的逐像素光源,每个Pass对应一个光源 |
Deferred | 用于延迟渲染,该pass会渲染G缓存(G-buffer) |
ShadowCaster | 把物体的深度信息渲染到阴影映射纹理(shadowmap)或一张深度纹理中 |
PrepassBase | 用于遗留的延迟渲染,该pass会渲染法线和高光反射的指数部分 |
PrepassFinal | 用于遗留的延迟渲染,该pass通过合并纹理、光照和自发光来渲染得到最后的颜色 |
Vertex、VertexMRGBM和VertexLM | 用于遗留的顶点照明渲染 |
注意:在渲染设置的时候,我们除了设置Pass的标签外,还要正确使用#pragma multi_compile_fwdbase这样的编译指令。实验表明只有分别为Bass Pass和Additional Pass设置#pragma multi_compile_fwdbase和#pragma multi_compile_fwdadd编译指令,我们才可以在相关的Pass中得到正确的光照变量,例如光照衰减值等。
4、前向渲染路径
①原理:每进行一次完整的前向渲染,我们需要渲染该对象的渲染图元,并计算两个缓冲区的信息:一个是颜色缓冲区,一个是深度缓冲区,我们利用深度缓冲来决定一个片元是否可见,如果可见就更新颜色缓冲区中的颜色值。
②Unity中前向渲染路径有3种处理光照的方式:逐顶点处理、逐像素处理、球谐函数处理。一个光源使用哪种处理模式取决于它的类型和渲染模式。
③Unity会根据场景中各个光源的设置以及这些光源对物体的影响程度对这些光源进行一个重要度排序。规则如下:
Ⅰ、场景中最亮的平行光总是按逐像素处理的
Ⅱ、渲染模式被设置为Not Important的光源,会按逐顶点或者SH处理
Ⅲ、渲染模式设置为Important的光源,会按逐像素处理
Ⅳ、如果根据以上规则得到的逐像素光源数量小于Quality Setting中的逐像素光源数量(Pixel Light Count),会有更多的光源以逐像素的方式进行渲染。
④Unity中前向渲染的两种Pass
5、顶点照明渲染路径
它是对硬件配置要求最少、运算性能最高,但得到效果最差的一种类型,它不支持逐像素才能得到的效果,它仅仅是前向渲染路径的一个子集。
6、延迟渲染路径
①原理:延迟渲染主要包含两个Pass,在第一个Pass中,我们不进行任何光照计算,仅是计算那些片元可见的,这主要通过深度缓冲技术实现,当我们发现一个片元是可见的,我们就把它的信息存储到G缓冲区中。然后,在第二个Pass中,我们利用G缓冲区的各个片元信息,进行真正的光照计算。
②缺点
不支持真正的抗锯齿(anti-aliasing)功能
不能处理半透明物体
对显卡有一定要求
7、三个渲染路径更详细记录请看链接:shader四大解释
二、光源类型
1、unity一共支持四种光源类型:平行光、点光源、聚光灯和面光灯。并且在在Shader中常用的光源属性有光源的位置、方向、颜色、强度以及衰减。
三、unity的阴影
1、在实时渲染中,最常用的一种名为Shadow Map的技术,这种技术它会首先把摄像机的位置放在于光源重合的位置上,那么场景中该光源的阴影区域就是那些摄像机看不到的地方,而unity就是使用的这种技术。
2、阴影实现流程
Ⅰ、让物体接收阴影
简单总结一下物体接收来自其他物体的阴影,以及它向其他物体投射阴影是两个过程。
①如果我们想要一个物体接收来自其他物体的阴影,就必须在Shader中对阴影映射纹理(包括屏幕空间的阴影图)进行采样,把采样结果和最后的光照结果相乘来产生阴影效果。
②如果我们想要一个物体向其他物体投射阴影,就必须把该物体加入到光源的阴影映射纹理的计算中,从而让其他物体在对阴影映射纹理采样时可以得到该物体的相关信息。在Unity中,这个过程是通过为该物体执行LightMode为ShadowCaster的Pass来实现的,如果使用了屏幕空间的投影映射技术,Unity还会使用这个Pass产生一张摄像机的深度纹理。
③让物体接收阴影:在前向渲染中,宏SHADOW_COORDS就是声明了一个名为_ShadowCoord的阴影纹理坐标变量。而TRANSFER_SHDOW的实现会根据平台不同而有所差异。如果当前平台可以使用屏幕空间的阴影映射技术,TRANSFER_SHADOW会调用内置的ComputeScreenPos函数计算_ShadowCoord;如果该平台不支持屏幕空间的阴影映射技术,就会使用传统的阴影映射技术,TRANSFER_SHADOW会把顶点坐标从模型空间变换到光源空间后存储到_ShadowCoord中。然后SHADOW_ATTENUATION负责使用_ShadowCoord对相关的纹理进行采样,得到阴影信息。
注意,当关闭了阴影后,SHADOW_COORDS和TRANSFER_SHDOW实际没有任何作用,而SHADOW_ATTENUATION会直接等同于数值1。
Ⅱ、让物体投射阴影(对于非透明物体),我们把Fallback设为VertexLit就可以得到正确的阴影。
对于使用透明物体我们要小心设置物体的Fallback也可以得到算是理想的效果,
对于使用透明度测试实现透明的物体,Fallback设置为Transparent/Cutout/VertexLit实现透明度阴影
对于透明度混合来讲,在unity中,所有内置的半透明Shader是不会产生任何阴影效果的,但是可以将Fallback设置为不透明物体使用的VertexLit,Diffuse。这样unity就会在它的Fallback中找到一个阴影投射Pass,但此时阴影不会穿透半透明物体。
3、统一管理关照衰减和阴影
UNITY_LIGHT_ATTENUATION是unity内置的用于计算关照衰减和阴影的宏,我们可以在内置的AutoLight.cginc里找到它的相关声明。它接收3个参数,它会将光照衰减和阴影值相乘后的结果存储到第一个参数中。第二个参数是结构体v2f,这个是传递给SHADOW_ATTENUATION,用来计算阴影值。第三个参数是世界空间的坐标,这个参数会用于计算光源空间下的坐标,再对光照衰减纹理采样来得到光照衰减。
在AutoLight.cginc中UNITY_LIGHT_ATTENUATION声明的时候,Unity针对不同的光源类型、是否启用cookie等不同情况声明了多个版本的UNITY_LIGHT_ATTENUATION。
4、透明物体阴影