draw call 理解和優化

draw call是openGL的描繪次數(directX沒怎麼研究,但原理應該差很少)
一個簡單的openGL的繪圖次序是:設置顏色→繪圖方式→頂點座標→繪製→結束。
每幀都會重複以上的步驟。這就是一次draw call

若是有兩個model,那麼須要  
設置顏色→繪圖方式→頂點座標A→繪製→結束。
設置顏色→繪圖方式→頂點座標B→繪製→結束。
兩次draw calls;
也就是說在openGl繪製前,若是色彩通道(color filter),繪圖方式(shader),頂點座標(model)不一樣的狀況下draw calls就會增長。

對openGl來講繪製參數(狀態值)的變動要比繪製大量的頂點更耗費cpu。

所謂高速繪圖就是,在儘可能不改變openGl狀態值的狀況下,用一次draw call完成全部繪製。
好比上面的例子:
設置顏色→繪圖方式→頂點座標A+頂點座標B→繪製→結束。
就要更加有效率。

我的估計unity3d的dynamic batch,static batch都是經過必定的方法使不一樣的object的頂點座標可以結合成一個總體,達到減小draw calls的效果。
可是有必定的要求限制,好比material要相同,mesh要相同並在300個面之內等等,這些都是爲了保證openGl的狀態值不改變。html

 

Unity在 Player Setting 裏的兩個功能選項 Static Batching 與 Dynamic Batching。功能描述以下:算法

  1. Static Batching 是將標明爲 Static 的靜態物件,若是在使用相同材質球的條件下,Unity 會自動幫你把這兩個物件合併成一個 Batch,送往 GPU 來處理。這功能對效能上很是的有幫助,因此是須要付費纔有的。
  2. Dynamic Batching 是在物件小於300面的條件下(不論物件是否爲靜態或動態),在使用相同材質球下,Unity就會自動幫你合合併成一個 Batch 送往 GPU 來處理。

 

Unity3D項目優化--繪製調用批處理unity3D Draw緩存

在屏幕上渲染物體,引擎須要發出一個繪製調用來訪問圖形API(iOS系統中爲OpenGL ES)。每一個繪製調用須要進行大量的工做來訪問圖形API,從而致使了CPU方面顯著的性能開銷。性能優化



Unity在運行時能夠將一些物體進行合併,從而用一個繪製調用來渲染他們。這一操做,咱們稱之爲「批處理」。通常來講,Unity批處理的物體越多,你就會獲得越好的渲染性能。iphone



Unity中內建的批處理機制所達到的效果要明顯強於使用幾何建模工具(或使用Standard Assets包中的CombineChildren腳本)的批處理效果。這是由於,Unity引擎的批處理操做是在物體的可視裁剪操做以後進行的。Unity先對每一個物體進行裁剪,而後再進行批處理,這樣可使渲染的幾何總量在批處理先後保持不變。可是,使用幾何建模工具來拼合物體,會妨礙引擎對其進行有效的裁剪操做,從而致使引擎須要渲染更多的幾何面片。編輯器



材質函數

 

只有擁有相同材質的物體才能夠進行批處理。所以,若是你想要獲得良好的批處理效果,你須要在程序中儘量地複用材質和物體。工具



若是你的兩個材質僅僅是紋理不一樣,那麼你能夠經過 紋理拼合 操做來將這兩張紋理拼合成一張大的紋理。一旦紋理拼合在一塊兒,你就可使用這個單一材質來替代以前的兩個材質了。post



若是你須要經過腳原本訪問複用材質屬性,那麼值得注意的是改變Renderer.material將會形成一份材質的拷貝。所以,你應該使用Renderer.sharedMaterial來保證材質的共享狀態。性能



動態批處理



若是動態物體共用着相同的材質,那麼Unity會自動對這些物體進行批處理。



動態批處理操做是自動完成的,並不須要你進行額外的操做。



Tips:

 

提醒:

 

一、 批處理動態物體須要在每一個頂點上進行必定的開銷,因此動態批處理僅支持小於900頂點的網格物體。



