Mesh网格编程(2)

程序网格作业框架

通用顶点

创建一个脚本命名为Vertex

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

namespace ProceduralMeshes
{
    
    
    public interface IMeshStreams
    {
    
    
        void Setup(Mesh.MeshData data,Bounds bounds ,int vertexCount, int indexCount);
        void SetVertex(int index, Vertex data);
        void SetTriangle(int index, int3 triangle);
    }//引入接口来隔离代码
    public struct Vertex
    {
    
    
        public float3 position, normal;
        public float4 tangent;
        public float2 texCoord0;
    }

    
}

这段代码定义了一个C#命名空间(namespace)ProceduralMeshes,并在其中定义了一个接口IMeshStreams和一个结构体Vertex。

IMeshStreams是一个接口,定义了三个方法:Setup、SetVertex和SetTriangle。这个接口的目的是提供一个与具体实现分离的抽象层,从而使代码更加灵活和可扩展。具体实现可以根据需要来实现这个接口并提供相应的实现。

Vertex是一个结构体,包含了一个float3类型的position和normal,一个float4类型的tangent以及一个float2类型的texCoord0。这个结构体的作用是描述了一个顶点的几何属性,例如位置、法线、切线和纹理坐标等。

网状流

using UnityEngine;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Unity.Collections;
using Unity.Mathematics;
using UnityEngine.Rendering;
using Unity.Collections.LowLevel.Unsafe;

namespace ProceduralMeshes.Streams
{
    
    
    
    public struct SingleStream : IMeshStreams
    {
    
       
        [StructLayout(LayoutKind.Sequential)]
        struct Stream0
        {
    
    
            public float3 position, normal;
            public float4 tangent;
            public float2 texCoord0;
        }
        [NativeDisableContainerSafetyRestriction]
        NativeArray<Stream0> stream0;
        [NativeDisableContainerSafetyRestriction]
        NativeArray<int3> triangles;
        public void Setup(Mesh.MeshData meshData,Bounds bounds, int vertexCount, int indexCount)//定义网格的缓冲区
        {
    
    
            var descriptor = new NativeArray<VertexAttributeDescriptor>(
                4,Allocator.Temp,NativeArrayOptions.UninitializedMemory
            );
            descriptor[0] = new VertexAttributeDescriptor(dimension: 3);//dimension:尺寸
            descriptor[1] = new VertexAttributeDescriptor(
                VertexAttribute.Normal,dimension:3
            );
            descriptor[2] = new VertexAttributeDescriptor(
                VertexAttribute.Tangent,dimension:4
            );
            descriptor[3] = new VertexAttributeDescriptor(
                VertexAttribute.TexCoord0, dimension: 2
            );
            meshData.SetIndexBufferParams(indexCount,IndexFormat.UInt32);//使用三十二位浮点数
            meshData.subMeshCount = 1;//网格数量为一
            meshData.SetSubMesh(0,new  SubMeshDescriptor(0,indexCount)
                {
    
    
                    bounds = bounds,
                    vertexCount = vertexCount
                },
                MeshUpdateFlags.DontRecalculateBounds|MeshUpdateFlags.DontValidateIndices);//设置单个子网络
            stream0 = meshData.GetVertexData<Stream0>();
            triangles = meshData.GetIndexData<int>().Reinterpret<int3>(4);
        }
        
        //实现包括将顶点数据复制到一个值,并将其存储在流中的相应索引处
        [MethodImpl(MethodImplOptions.AggressiveInlining)]//将Burst以内敛形式插入整个代码
        public void SetVertex(int index, Vertex vertex) => stream0[index] = new Stream0
        {
    
    
            position = vertex.position,
            normal = vertex.normal,
            tangent = vertex.tangent,
            texCoord0 = vertex.texCoord0
        };
        /*
         * 通过将索引数据重新解释为三角形数据,
         * 直接将三角形数据复制到索引缓冲区。
         * 将本机数组存储在末尾的字段中,并执行
         */
        public void SetTriangle(int index, int3 triangle) => triangles[index] = triangle;
    }

定义一个结构体“SingleStream”实现“IMeshStreams”界面。
它包含的方法设置和控制网格的顶点和索引数据。

SingleStream的结构定义了一个私人“Stream0”结构,其中包含网格的顶点数据。
设置的方法初始化网格数据缓冲区,包括设置顶点的数量和指数和创建一个sub-mesh描述符。
SetVertex的方法设置顶点数据在一个特定的索引,而“SetTriangle”设置三角形数据在一个特定的索引方法。

总的来说,这个脚本用于创建和修改程序网格在统一中,允许在运行时动态创建和操纵网格。

网格生成器

using UnityEngine;

namespace ProceduralMeshes
{
    
    
    public interface IMeshGenerator//为负责生成网格的代码部分引入一个接口
    {
    
    
        Bounds Bounds {
    
     get; }
        void Execute<S>(int i, S streams) where S : struct, IMeshStreams;
        int VertexCount {
    
     get; }
        int IndexCount {
    
     get; }
        int JobLength {
    
     get; }//安排作业时还必须知道作业的长度。添加 getter 属性以提供此信息
    }
}

using ProceduralMeshes;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;

namespace ProcedurbalMeshes
{
    
    
    [BurstCompile(FloatPrecision.Standard, FloatMode.Fast, CompileSynchronously = true)]
    public struct MeshJob<G, S> : IJobFor//限定了一个用于生成网格的结构体类型和一个用于保存网格流数据的结构体类型。
        where G : struct, IMeshGenerator
        where S : struct, IMeshStreams
    {
    
    
        private G generator;
        [WriteOnly]//只在生成网格时写入流,而不是从中读取
        private S streams;

        public void Execute(int i) => generator.Execute(i, streams);
        public static JobHandle ScheduleParallel(Mesh mesh,Mesh.MeshData meshData, JobHandle dependency)
        {
    
    
            var job = new MeshJob<G, S>();
            
            job.streams.Setup(
                meshData,mesh.bounds = job.generator.Bounds,job.generator.VertexCount,job.generator.IndexCount
                );
            return job.ScheduleParallel(job.generator.JobLength, 1, dependency);
        }
    }
   
}

这段代码定义了一个结构体 MeshJob<G, S>,其中 G 和 S 是泛型类型参数,分别表示用于生成网格的结构体类型和用于保存网格流数据的结构体类型。该结构体实现了 IJobFor 接口,表明该结构体类型可以用于执行并行作业。

在结构体中,有一个 generator 成员变量和一个 streams 成员变量,分别表示用于生成网格的结构体和用于保存网格流数据的结构体。generator 是类型 G 的实例,streams 是类型 S 的实例,并使用 [WriteOnly] 属性进行了标记,表示只在生成网格时写入流,而不从中读取。

结构体中还有一个 Execute 方法,该方法接受一个整数参数 i,并调用 generator.Execute(i, streams) 来生成网格流数据。

该结构体还有一个静态方法 ScheduleParallel,该方法接受一个 Mesh 类型的参数 mesh,一个 Mesh.MeshData 类型的参数 meshData,以及一个 JobHandle 类型的参数 dependency。该方法返回一个 JobHandle 类型的值,表示生成网格作业的句柄。

在方法中,首先创建了一个 MeshJob<G, S> 类型的变量 job。然后,通过调用 streams.Setup() 方法,将 meshData、网格边界、顶点数和索引

在通过上个博客中的资源便可以生成一个四边形了

猜你喜欢

转载自blog.csdn.net/tongmeng_yiran/article/details/129468408