Unity3D研究院之優化Graphics.DrawMeshInstanced

若是項目中使用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

相關文章
相關標籤/搜索