二、 若是你的着色器使用頂點位置,法線和UV值三種屬性,那麼你只能批處理300頂點如下的物體;若是你的着色器須要使用頂點位置,法線,UV0,UV1和切向量,那你只能批處理180頂點如下的物體。



三、請注意:屬性數量的限制可能會在未來進行改變。



四、 不要使用縮放尺度(scale)。分別擁有縮放尺度(1,1,1)和(2,2,2)的兩個物體將不會進行批處理。



五、 統一縮放尺度的物體不會與非統一縮放尺度的物體進行批處理。

 

使用縮放尺度(1,1,1)和 (1,2,1)的兩個物體將不會進行批處理,可是使用縮放尺度(1,2,1)和(1,3,1)的兩個物體將能夠進行批處理。



六、 使用不一樣材質的實例化物體(instance)將會致使批處理失敗。



七、擁有lightmap的物體含有額外(隱藏)的材質屬性,好比:lightmap的偏移和縮放係數等。因此,擁有lightmap的物體將不會進行批處理(除非他們指向lightmap的同一部分)。



八、 多通道的shader會妨礙批處理操做。好比,幾乎unity中全部的着色器在前向渲染中都支持多個光源,併爲它們有效地開闢多個通道。



九、預設體的實例會自動地使用相同的網格模型和材質。



靜態批處理



相對而言,靜態批處理操做容許引擎對任意大小的幾何物體進行批處理操做來下降繪製調用(只要這些物體不移動,而且擁有相同的材質)。所以,靜態批處理比動態批處理更加有效,你應該儘可能低使用它,由於它須要更少的CPU開銷。



爲了更好地使用靜態批處理,你須要明確指出哪些物體是靜止的,而且在遊戲中永遠不會移動、旋轉和縮放。想完成這一步,你只須要在檢測器(Inspector)中將Static複選框打勾便可,以下圖所示:



 

使用靜態批處理操做須要額外的內存開銷來儲存合併後的幾何數據。在靜態批處理以前,若是一些物體共用了一樣的幾何數據,那麼引擎會在編輯以及運行狀態對每一個物體建立一個幾何數據的備份。這並不老是一個好的想法,由於有時候,你將不得不犧牲一點渲染性能來防止一些物體的靜態批處理,從而保持較少的內存開銷。好比,將濃密森裏中樹設爲Static,會致使嚴重的內存開銷。



靜態批處理目前只支持Unity iOS Advanced。

 

Unity3D - 性能優化之Draw Call

nity(或者說基本全部圖形引擎)生成一幀畫面的處理過程大體能夠這樣簡化描述:引擎首先通過簡單的可見性測試,肯定攝像機能夠看到的物體,而後把這些物體的頂點(包括本地位置、法線、UV等),索引(頂點如何組成三角形),變換(就是物體的位置、旋轉、縮放、以及攝像機位置等),相關光源,紋理,渲染方式(由材質/Shader決定)等數據準備好,而後通知圖形API——或者就簡單地看做是通知GPU——開始繪製,GPU基於這些數據,通過一系列運算,在屏幕上畫出成千上萬的三角形,最終構成一幅圖像。

在Unity中,每次引擎準備數據並通知GPU的過程稱爲一次Draw Call。這一過程是逐個物體進行的,對於每一個物體,不僅GPU的渲染,引擎從新設置材質/Shader也是一項很是耗時的操做。所以每幀的Draw Call次數是一項很是重要的性能指標,對於iOS來講應儘可能控制在20次之內,這個值能夠在編輯器的Statistic窗口看到。

Unity內置了Draw Call Batching技術,從名字就能夠看出,它的主要目標就是在一次Draw Call中批量處理多個物體。只要物體的變換和材質相同,GPU就能夠按徹底相同的方式進行處理,便可以把它們放在一個Draw Call中。Draw Call Batching技術的核心就是在可見性測試以後,檢查全部要繪製的物體的材質,把相同材質的分爲一組(一個Batch),而後把它們組合成一個物體(統一變換),這樣就能夠在一個Draw Call中處理多個物體了(其實是組合後的一個物體)。

