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

  • 相关阅读:
    LeetCode 811. Subdomain Visit Count (子域名访问计数)
    LeetCode 884. Uncommon Words from Two Sentences (两句话中的不常见单词)
    LeetCode 939. Minimum Area Rectangle (最小面积矩形)
    LeetCode 781. Rabbits in Forest (森林中的兔子)
    LeetCode 739. Daily Temperatures (每日温度)
    三种方式实现按钮的点击事件
    239. Sliding Window Maximum
    14.TCP的坚持定时器和保活定时器
    13.TCP的超时与重传
    12.TCP的成块数据流
  • 原文地址:https://www.cnblogs.com/hont/p/15110254.html
Copyright © 2011-2022 走看看