Unity3D學習筆記4——創建Mesh高級接口

1. 概述

在文章Unity3D學習筆記2——繪製一個帶紋理的面中使用代碼的方式創建了一個Mesh,不過這套接口在Unity中被稱爲簡單接口。與其相對應的,Unity還提供了一套高級API來創建Mesh。

2. 詳論

根據Unity文檔的論述,使用高級接口能夠得到更高的性能,能夠跳過一些驗證檢查。但是這並不是最關鍵的,簡單接口有個最大的缺點是頂點個數超過65535個時就有問題(至少在2019.4.3f1版本還是這樣)。

話不多說,直接上代碼:

using UnityEngine;
using UnityEngine.Rendering;

[ExecuteInEditMode]
public class Note4Main : MonoBehaviour
{
    public Material material;

    // Start is called before the first frame update
    void Start()
    {
        Mesh mesh = new Mesh();
        mesh.name = "quad";

        //頂點數據
        VertexAttributeDescriptor[] vertexAttributeDescriptorList = new[]{
             new VertexAttributeDescriptor(VertexAttribute.Position, VertexAttributeFormat.Float32, 3),
             new VertexAttributeDescriptor(VertexAttribute.Normal, VertexAttributeFormat.Float32, 3),
             new VertexAttributeDescriptor(VertexAttribute.TexCoord0, VertexAttributeFormat.Float32, 2)};

        const int vertexCount = 4;
        const int verticesAttributeBufferLength = vertexCount * (3 + 3 + 2);
        float[] verticesAttributeBuffer = new float[verticesAttributeBufferLength] {
            -5, -5, 0, 0, 0, -1,0, 0,
            -5, 5, 0, 0, 0, -1, 0, 1,
            5, -5, 0, 0, 0, -1, 1, 0,
            5, 5, 0, 0, 0, -1, 1, 1
        };

        mesh.SetVertexBufferParams(vertexCount, vertexAttributeDescriptorList);
        mesh.SetVertexBufferData(verticesAttributeBuffer, 0, 0, verticesAttributeBufferLength, 0);

        int[] triangles = new int[6] { 0, 1, 2, 1, 3, 2 };
        int indexCount = triangles.Length;

        //頂點索引文件
        mesh.SetIndexBufferParams(indexCount, IndexFormat.UInt32);
        mesh.SetIndexBufferData(triangles, 0, 0, indexCount);

        //子Mesh描述
        mesh.subMeshCount = 1;
        SubMeshDescriptor subMeshDescriptor = new SubMeshDescriptor(0, indexCount);
        mesh.SetSubMesh(0, subMeshDescriptor);

        MeshFilter mf = gameObject.GetComponent<MeshFilter>();
        if (mf == null)
        {
            mf = gameObject.AddComponent<MeshFilter>();
        }
        mf.sharedMesh = mesh;

        MeshRenderer meshRenderer = gameObject.GetComponent<MeshRenderer>();
        if (meshRenderer == null)
        {
            meshRenderer = gameObject.AddComponent<MeshRenderer>();
        }
        meshRenderer.material = material;
    }

    // Update is called once per frame
    void Update()
    {
    }
}

最後可以直接得到與Unity3D學習筆記2——繪製一個帶紋理的面一樣的效果。如果有一些圖形基礎,就會很容易理解這段代碼。都是申請一個buffer,定義頂點的描述信息,這裏是按照x,y,z,nx,ny,nz,u,v的順序,一個頂點一個頂點進行排列。接着是定義一個頂點索引buffer;不同的是增加了一個對於子mesh的描述。在Unity裏,一個Mesh可以包含多個子Mesh,每個子Mesh都能對應MeshRenderer中的多個材質中的一個。

3. 其他

  1. 根據官方文檔論述,這套高API性能更高。但個人使用感覺不是很明顯。跳過驗證的設置也可能帶來一些其他問題,我一般用默認設置。
  2. 另一個優點是,可以避免簡單接口中頂點個數超過65535時Mesh繪製不正確的問題。理論上,繪製的批次越少越好,這就要求儘可能合批次繪製,同樣頂點個數的物體分多個mesh繪製,性能比不上使用一個大的Mesh一次繪製。
  3. 官方文檔還提到了有其他接口可以通過C# Jobs和Burst創建Mesh,C# Jobs與多線程相關,難道意味着可以在多線程下創建Mesh了?有待進一步研究。

4. 參考

  1. Unity3D學習筆記2——繪製一個帶紋理的面
  2. Unity Documentation - Mesh
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章