using Pathfinding.Util; using Unity.Burst; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Jobs; using UnityEngine; namespace Pathfinding.Graphs.Navmesh.Jobs { /// /// Builds tiles from raw mesh vertices and indices. /// /// This job takes the following steps: /// - Transform all vertices using the matrix. /// - Remove duplicate vertices /// - If is enabled: ensure all triangles are laid out in the clockwise direction. /// [BurstCompile(FloatMode = FloatMode.Default)] public struct JobBuildTileMeshFromVertices : IJob { public NativeArray vertices; public NativeArray indices; public Matrix4x4 meshToGraph; public NativeArray outputBuffers; public bool recalculateNormals; [BurstCompile(FloatMode = FloatMode.Fast)] public struct JobTransformTileCoordinates : IJob { public NativeArray vertices; public NativeArray outputVertices; public Matrix4x4 matrix; public void Execute () { for (int i = 0; i < vertices.Length; i++) { outputVertices[i] = (Int3)matrix.MultiplyPoint3x4(vertices[i]); } } } public struct BuildNavmeshOutput : IProgress, System.IDisposable { public NativeArray tiles; public float Progress => 0.0f; public void Dispose () { for (int i = 0; i < tiles.Length; i++) tiles[i].Dispose(); tiles.Dispose(); } } public static Promise Schedule (NativeArray vertices, NativeArray indices, Matrix4x4 meshToGraph, bool recalculateNormals) { if (vertices.Length > NavmeshBase.VertexIndexMask) throw new System.ArgumentException("Too many vertices in the navmesh graph. Provided " + vertices.Length + ", but the maximum number of vertices per tile is " + NavmeshBase.VertexIndexMask + ". You can raise this limit by enabling ASTAR_RECAST_LARGER_TILES in the A* Inspector Optimizations tab"); var outputBuffers = new NativeArray(1, Allocator.Persistent); var job = new JobBuildTileMeshFromVertices { vertices = vertices, indices = indices, meshToGraph = meshToGraph, outputBuffers = outputBuffers, recalculateNormals = recalculateNormals, }.Schedule(); return new Promise(job, new BuildNavmeshOutput { tiles = outputBuffers, }); } public void Execute () { var int3vertices = new NativeArray(vertices.Length, Allocator.Temp); var tags = new NativeArray(indices.Length / 3, Allocator.Temp, NativeArrayOptions.ClearMemory); new JobTransformTileCoordinates { vertices = vertices, outputVertices = int3vertices, matrix = meshToGraph, }.Execute(); unsafe { UnityEngine.Assertions.Assert.IsTrue(this.outputBuffers.Length == 1); var tile = (TileMesh.TileMeshUnsafe*) this.outputBuffers.GetUnsafePtr(); var outputVertices = &tile->verticesInTileSpace; var outputTriangles = &tile->triangles; var outputTags = &tile->tags; *outputVertices = new UnsafeAppendBuffer(0, 4, Allocator.Persistent); *outputTriangles = new UnsafeAppendBuffer(0, 4, Allocator.Persistent); *outputTags = new UnsafeAppendBuffer(0, 4, Allocator.Persistent); new MeshUtility.JobRemoveDuplicateVertices { vertices = int3vertices, triangles = indices, tags = tags, outputVertices = outputVertices, outputTriangles = outputTriangles, outputTags = outputTags, }.Execute(); if (recalculateNormals) { var verticesSpan = outputVertices->AsUnsafeSpan(); var trianglesSpan = outputTriangles->AsUnsafeSpan(); MeshUtility.MakeTrianglesClockwise(ref verticesSpan, ref trianglesSpan); } } int3vertices.Dispose(); } } }