若是項目中使用GPU Instancing的話,不少人都會用底層API Graphics.DrawMeshInstanced在Update中繪製。dom
咱們先來作個極端的測試,以下代碼所示。測試
void Update() { for (int i = 0; i < 1024; i++) { Graphics.DrawMeshInstanced(mesh, 0, material, m_atrix4x4s, 1023); } }
以下圖所示,能看出來在Update每幀都有一個比較高的耗時。優化
using UnityEngine; using UnityEngine.Rendering; public class G1 : MonoBehaviour { //GPU instancing材質 public Material material; //GPU instancing網格 public Mesh mesh; //隨便找個位置作隨機 public Transform target; //是否使用cammandBuffer渲染 public bool useCommandBuffer = false; //觀察攝像機 public Camera m_Camera; private Matrix4x4[] m_atrix4x4s = new Matrix4x4[1023]; void Start() { CommandBufferForDrawMeshInstanced(); } private void OnGUI() { if (GUILayout.Button("<size=50>當位置發生變化時候在更新</size>")) { CommandBufferForDrawMeshInstanced(); } } void Update() { if (!useCommandBuffer) { GraphicsForDrawMeshInstanced(); } } void SetPos() { for (int i = 0; i < m_atrix4x4s.Length; i++) { target.position = Random.onUnitSphere * 10f; m_atrix4x4s[i] = target.localToWorldMatrix; } } void GraphicsForDrawMeshInstanced() { if (!useCommandBuffer) { SetPos(); Graphics.DrawMeshInstanced(mesh, 0, material, m_atrix4x4s, m_atrix4x4s.Length); } } void CommandBufferForDrawMeshInstanced() { if (useCommandBuffer) { SetPos(); if (m_buff != null) { m_Camera.RemoveCommandBuffer(CameraEvent.AfterForwardOpaque, m_buff); CommandBufferPool.Release(m_buff); } m_buff = CommandBufferPool.Get("DrawMeshInstanced"); for (int i = 0; i < 1; i++) { m_buff.DrawMeshInstanced(mesh, 0, material, 0, m_atrix4x4s, m_atrix4x4s.Length); } m_Camera.AddCommandBuffer(CameraEvent.AfterForwardOpaque, m_buff); } } CommandBuffer m_buff = null; }
若是每幀的調用Graphics.DrawMeshInstanced的位置矩陣和MaterialPropertyBlock參數都是一致,我就在想可否進行優化。code
其實CommandBuffer也有DrawMeshInstanced方法,這樣就能夠不用在Update裏每幀調用了。當位置矩陣或者MaterialPropertyBlock參數發生變化時在調用DrawMeshInstanced,放入CommandBuffer中渲染。以下圖所示,使用CommandBuffer.DrawMeshInstanced只有當元素位置改變時在刷新,這樣明顯效率高了不少。orm
結合實際項目,好比以前作過的地面的草、石頭、柵欄一旦建立出來之後都不會去改變位置,更適合用commandbuffer來作。固然裁剪還須要本身來作,GPU instancing不支持自動裁剪
blog