zoukankan      html  css  js  c++  java
  • 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获取。这里需要注意,

    要在编辑器下检查Mesh的数据,结构体需要与其保持一致。

    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

  • 相关阅读:
    农夫带着狼、羊和一棵白菜过河
    C#实现L型棋牌覆盖
    数据库存储管理
    4个人打算过桥,它们都在桥的某一端,.我们有17分钟让他们全部到达大桥的另一头?
    C# 创建Public无参构造函数的快捷键
    控制文件管理
    配置数据库
    C#实现线性查找(递归,非递归)
    C#实现选择排序
    C#4.0参数默认值
  • 原文地址:https://www.cnblogs.com/hont/p/15110254.html
Copyright © 2011-2022 走看看