微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Unity新的MeshData API学习

在新版本的Unity中提供了MeshDataArray和MeshData两个API,使Mesh数据操作支持多线程,以更好的支持DOTS。

api文档https://docs.unity3d.com/es/2020.2/ScriptReference/Mesh.MeshData.html

 

1.IJob修改顶点

首先用Mesh.AllocateWritableMeshData分配一个可写的网格数据,然后通过jobs进行顶点操作,

最后通过Mesh.ApplyAnddisposeWritableMeshData接口赋值回Mesh。

 

用简单的正弦波x轴移动测试:

 

代码如下:

using System;
using System.Linq;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Rendering;

[RequireComponent(typeof(MeshFilter))]
public class MDT1 : MonoBehavIoUr
{
    [BurstCompile]
    public struct TestJob : IJobParallelFor
    {
        [ReadOnly] public float time;
        [ReadOnly] public NativeArray<Vector3> sourceVertices;
        [writeonly] public NativeArray<Vector3> writeVertices;


        public void Execute(int index)
        {
            Vector3 vert = sourceVertices[index];
            vert.x += math.sin(index + time) * 0.03f;
            writeVertices[index] = vert;
        }
    }

    public MeshFilter meshFilter;
    private NativeArray<Vector3> mCacheVertices;
    private NativeArray<Vector3> mCachenormals;

    private ushort[] mCacheTriangles;
    private Mesh mCacheMesh;


    private void Awake()
    {
        Mesh sourceMesh = meshFilter.sharedMesh;
        mCacheVertices = new NativeArray<Vector3>(sourceMesh.vertices, Allocator.Persistent);
        mCachenormals = new NativeArray<Vector3>(sourceMesh.normals, Allocator.Persistent);
        mCacheTriangles = sourceMesh.triangles
            .Select(m => (ushort) m)
            .ToArray();

        mCacheMesh = new Mesh();
        GetComponent<MeshFilter>().mesh = mCacheMesh;
    }

    private void OnDestroy()
    {
        mCacheVertices.dispose();
        mCachenormals.dispose();
    }

    private void Update()
    {
        Mesh.MeshDataArray dataArray = Mesh.AllocateWritableMeshData(1);
        Mesh.MeshData data = dataArray[0];

        data.SetVertexBufferParams(mCacheVertices.Length,
            new VertexAttributeDescriptor(VertexAttribute.Position),
            new VertexAttributeDescriptor(VertexAttribute.normal, stream: 1));
        data.SetIndexBufferParams(mCacheTriangles.Length, IndexFormat.UInt16);

        NativeArray<Vector3> vertices = data.GetVertexData<Vector3>();
        NativeArray<ushort> indices = data.GetIndexData<ushort>();

        NativeArray<Vector3> normals = new NativeArray<Vector3>(mCachenormals.Length, Allocator.TempJob);
        data.Getnormals(normals);
        for (int i = 0; i < normals.Length; ++i)
            normals[i] = mCachenormals[i];
        normals.dispose();

        for (int i = 0; i < mCacheTriangles.Length; ++i)
            indices[i] = mCacheTriangles[i];
        
        TestJob job = new TestJob()
        {
            time = Time.time,
            sourceVertices = mCacheVertices,
            writeVertices = vertices
        };

        job
            .Schedule(mCacheVertices.Length, 8)
            .Complete();

        data.subMeshCount = 1;
        data.SetSubMesh(0, new SubMeshDescriptor(0, mCacheTriangles.Length));

        Mesh.ApplyAnddisposeWritableMeshData(dataArray, mCacheMesh);
        mCacheMesh.Recalculatenormals();
        mCacheMesh.RecalculateBounds();
    }
}

 

2.直接通过结构获取Mesh对应字段,并修改更新

也可以直接设置和Mesh字段结构一样的结构体,直接GetVertexData获取。这里需要注意,

顶点索引数据类型一般是uint16,可在编辑器内看下,不要声明错了

using System;
using Unity.Collections;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Rendering;

public class MDT2 : MonoBehavIoUr
{
    struct VertexStruct
    {
        public float3 pos;
        public float3 normal;
        public float4 tangent;
        public float2 uv0;
        public float2 uv1;
    }

    public Mesh srcmesh;
    public MeshFilter meshFilter;

    private Mesh mCacheMesh;
    private NativeArray<VertexStruct> mCacheInVertices;


    private void Start()
    {
        mCacheMesh = new Mesh();
        meshFilter.sharedMesh = mCacheMesh;
    }

    private void Update()
    {
        Mesh.MeshDataArray inMeshDataArray = Mesh.AcquireReadOnlyMeshData(srcmesh);
        Mesh.MeshData inMesh = inMeshDataArray[0];
        mCacheInVertices = inMesh.GetVertexData<VertexStruct>();

        int vertexCount = srcmesh.vertexCount;
        int indexCount = srcmesh.triangles.Length;

        Mesh.MeshDataArray outMeshDataArray = Mesh.AllocateWritableMeshData(1);
        Mesh.MeshData outMesh = outMeshDataArray[0];
        outMesh.SetVertexBufferParams(vertexCount,
            new VertexAttributeDescriptor(VertexAttribute.Position),
            new VertexAttributeDescriptor(VertexAttribute.normal),
            new VertexAttributeDescriptor(VertexAttribute.Tangent, VertexAttributeFormat.Float32, 4),
            new VertexAttributeDescriptor(VertexAttribute.TexCoord0, VertexAttributeFormat.Float32, 2),
            new VertexAttributeDescriptor(VertexAttribute.TexCoord1, VertexAttributeFormat.Float32, 2));

        outMesh.SetIndexBufferParams(indexCount, IndexFormat.UInt16);

        NativeArray<ushort> indices = outMesh.GetIndexData<ushort>();
        for (int i = 0; i < srcmesh.triangles.Length; ++i)
            indices[i] = (ushort) srcmesh.triangles[i];

        NativeArray<VertexStruct> outVertices = outMesh.GetVertexData<VertexStruct>();
        for (int i = 0; i < mCacheInVertices.Length; i++)
        {
            VertexStruct vert = mCacheInVertices[i];
            vert.pos.x += math.sin(i + Time.time) * 0.03f;
            outVertices[i] = vert;
        }

        outMesh.subMeshCount = 1;
        SubMeshDescriptor subMeshDesc = new SubMeshDescriptor
        {
            indexStart = 0,
            indexCount = indexCount,
            topology = MeshTopology.Triangles,
            firstVertex = 0,
            vertexCount = vertexCount,
            bounds = new Bounds(Vector3.zero, Vector3.one * 100f)
        };
        outMesh.SetSubMesh(0, subMeshDesc);

        Mesh.ApplyAnddisposeWritableMeshData(outMeshDataArray, mCacheMesh);
        mCacheMesh.Recalculatenormals();
        mCacheMesh.RecalculateBounds();
        
        mCacheInVertices.dispose();
        inMeshDataArray.dispose();
    }
}

 

3.Graphics Buffer

在unity2021.2版本之后可以拿到Graphics Buffer类型:

mesh.GetVertexBuffer()

该类型可直接作为Buffer参数传入ComputeShader中。具体在github上有示例:

https://github.com/Unity-Technologies/MeshApiExamples

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