彷佛是在Unity5.4中開始支持GPU Instacing,但若是要比較好的使用推薦用unity5.6版本,由於這幾個版本一直在改。html
這裏測試也是使用unity5.6.2進行測試git
在5.6的版本里,Instancing再也不是一個單獨的shader,而是一個開關。github
若是使用Instancing功能須要開啓,不然調用相關接口時會報錯dom
默認狀況下,多個同樣的模型會被動態批次合併優化掉,動態批次合併有不少種狀況不可用,其中一種就是鏡像的狀況。ide
這裏用鏡像後的實例模型和GPU Instancing作比較測試
注意,在Unity5.6.2或者以後的版本中,只要材質球勾選Instancing,即自動開啓並使用GPU Instancing。優化
GPU Instancing大體代碼以下(用Graphics一次性調用減小了層級對象的建立開銷):ui
void Update() { var meshRenderer = template.GetComponent<MeshRenderer>(); var meshFilter = template.GetComponent<MeshFilter>(); var mesh = meshFilter.sharedMesh; var matrices = new Matrix4x4[instanceCount]; for (int i = 0; i < matrices.Length; i++) { var position = Random.insideUnitSphere * range; var rotation = Quaternion.LookRotation(Random.insideUnitSphere); var scale = Vector3.one * Random.Range(-2f, 2f); var matrix = Matrix4x4.TRS(position, rotation, scale); matrices[i] = matrix; } Graphics.DrawMeshInstanced(mesh, 0, meshRenderer.sharedMaterial, matrices); }
是實時隨機的位置,會看見只有13個Batches.spa
常規實例化測試腳本(掛了正弦運動腳本,注意鏡像反轉,使其沒法動態批次合併):翻譯
for (int i = 0; i < instanceCount; i++) { var instancedTemplate = Instantiate(template); instancedTemplate.transform.position = Random.insideUnitSphere * range; instancedTemplate.transform.forward = Random.insideUnitSphere; instancedTemplate.transform.localScale = Vector3.one * Random.Range(-2f, 2f); }
大概在1020個Batches
另外我還打了個APK包測了下,竟然能在個人紅米3S上跑。這就有點厲害了
那麼GPU Instacing其實也有一些限制的,好比不支持蒙皮網格等(不過資源商店有一個Animation Instacing: 連接)
(補充:Unity官方開源了一個Animation Instacing: https://blogs.unity3d.com/cn/2018/04/16/animation-instancing-instancing-for-skinnedmeshrenderer/)
這些支持信息在官網的頁面都有羅列 https://docs.unity3d.com/Manual/GPUInstancing.html
硬件需求:
GPU Instancing is available on the following platforms and APIs:
DirectX 11 and DirectX 12 on Windows
OpenGL Core 4.1+/ES3.0+ on Windows, macOS, Linux, iOS and Android
Metal on macOS and iOS
Vulkan on Windows and Android
PlayStation 4 and Xbox One
WebGL (requires WebGL 2.0 API)
模塊間的需求(沒找到原版的帖子,翻譯版摘抄一段):
下列狀況不能使用Instancing:
- 使用Lightmap的物體
- 受不一樣Light Probe / Reflection Probe影響的物體
- 使用包含多個Pass的Shader的物體,只有第一個Pass能夠Instancing前向渲染時,受多個光源影響的物體只有Base Pass能夠instancing,Add Passes不行
另外,默認的DrawMeshInstanced有1024實例數的限制
須要DrawMeshInstancedIndirect,而這個接口依賴ComputerShader,一些平臺不支持。
而後再測一下GPU Instanced Indirect,也就是DrawMeshInstancedIndirect這個接口
彷佛是藉助ComputerShader實現超過1024數量的Instancing
下圖爲3萬個Cube:
代碼和shader我作了點修改,大體以下:
void Update() { // Update starting position buffer if (cachedInstanceCount != instanceCount) UpdateBuffers(); for (int i = 0; i < mPositions.Length; i++) { float angle = Random.Range(0.0f, Mathf.PI * 2.0f); float distance = Random.Range(20.0f, 100.0f); float height = Random.Range(-2.0f, 2.0f); float size = Random.Range(0.05f, 0.25f); mPositions[i] = new Vector4(Mathf.Sin(angle) * distance, height, Mathf.Cos(angle) * distance, size); } positionBuffer.SetData(mPositions); instanceMaterial.SetBuffer("positionBuffer", positionBuffer); // Render Graphics.DrawMeshInstancedIndirect( instanceMesh, 0, instanceMaterial, new Bounds(Vector3.zero, new Vector3(100.0f, 100.0f, 100.0f)), argsBuffer); }
shader須要額外定製,這點比較蛋疼。若是換成standard讀不到positionBuffer這種結構。
DrawMeshInstancedIndirect的具體使用案例,能夠參考這兩個連接:
https://docs.unity3d.com/ScriptReference/Graphics.DrawMeshInstancedIndirect.html
https://github.com/tiiago11/Unity-InstancedIndirectExamples
補充測試工程地址: https://gitee.com/Hont/GPUInstancingTest
(unity2017.4)
Geometry instancing
https://en.wikipedia.org/wiki/Geometry_instancing
Unity中的批處理優化與GPU Instancing