Unity Shader前向渲染

前言:渲染路径的存在是帮助我们来处理更多数量和更多类型的光照。

一、前向渲染中的原理

前向渲染是通过深度缓冲和颜色缓冲来实现的,使用深度缓冲来决定一个片元是否可见,如果可见,则更新颜色缓冲区中的颜色值。如果场景中有n个物体受m个光源的影响,那么要渲染整个场景,则需要n*m个pass,如果m较多的话,这个开销还是比较大的。

二、unity中的前向渲染

unity中对光照的处理方式有三种分类:逐顶点(最多有四个光源类型可以用逐顶点),逐像素,球谐函数(SH)。决定光照的处理方式有很多因素,每个光照只能按照一种处理方式来处理,下面会一一介绍。

首先每个unity光照都有一个属性叫做render mode,一共有三个选项,important,auto, not important;

如果一个光照被声明为important,它就是逐像素处理的,如果被声明为not important,它就是逐顶点处理或球谐处理,如果被声明为Auto,则要根据unity的quality setting中设置的pixel light count来决定。具体解释一下,如果一个光照被声明为important,那么它如果不是最重要的平行光,它就是逐像素处理的,它就需要使用forwardadd的pass,(forwardadd下面会介绍),如果它被声明为not important,而且它是点光源,就使用顶点处理的方式,前提是点光源的数量要不大于四个,如果超过四个了,或者是其它类型的光源,就要使用SH方式。在Auto类别中的,要根据pixel light count,如果pixed light count为5,但是important类型的光源不够(最重要的平行光不计算在内),那么就要从auto中取,其中平行光>其它光源(点光源应该是放在最后的,但我也不确定这一点),如果auto还不够,就算了,不能从not important中取。就是通过以上这种逻辑来确定一个光源的处理方式。

首先要明白一点,这些处理方式的计算并不是来计算光照模型,而是来计算填充unity提供的一些内置变量,至于我们作为开发者如何使用这些变量,就是完全自由的,我们可以使用一个逐像素的光照在一个pass里写一个逐顶点光照模型的计算程序。

前向渲染有两种,一个forwardbase,用来计算环境光、最重要的平行光、逐顶点和球谐函数以及光照贴图。被声明为forwardbase渲染路径的pass在一个物体的渲染中只能被执行一次,由于环境光只需要执行一次计算,所以要放在该pass中,最重要的平行光一般是指强度最大的平行光,逐顶点的计算通常需要使用到相关的内置变量做计算,如果一个光照是按照逐顶点光照来处理,它就会把该光照的信息计算之后填充到相应内置变量里,但是如果在forwardbase的pass里没有进行处理计算,那么也是看不到任何效果的。

float4 lightPos1 = float4(unity_4LightPosX0[0], unity_4LightPosY0[0], unity_4LightPosZ0[0],1);
fixed3 lightDir1 = normalize(lightPos1-i.worldPos).xyz;
fixed3 diff1 = unity_LightColor[0]*albedo*max(0,dot(lightDir1,worldNormal));

一个forwardadd是用来计算逐像素光照的,该类型的pass可以被重复执行。

注意事项:

A. 预编译指令,#pragma multi_compile_fwdbase,#pragma multi_compile_fwdadd,#pragma multi_compile_fwdadd_fullshadows;它能够帮助我们得到正确的内置变量。

B. base pass中渲染的平行光默认是支持阴影的,而add pass默认是不支持的,所有需要使用#pragma multi_compile_fwdadd_fullshadows代替原有预编译指令,可以为点光源和聚光灯开启阴影效果。

C. add base中的渲染设置中添加了blend命令,因为add pass需要和帧缓存中数据进行叠加,如果没有开启混合,那么就会直接覆盖掉之前的结果,显然是不对的。

D. 对于前向渲染来所,一个unityshader通常会定义一个Base Pas(也可以定义多次,例如双面渲染就需要两次等)以及一个add pass,一个base pass仅会执行一次,而一个add pass会执行多次。

E. 用同一个add pass在处理不同的光源类型时,可以通过使用宏来做出判断,比如计算光的方向,

#ifdef USING_DIRECTIONAL_LIGHT
    fixed3 worldLightDir=normalize(_WorldSpaceLightPos0.xyz);
#else
    fixed3 worldLightDir=normalize(_WorldSpaceLightPos0.xyz-i.worldPos.xyz);
#endif

三、内置的光照变量和函数


本文转自:CSDN - 莫之,转载此文目的在于传递更多信息,版权归原作者所有。

最新文章