在新版本的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] 举报,一经查实,本站将立刻删除。