渲染路径我理解就是一种渲染模式吧。因为现实的光照是很复杂的,计算机或说图形引擎,只是用一种近似的方式来模拟,以便用更少的性能来获得更好的效果。所以就会有各种模式、各种模型。
Unity默认就是前向渲染路径。结合官网文档和unity shader入门精要,总结下认识。
光源处理类型分配
- Lights that have their Render Mode set to Not Important are always per-vertex or SH.
- Brightest directional light is always per-pixel.
- Lights that have their Render Mode set to Important are always per-pixel.
- If the above results in less lights than current Pixel Light Count Quality Setting, then more lights are rendered per-pixel, in order of decreasing brightness.
首先是这一段,在场景里有多个光源的时候,对光源的处理进行分类,决定使用哪一种处理模式:逐像素(per-pixel)、逐顶点(per-vertex)还是Spherical Harmonics (SH)。这3种效果依次递减。
最亮的平行光基本是逐像素
-
然后光源本身可以设置render mode,如果设置成Not Important,基本就是逐顶点或SH模式;而设置成Important,则基本是逐像素。我想这个属性就是为了我们能进行人为调控吧。
在QualitySettings(Edit->Project Settings->Quality->Pixel Light Count)里设置了逐像素的光源个数,默认是4个。这时,如果你根据上面的原则来逐像素光源个数不够,就会补位。
推测:补位是根据光源对当前物体的影响来判断的,比较近光照强的补位。最后,逐顶点光源个数是4个。
shader的pass类型
前向渲染路径有定义两种pass:base pass和additional pass。
- base pass一般就定义一个,它会被一个逐像素的平行光和逐顶点/SH方式的其他光源使用。
在base pass 内可以使用环境光、自发光这些,而且默认平行光可以使用阴影。
- 而其他的逐像素光源会使用additional pass,而且每个光源执行一次,所以它是会被多次执行的。
测试
用到的shader和图片资源打包放在github这个库
为了验证上面的规则以及不同处理类型的区别,做一些测试
单个点光源
当把QualitySettings里逐像素光源个数设为0后,点光源的
auto
就被分配成了not important
。因为auto和not imprtant的效果是一样的。然后对比important和not important下的效果区别,看图:
点光源是放在一个房间的拐角里,可以很明显的看出两者的区别。
首先important情况下的效果符合点光源的性质,就是中间亮,然后向边缘衰减的圈圈样子。
而not important下效果出现突变,注意看里侧的那一边,左下半边整个亮而右上半边整个不亮。我猜测是跟颜色插值有关,设置成not important情况下,是逐顶点的计算光效,可能是计算了面的4个角的光照,然后插值计算内部,而这样做会导致光效突变,因为左上角是暗的。
这个测试我想重点是明显的看出逐顶点和逐像素的光照处理的区别
- 然后换个角度看对3个胶囊的对比:
现象总结:左边的两种情况都不亮,中间的在important时亮,右边的两种情况都亮。
分析:
3个胶囊分别使用资源包里VertexDiffuse、MultiLight和default02的材质。
首先左边的胶囊只计算了forwardBase的逐顶点光照,中间的同时计算了forwardBase和ForwardAdd的光照,右边的是使用了表面着色器,unity shader生成的代码处理了光照,相当于使用系统默认处理。
根据上面的规则,not important时是逐顶点的,所以会执行ForwardBase
的pass,然后左边胶囊应该有光照,实际没有。不知为啥_LightColor0是空的,所以光没了。中间的和左边的情况一样,因为中间只是多出了一个ForwardAdd
Pass,但这时它不起作用。右边成功的计算出了光照,说明依靠_LightColor0是不可行的。这个问题后面再探索,这里主要是验证前向渲染路径里的规则。
important时,点光源是逐像素的,而ForwardBase
是给逐像素的平行光的,这时点光源使用ForwardAdd
Pass。所以中间的胶囊亮了,而左边没亮,而右侧的光会稍强一些,因为双通道的光照叠加,截图里看不太出来,unity可以明显观察到。
到这,现象和规则基本是匹配的。最后,再次验证下important时是走ForwardAdd
Pass。在中间的shader上,给ForwardAdd
通道的光照加了一个比例:
return fixed4(finalColor * _AddRate, 1);
finalColor已经是最终颜色了,只是使用_AddRate来做测试,当它值为0时,中间的胶囊彻底不亮。说明这时就只有ForwardAdd
Pass。
当QualitySettings有空余的逐像素光照时,是按什么原则补位的?
按正常逻辑,肯定影响力越大的光照越有可能,跟物体的距离就是很重要的标准,看官网的示例也是。所以下面就测试一下。
准备条件:
- 把QualitySettings里的逐像素光照设为1
- 在场景里放两个点光源,一样的光照强度。然后一个靠近底部的平板,一个靠近顶部的平板。
在两个光源都是Auto的时候,会发现他们都呈现出点光源的性质,可是QualitySettings为1,按理说应该只有一个是逐像素光照,也就是只有一个能表现出点光源的性质(上面已经知道点光源逐顶点的时候,对平面会出现突变)。
因为对于不同的物体来说,逐像素的光源是会变化的
也就是对于顶部面板而言,上面的点光源是逐像素的,而对下面的面板而言,就是下面光源了,所以当两者都是Auto
模式时,Unity就按照距离自动分配了。这是不是很符合现实的样子?
然后把下面的光源设为important
,它就会总是逐像素,会抢夺顶部光源对顶部面板的逐像素位置,所以第二张图里,顶部的光照相比下降了。
所以相反的,把底部设置成not important
,就会让它永远是逐顶点的,它的光照不亮了,和截图的是对应的,只有顶部是亮的了。