但Draw Call Batching存在一個缺陷,就是它須要把一個Batch中的全部物體組合到一塊兒,至關於建立了一個與這些物體加起來同樣大的物體,與此同時就須要分配相應大小的內存。這不只會消耗更多內存,還須要消耗CPU時間。特別是對於移動的物體,每一幀都得從新進行組合,這就須要進行一些權衡,不然得不償失。但對於靜止不動的物體來講,只須要進行一次組合,以後就能夠一直使用,效率要高得多。

Unity提供了Dynamic Batching和Static Batching兩種方式。Dynamic Batching是徹底自動進行的,不須要也沒法進行任何干預,對於頂點數在300之內的可移動物體,只要使用相同的材質,就會組成Batch。Static Batching則須要把靜止的物體標記爲Static,而後不管大小,都會組成Batch。如前文所說,Static Batching顯然比Dynamic Batching要高效得多,因而,Static Batching功能是收費的……

要有效利用Draw Call Batching,首先是儘可能減小場景中使用的材質數量,即儘可能共享材質,對於僅紋理不一樣的材質能夠把紋理組合到一張更大的紋理中(稱爲Texture Atlasing)。而後是把不會移動的物體標記爲Static。此外還能夠經過CombineChildren腳本(Standard Assets/Scripts/Unity Scripts/CombineChildren)手動把物體組合在一塊兒,但這個腳本會影響可見性測試,由於組合在一塊兒的物體始終會被看做一個物體,從而會增長GPU要處理的幾何體數量,所以要當心使用。

對於複雜的靜態場景,還能夠考慮自行設計遮擋剔除算法,減小可見的物體數量同時也能夠減小Draw Call。

總之,理解Draw Call和Draw Call Batching原理,根據場景特色設計相應的方案來儘可能減小Draw Call次數纔是王道,其它方面亦然。

 

U3D DrawCall優化手記

http://www.cnblogs.com/ybgame/p/3588795.html

在最近,使用U3D開發的遊戲核心部分功能即將完成,中間因爲各類歷史緣由,致使項目存在比較大的問題,這些問題在最後,恐怕只能經過一次完全的重構來解決

如今的遊戲跑起來會有接近130-170個左右的DrawCall,遊戲運行起來明顯感受到卡,而通過一天的優化,DrawCall成功縮減到30-70個,這個效果是很是顯著的,而且這個優化並無經過將現有的資源打包圖集來實現,圖集都是原有的圖集,若是從全局的角度對圖集再進行一次優化,那麼DrawCall還能夠再減小十幾個

本次優化的重點包括:層級關係和特效

對於U3D,我是一個菜鳥,對於U3D的一些東西是隻知其一;不知其二,例如DrawCall,我獲得的是一些並不徹底正確的信息,例如將N個紋理打包成一個圖集,這個圖集就只會產生一個DrawCall,若是不打成圖集,那麼就會有N個DrawCall,這個觀點在不少人的認識裏都是正確的,由於能夠經過簡單的操做來驗證,但嚴格來講,這個觀點是錯誤的,由於它還受層級關係影響!

渲染順序

U3D的渲染是有順序的,U3D的渲染順序是由咱們控制的,控制好U3D的渲染順序,你才能控制好DrawCall

一個DrawCall,表示U3D使用這個材質/紋理,來進行一次渲染,那麼此次渲染假設有3個對象,那麼當3個對象都使用這一個材質/紋理的時候,就會產生一次DrawCall,能夠理解爲一次將紋理輸送到屏幕上的過程,(實際上引擎大多會使用如雙緩衝,緩存這類的手段來優化這個過程,但在這裏咱們只須要這樣子認識就能夠了),假設3個對象使用不一樣的材質/紋理,那麼無疑會產生3個DrawCall

接下來咱們的3個對象使用2個材質,A和B使用材質1,C使用材質2,這時候來看,應該是有2個DrawCall,或者3個DrawCall。應該是2個DrawCall啊,爲何會有3個DrawCall???並且是有時候2個,有時候3個。咱們按照上面的DrawCall分析流程來分析一下:

1.渲染A,使用材質1
2.渲染B,使用材質1
3.渲染C,使用材質2

在這種狀況下是2個DrawCall,在下面這種狀況下,則是3個DrawCall

1.渲染A,使用材質1
2.渲染C,使用材質2
3.渲染B,使用材質1

