對遊戲開發者而言,著色器長久以來就是遊戲開發中的重要部分,在unity中編寫並實現著色器的過程直觀且高效,優秀的著色器還可以創造非常精美的遊戲畫面,同時保證極高的效能。今天將由unity的技術工程師張陳淵來分享如何對unity shader著色器進行優化。
我們在unity中建立shader著色器的時候,會有四個選項:
除了computer shader外,另外三種並沒有本質的區別。而在書寫unity shader時,有一些寫法會影響到執行效率。
[gamma]與[linear]指定,當顏色空間配製為gamma時,對屬性變數指定為[gamma]和[linear]都是無效的,只有當顏色空間配製為linear時,指定才有效。所以當我們我們需要將乙個vector做為顏色使用,在linear顏色空間下,指定其為[linear]是比[gamma]要高效的,因為如果指定為[gamma],unity會在cpu端做一次轉換計算。
[noscaleoffset]可以為我們省掉乙個變數的分配,如果不需要用到紋理tiling和offset,請使用[noscaleoffset]。
屬性裡面還有乙個perrenderdata,如果有乙個物體,我們進行渲染一百次,是同乙個材質,但是我們有時候又需要這一百個物體顯示為不同的顏色,那麼怎麼做?一種方法是頂點色這樣做,但是這種方法不是特別好,我們還有一種方法可能是直接在材質屬性裡面加乙個顏色,然後每個材質設不同的顏色。
如果要為每個材質設不同的顏色,unity會幫助你建立一百個這樣的材質,相當於你渲染一百個物體,每個物體顏色不一樣,所以直接設定的時候,會幫助你建立一百個材質,這對於gpu來講會影響,但是更重要是記憶體方面,會有一百個材質的記憶體開銷,這是乙個最大的瓶頸。所以我們引入了perrenderdata的這麼乙個屬性的控制,它可以幫你把這個資料。例如:color顏色,我們不需要將其畫到材質裡面,而是通過render可以設定。
現在介紹一下tags,tags指定渲染順序,告訴引擎如何以及何時將其渲染。unity提供給我們一些預設的渲染佇列,每乙個對應乙個唯一的值,來指導unity繪製物件到螢幕上。這些內建的渲染佇列被稱為background, geometry, alphatest,這些佇列不是隨便建立的,它們是為了讓我們更容易地編寫shader並處理實時渲染的。
下面是佇列的描述:
我們優化的時候對於不透明的物體不需要從後往前畫,例如:很遠的山或者背景,作為background,前面作為geometry,其實前景應該先畫,然後再畫後景。
有時候unity處理的比較粗糙,更多時候需要大家自己進行控制。半透明必須從後往前畫,這裡沒有太多辦法進行優化。disablebatching建議大家不要開啟,預設的情況是不開啟的。
forcenoshadowcasting,例如:當我們畫不透明的物體,需要替換半透明的物體,但是半透明的物體沒有陰影,你可以更改shader**讓它不投射陰影,直接加上forcenoshadowcasting就可以了。
grabpass,我們需要抓緩衝圖有二種方式,如下圖所示
這二種方式的區別是很明顯的,第一種方式是比較低效的,因為grabpass呼叫的時候必定會進行抓取的操作,所以沒次都是不同的。但是下面比較高效,一幀裡面最多隻執行一次,就是第一次使用會執行,後面不會執行。這個根據大家的實際的應用進行選擇。
render state,以前直接寫圖形程式的時候可能會比較關注怎麼設定渲染狀態,當它有變化的時候我們需要設定,沒有變化時候該怎麼處理?
unity引擎是這樣處理的,它把渲染狀態快取,快取的作用就是為了不要頻繁的切換,因為會判斷當前這個狀態和上一次的狀態是不是相同?如果是相同,不需要呼叫圖形api的介面,因為介面呼叫也有一定的消耗。那麼這裡可以引出乙個優化點,如果渲染狀態頻繁的切換,那麼起不到優化的作用。
所以我們寫shader的時候,盡量不要讓這些連續的,不要有太多的渲染狀態,盡量保證是少的,這樣優化作用是大的。例如:aaa連續和bbb連續畫,這樣的效率高於ab間插的渲染。
alpha testing,大家知道在移動端,這是限於硬體的機能限制,盡量不要開啟,在移動端開啟,它的效能會比較低。
color mask,我們在移動端也盡量不要開啟,這是固定的,大家一定要記住,因現在受於移動端的限制,pc端沒有這個限制。
su***ce shader優化是比較難的,這裡統計了一下我們能夠做什麼?我們基本可以做這些事情。預設情況下su***ce shader其實是開啟了所有的計算,我們需要關閉或者模擬一些計算來達到乙個優化的目的。
其次是halfasview,是使用光照方向和視角方向的中間向量替代乙個視角方向,如果大家對比效果,覺得二種比較下來差不多,就可以選擇優化過的效果。
noforwarddadd,如果只有一盞畫素光,你可以開啟這個選項。
最後是環境光,我們可以關掉乙個環境光,因為關了之後有一些優化的計算,這裡優化強度比較大,但是光照損失也是比較大,如果覺得效果可以接受,就可以關掉它。
變體優化是乙個比較重要的點,因為很多人覺得shader很佔記憶體, 上百兆占用都有可能。小的話20多兆,達到上百兆肯定是不行的,那麼我們需要查原因,到底什麼東西導致我們的shader變得這麼大。
unity提供另外乙個關鍵字shader feature,它只會把使用的編譯到包裡面,而不會把沒有用的編譯裡面。multi_compile則會產生所有的變體。收集變體時需要注意,使用shader feature的方式,我們需要建立材質去進行變體的收集,材質需要序列化到場景中。
最後講講shader的**優化,我個人覺得它可優化的空間不大,空間大的地方在哪兒?我們思考優化這些最後的效果,思考這些資料是不是真的應該去進入了渲染管線?這是重點。進入渲染管線的資料優化之後,我們再做shader優化就是錦上添花的事情。
首先我們cpu的軟體裁減是不是高效且正確?當然我們會使用unity的裁減功能,或者可以自己寫。當有over draw時,渲染順序是不是可以再優化 。例如:遠處的陰影是不是真的需要開啟?解析度可以再小一點嗎,最後乙個全屏特效做的次數,大家講的bloom次數非常多,可不可以減少一些?或者其它的全屏特效可不可以集中一次把它做完。這些事情我們思考之後已經優化了很多效率。
最後我們可能需要針對**去進行優化。那麼**優化我們需要利用一些工具做,英偉達的工具,ios我們會使用xcode,安卓有很多或者高通提供的工具我們都可以使用。
我們在**優化的幾個重點:
Unity Shader 頂點著色器引數
本章主要描述在unity cg語言編寫shader的時候,頂點著色器的引數。一般在shader中都會將頂點著色器的引數封裝為乙個結構體 unity vertex input instance id 結構體中的屬性都是meshrenderer在每次drawcall的時候傳遞過來的,我們在shader中...
UnityShader之固定管線著色器
首先,我們先 看一下unityshader的基本框架。設定 shader 的目錄路徑 shader fixedshader fixed001 子著色器 表示一種渲染方案 subshader subshader subshader 備用著色器 一般用最簡單的 shader fallback diffu...
著色器(Shader)之畫素著色器
畫素著色器實際上就是對每乙個畫素進行光柵化的處理期間,在gpu上運算的一段程式。不同與頂點著色器,畫素著色器不會以軟體的形式來模擬畫素著色器。畫素著色器實質上是取代了固定功能流水線中多重紋理的環節,而且賦予了我們訪問單個畫素以及訪問每乙個畫素紋理座標的能力 多重紋理就是我們同時啟用多層紋理,然後規定...