上回 遊戲圖形批量渲染及優化:Unity動態合批技術 簡單總結了一下動態合批,這次我們繼續說說Unity實例化渲染。
| 實例化渲染
當我們想要呈現這樣的場景:一片茂密的森林、廣闊的草原或崎嶇的山路時,會發現在這些場景中存在大量重複性元素:樹木、草和岩石。
仙境怕是也不過如此吧
它們都使用了相同的模型,或者模型的種類很少,比如:樹可能隻有幾種;但為了做出差異化,它們的顏色略有不同,高低參差不齊,當然位置也各不相同。
使用靜態合批來處理它們(假設它們都沒有動畫),是不合適的。因為數量太多(林子大了,多少樹都有),所以合並後的網格體積可能非常大,這會引起內存的增加;而且,這個合並後的網格還是由大量重複網格組成的,不劃算。
使用動態合批來處理他們,雖然不會“合並”網格,但是仍然需要在渲染前遍曆所有頂點,進行空間變換的操作;雖然單顆樹、石頭的頂點數量可能不多,但由於數量很多,所以也會在一定程度上增加CPU性能的開銷,沒必要。
那麼,對於場景中這些模型重複、數量多的渲染需求,有沒有適合的批處理策略呢?有吧,實例化渲染就是為了解決這樣的問題。
| 簡述工作原理
實例化渲染,是通過調用“特殊”的渲染接口,由GPU完成的“批處理”。
它與傳統的渲染方式相比,最大的差別在於:調用渲染命令時需要告知GPU這次渲染的次數(繪製N個)。當GPU接到這個命令時,就會連續繪製N個物體到我們的屏幕上,其效率遠高於連續調用N次傳統渲染命令的和(一次繪製一個)。
舉個例子,假設希望在屏幕上繪製出兩個顏色、位置均不同的箱子。如果使用傳統的渲染,則需要調用兩次渲染命令(DrawCall = 2),分別為:畫一個紅箱子 和 畫一個綠箱子。
兩個顏色、位置各異的箱子
如果使用實例化渲染,則隻需要調用一次渲染命令(DrawCall = 1),並且附帶一個參數2(表示繪製兩個)即可。
當然,如果隻是這樣,那GPU就會把兩個箱子畫在相同的位置上。所以我們還需要告訴GPU兩個箱子各自的位置(其實是轉換矩陣)以及顏色。
這個位置和顏色我們會按照數組的方式傳遞給GPU,大概這個樣子吧:
分別傳遞保存位置和顏色的數組
那接下來GPU在進行渲染時,就會在渲染每一個箱子的時候,根據當前箱子的索引(第幾個),拿到正確的屬性(位置、顏色)來進行繪製了。
一個簡單的實例化渲染流程
| Unity是如何處理實例化的
我們通過一個簡單的場景,來看一下Unity為實例化渲染做了什麼。
實例化渲染兩個彩色箱子
顏色屬性通過MaterialPropertyBlock傳入
通過GPA觀察Unity做了什麼。
GPA中的VertexBuffer和IndexBuffer中的信息
注:Unity默認Cube網格,包含24個頂點和36個索引。
頂點緩衝區Size = (Position(float3)
+ Normal(float3)
+ Tangent(float4)
+ TexCoord(float2)
+ TexCoord1(float2)) x 24 = 1344Byte
索引緩衝區Size = Index(ushort) x 36 = 72Byte
可見,頂點、索引緩衝區內,確實隻有一個網格的數據。
那麼GPU如何判斷每個Cube的繪製位置,及其顏色呢?
結合引擎為Dx平台生成的shader(我的測試環境使用的是Pc),可以很容易找到對應的數據。
轉換矩陣及顏色被分別填入Constant Buffer中
Constant Buffer中的矩陣(Dx為行向量)
Constant Buffer中的屬性(顏色)
可見,渲染時GPU可以通過當前實例化單位的索引,從Buffer中獲取到對應的屬性,完成正確的繪製。
| Unity中啟用實例化渲染
當然,相比於上述無用的知識點,如何在Unity中使用實例化渲染可能更為重要。
在Unity中可以通過自動或手動的方式,啟用實例化渲染。
自動啟用實例化渲染
使用支持實例化渲染的Shader,並勾選材質球上的啟用開關,Unity便會對滿足條件的物體,自動開啟實例化渲染。
有這個選項即表示該Shader支持實例化渲染
自定義Shader
如果你希望自己的Shader也支持實例化渲染,應重點注意以下內容:
#pragma multi_compile_instancing
啟用實例化渲染(材質球上將出現啟用實例化的勾選框);
UNITY_VERTEX_INPUT_INSTANCE_ID
在a2v及v2f的結構中定義實例化索引下標(SV_InstanceID ),也就是當前渲染單位的索引,用於從Constant Buffer中提取正確的屬性(做顯示差異化用);
UNITY_INSTANCING_BUFFER_START ~ END
在這個起止區域內定義屬性,才能在著色器中正確的根據索引提取出當前渲染單位所對應的屬性;
UNITY_SETUP_INSTANCE_ID
定義在著色器的起始位置,使頂點著色器(或片段著色器)可以正確的訪問到實例化單位的索引;
UNITY_ACCESS_INSTANCED_PROP
根據索引訪問到這個單位對應的屬性,如上麵例子中每個箱子的顏色屬性。
這裏隻是簡述一些相對重要的內容(湊些字數),官方文檔中有更詳細內容,建議優先了解。
手動實例化渲染
使用 Graphics.DrawMeshInstanced 和 Graphics.DrawMeshInstancedIndirect 來手動執行 GPU 實例化,詳見官方文檔中的解釋,這裏就不再贅述了。
| 實例化渲染的使用要求
並非所有設備都可以使用實例化渲染。
在Unity官方文檔中,列舉了各平台支持實例化渲染的最低要求。
官方文檔中對支持實例化渲染的最低API要求
當然,我們也可以通過引擎中SystemInfo.supportsInstancing屬性來判斷環境是否支持實例化渲染。
那支持實例化渲染的機器占比大概是多少呢?由於國內大多數遊戲公司都是以手遊項目糊口。所以開發者可能會更多關注其在安卓平台上的情況。
根據Android開發者的官方數據顯示,截至2020年8月30日,約88%的活躍安卓設備,都已經支持實例化渲染,所以基本上可以放心使用。
android開發者官網發布的活躍設備OpenGL ES版本占比信息
| 與靜、動態合批的差異
靜、動態合批實質上是將可以合批的對象真正的合並成一個大物體後,再通知GPU進行渲染,也就是其頂點索引緩衝區中必須包含全部參與合批對象的頂點信息;因此,可以認為是CPU完成的批處理。
實例化渲染是對網格信息的重複利用,無論最終要渲染出幾個單位,其頂點和索引緩衝區內都隻有一份數據,可以認為是GPU完成的批處理。
其實這麼總結也有點問題,本質上講:動、靜態合批解決的是合批問題,也就是先有大量存在的單位,再通過一些手段合並成為批次;而實例化渲染其實是個複製的事兒,是從少量複製為大量,隻是利用了它“可以通過傳入屬性實現差異化”的特點,在某些條件下達到了與合批相同的效果。
| 簡單總結靜、動態合批及實例化渲染
無論是靜態合批、動態合批或實例化渲染,本質上並無孰優孰劣,它們都隻是提高渲染效率的解決方案,也都有自己適合的場景或擅長解決的問題。
個人以為:
如果你的場景中存在多數靜止的、使用了不同網格、相同材質的物體,特別是當你的相機通常隻能照到一部分物體時(如第一視角),可以優先嚐試下靜態合批,通過犧牲一些內存來提升渲染效率;
針對那些運動的、網格頂點數很少、材質相同的物體,比如飛行的各種箭矢、炮彈等,使用動態合批,通過增加一些CPU處理頂點的性能開銷,來提升渲染效率,也許是不錯的選擇;
如果有大量模型相同、材質相同、或盡管表現上有一些不同,但仍然可以通過屬性來實現這些差異化的物體時,啟用實例化渲染通常可以在很大程度上提升渲染效率。
| 寫在最後
按計劃下次更新的內容應該是“優化骨骼蒙皮動畫,以及兩種常用的批量渲染方式”,但覺得內容有點多,所以將其分為兩個部分;因此,下次更新的內容變為“優化骨骼蒙皮動畫”,而“兩種常用的骨骼蒙皮動畫單位的批量渲染方式”,將作為本係列的最後一次更新內容。
下回見嘍。
作者:枸杞憂天
來源:偶爾學學Unity公眾號
熱門課程
專業講師指導 快速擺脫技能困惑相關文章
多種教程 總有一個適合自己專業問題谘詢
你擔心的問題,火星幫你解答火星時代教育提供深度、係統的建築表現設計師培訓課程,探索21世紀建築藝術的多種可能性與創新。
UE4場景地編是遊戲開發的重要環節,火星時代教育提供係統全麵的UE4場景地編培訓,助你占領遊戲開發前沿。
涵蓋了關於AI插畫培訓班的選擇與比較,以及火星時代教育的專業課程介紹。關鍵詞:AI插畫培訓,火星時代教育。
本文詳細介紹遊戲原畫美術設計師的培訓信息,探討华体会hth体育app在线登录 師的重要性和成功之路,並強調火星時代教育在原畫設計師培訓方麵的專業能力。
深入探究遊戲原畫場景的描繪技巧,提高你的創作能力。從火星時代教育進行學習。
遊戲原畫CG設計培訓為你打開專業华体会hth体育app在线登录 的大門,讓你的創造力在火星時代教育的引導下釋放出來。
1. 打開微信掃一掃,掃描左側二維碼
2. 添加老師微信,馬上領取免費課程資源
同學您好!