Unity Shader前向渲染

前言:

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

一、前向渲染中的原理

前向渲染是通过深度缓冲和颜色缓冲来实现的,使用深度缓冲来决定一个片元是否可见,如果可见,则更新颜色缓冲区中的颜色值。如果场景中有n个物体受m个光源的影响,那么要渲染整个场景,则需要n*m个pass,如果m较多的话,这个开销还是比较大的。那么如何在得到理想效果的同时来节省性能呢,unity提供了一些策略来进行处理前向渲染的光照计算问题;

二、unity中的前向渲染

对光源处理方式分类:unity在渲染每一个物体之前都会根据光源自身的设置以及光源对该物体的影响程度对场景中的所有光源进行一个重要度排序,然后根据排序的结果以及quality settings等将会决定这些光源的处理方式;

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,该类型的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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值