本系列主要参考一书(感谢原书莋者)同时会加上一点个人理解或拓展。
是本书所有的插图是本书所需的代码和资源(当然你也可以从下载)。
之前学习的各种Shader时峩们从没有考虑在所有平台下的可用性。Unity是一个强大的跨平台游戏引擎但这也决定了在编写代码时我们需要考虑更多的平台因素。对于Shader洏言如果没有进行相应的优化,很有可能无法运行在移动平台等对性能限制较高的平台上我们需要理解一些关键的因素来优化我们的Shader,以提高游戏性能而又能尽可能保持取得同样的视觉效果
尤其是如果你的目标平台包括Android系统,那么就一定要小心中国各种山寨机的大浪┅下把你拍在沙滩上的后果。所以,如果你从来没有为你的Shader考虑过这些情况那么,且用且小心吧。
这一章中,我们会学习三节內容:什么是一个高效的Shader怎样对Shader进行性能分析,为移动平台优化我们的Shader
那么,什么是一个高效的Shader呢这是个有点复杂的问题,它涉及箌了很多因素例如,和你使用的变量个数及其所占内存Shader使用的纹理个数有关等等。还有可能你的Shade虽然工作良好,但我们实际商可以使用一半数目的变量就可以取得相同的效果我们将在本节中发掘这样的一些技巧,并向你说明它们是如何组合起来让我们的Shader更快更高效嘚而又可以各种平台上取得同样高质量的视觉效果。
-
创建一个新的场景和一个球体添加一个平行光。
-
最后使用下列代码修改Shader。
简单嘚光照函数里面进行了简单的漫反射处理surf函数里则改变了模型的法线。
最后你得到的效果大概是这样的:
下面,我们来一步步优化这個Shader
首先,我们需要优化变量类型以便它们尽可能少地占用内存:
-
修改Input结构。之前我们的UV坐标都是存储在了float2类型的变量中,现在我们將它们改为half2:
-
接下来是光照函数同样,将其中float家族的变量改成对应的fixed类型变量:
-
最后修改surf函数中的变量类型。同样使用fixed类型变量:
在修改了变量类型后我们现在来利用Unity内置的光照函数变量,以便我们可以控制Shader是如何处理光源的为此,我们可以很大程度上减少Shader处理的咣源个数修改#pragma声明:
};最后,我们告诉Unity这个
Shader只工作在特定的渲染器上:
最后优化前后效果如下(左前右后):
可以看出,我们肉眼几乎看不出任何差别但是我们已经减少了这个Shader被绘制到屏幕上所花费的时间。我们将在下一节中利用Unity的可视化工具来分析这种减少程度的大尛但在这里,我们关注的是使用了更少的数据来得到相同的渲染效果。在创建我们自己的Shader的时候也要一直记住这个思想!
上面一共提到了4种优化方式:优化变量类型,共享UV坐标减少处理的光源个数,让Shader只工作在特定的渲染器上下面,我们来更深入地理解这些技术昰如何工作的最后再学习其他一些技巧。
首先我们来看一下在我们声明变量时每个变量存储的数据大小。由于在声明变量时我们往往有多个选择(float,halffixed),我们需要来看一下这些类型的特点:
-
float:高精度浮点值通常是32位,也是三者中最慢的一个它对应的还有float2,float3和float4
-
half:中精度浮点值。通常是16位范围是-60000至+60000,它适合存储UV坐标颜色值等,比float类型快很多它对应的还有half2,half3和half4。
-
fixed:低精度浮点值通常是11位,范围是-2.0至+2.0精度为1/256。这是三者中最小的一个可以用于光照计算、颜色等。它对应的值有fixed2fixed3和fixed4。
-
尽可能使用低精度变量
-
对于颜色值和單位长度的向量,使用fixed
-
对于其他类型,如果范围和精度合适的话使用half;其他情况使用float。
从上可以看出这一步优化是通过在#pragma语句中声奣noforwardadd值来实现的。这主要是告诉Unity使用这种Shader的对象,只接受一个单一的平行光光源作为逐像素光源其他的光源都使用内置的球谐函数处理後作为逐顶点的光源。当我们在场景中放置了另一个光源时这种策略会很明显,因为我们的Shader使用一个法线贴图进行逐像素的操作
这样莋当然很好,但是如果我们需要不止一个平行光而且想要控制哪一个是用于该逐像素计算的主光源,又该怎么办呢这就需要Unity面板中的┅个设置啦!如果你仔细观察,就会法线每一个光源都有一个Render Mode下拉菜单当你点击它时,会出现Auto, Important,
和Not Important三种选项通过选择Important,你可以告诉Unity这个咣源更需要被当成一个逐像素光源而非一个逐顶点光源。如果设置为Auto那么就由Unity自己做决定啦!
懵了是不是。。为了说明上述意思峩们来做个试验!在场景里放置另一个点光源,然后移除Shader中的Main Texture第一次,打开平行光关闭点光源(左图);第二次关闭平行光,打开点咣源(右图)你可以发现第二个点光源并不会影响我们的法线贴图(只是照亮了模型,也就是它只是逐顶点处理)只有第一个平行光財会影响。
这里的优化是由于我们把其他所有光源当成了顶点光源,而在计算像素颜色时只计算一个主平行光作为像素光源
这步优化佷简单,仅仅使用了Main Texture的UV坐标来代替法线贴图的UV坐标这样实际上减少了内部提取法线贴图UV坐标的代码。这种方法可以很好地简化我们的代碼
最后,我们在语句中声明了以便告诉Unity,这个Shader不会再接受来自延迟渲染中的其他任何自定义的光照这意味着,我们仅可以在正向渲染(forward render)中有效地使用这个Shader这是在主摄像机的设置中设置的。
其他的优化策略还有很多我们之前学过如何把多个灰度图打包到一个RGBA贴图Φ,以及如何使用一张贴图来模拟光照效果由于这些众多的技术,因此问如何优化Shader是一个很模糊的问题但是,了解这些技术使得我们鈳以根据不同的Shader和平台采用合适的技术来得到一个具有稳定帧率的Shader。