由於咱們沒有控制好渲染順序(或者說沒有去特地控制),因此致使了額外的DrawCall,由於A和B不是一次性渲染完的,而是被C打斷了,因此致使材質1被分爲兩次渲染

那麼是什麼在控制這個渲染順序呢?首先在多個相機的狀況下,U3D會根據相機的深度順序進行渲染,在每一個相機中,它會根據你距離相機的距離,由遠到近進行渲染,在UI相機中,還會根據你UI對象的深度進行渲染

那麼咱們要作的就是,對要渲染的對象進行一次規劃,正確地排列好它們,規則是,按照Z軸或者深度,對空間進行劃分,而後肯定好每一個對象的Z軸和深度,讓使用同一個材質的東西,儘可能保持在這個空間內,不要讓其餘材質的對象進入這個空間,不然就會打斷這個空間的渲染順序

在這個基礎上,更細的規則有:

  • 場景中的東西,咱們使用Z軸來進行空間的劃分,例如背景層,特效層1,人物層,特效層2
  • NGUI中的東西,咱們統一使用Depth來進行空間的劃分
  • 人物模型,當人物模型只是用一個材質,DrawCall只有1,可是用了2個以上的材質,DrawCall就會暴增(或許對材質的RenderQueue進行規劃也可使DrawCall只有2個,但這個要拆分好才行),3D人物處於複雜3D場景中的時候,咱們的空間規則不免被破壞,這隻能在設計的時候儘可能去避免這種狀況了
  • 使用了多個材質的特效,在動畫的過程當中,每每會引發DrawCall的波動,在視覺效果能夠接受的範圍內,能夠將特效也進行空間劃分,假設這個特效是2D顯示,那麼可使用Z軸來劃分空間

打包圖集

每一個材質/紋理的渲染必定是會產生DrawCall的,這個DrawCall只能經過打包圖集來進行優化

製做圖集通常遵循幾個規則:

  • 從功能角度進行劃分,例如UI能夠劃分爲公共部分,以及每一個具體的界面,功能上,顯示上密切相關的圖片打包到一塊兒
  • 不要一股腦把全部東西打包到一個圖集裏,特別是那些不可能同時出現的東西,它們就不該該在一個圖集裏,這樣的圖集意義不大,減小不了DrawCall,而且一個你不須要顯示的圖片,會一直佔用你的內存,這讓我很是不爽
  • 注意控制圖集的大小,不要讓圖集太大,一個超級大圖集的DrawCall消耗或許頂的上十幾個小圖集的消耗

字符圖集,在使用BMFont或者其餘工具生成圖片字的時候,咱們每每是直接導入一大串文字,而後直接生成圖片,但實際上這上面的操做也有優化空間,例如BMFont生成的圖片大小,是能夠設置的,有兩個規則,一個規則是導出的圖片儘可能小,另外一個是導出的圖片儘可能少,默認的大小應該是512x512,假設你生成的圖片256x256就能夠容納,那麼多作一個操做你能夠節省這麼多空間,另外當你輸入多幾個字,就致使增長一張圖片時,例如1024變成2048,那麼你能夠考慮使用3張512的圖片,這樣也會節省空間

通過精心劃分的圖集在加上精心規劃的渲染順序,DrawCall會有一個質的優化

特效清理

U3D提供了很是便捷的方法讓咱們很輕易地使用美術給過來的特效,懶惰的U3D程序猿會直接放入U3D,甚至不去看這是個什麼特效,咱們的特效通常都是一瞬間的事情,例如技能特效,或者其餘什麼特效,那麼特效播放完,這個特效咱們就看不到了,但假設這個特效在播放結束的時候,沒有將自身的Active屬性設置爲false,那麼它就會繼續佔用你的DrawCall,消耗你設備的計算能力,因此程序須要保證當一個特效播放完以後,可以被消耗,或者設置爲非激活的狀態,可使用一些公共方法來完成特效播放完以後的清理工做(本身實現2個靜態函數,一個播放完銷燬,一個播放完設置未激活)

完成DrawCall的優化以後,接下來就是內存的優化了,(內存優化手記 待續)

相關文章
相關標籤/搜索