using Unity.Burst; using Unity.Collections; using Unity.Jobs; using Unity.Mathematics; using UnityEngine.Assertions; namespace Pathfinding.Graphs.Navmesh.Jobs { /// /// Calculates node connections between triangles within each tile. /// Connections between tiles are handled at a later stage in . /// [BurstCompile] public struct JobCalculateTriangleConnections : IJob { [ReadOnly] public NativeArray tileMeshes; [WriteOnly] public NativeArray nodeConnections; public struct TileNodeConnectionsUnsafe { /// Stream of packed connection edge infos (from ) public Unity.Collections.LowLevel.Unsafe.UnsafeAppendBuffer neighbours; /// Number of neighbours for each triangle public Unity.Collections.LowLevel.Unsafe.UnsafeAppendBuffer neighbourCounts; } public void Execute () { Assert.AreEqual(tileMeshes.Length, nodeConnections.Length); var nodeRefs = new NativeParallelHashMap(128, Allocator.Temp); bool duplicates = false; for (int ti = 0; ti < tileMeshes.Length; ti++) { nodeRefs.Clear(); var tile = tileMeshes[ti]; var numIndices = tile.triangles.Length; var neighbours = new Unity.Collections.LowLevel.Unsafe.UnsafeAppendBuffer(numIndices * 2 * 4, 4, Allocator.Persistent); var neighbourCounts = new Unity.Collections.LowLevel.Unsafe.UnsafeAppendBuffer(numIndices * 4, 4, Allocator.Persistent); const int TriangleIndexBits = 28; unsafe { Assert.IsTrue(numIndices % 3 == 0); // Access data via the raw pointer to avoid bounds checks var triangles = tile.triangles.ptr; for (int i = 0, j = 0; i < numIndices; i += 3, j++) { duplicates |= !nodeRefs.TryAdd(new int2(triangles[i+0], triangles[i+1]), (uint)j | (0 << TriangleIndexBits)); duplicates |= !nodeRefs.TryAdd(new int2(triangles[i+1], triangles[i+2]), (uint)j | (1 << TriangleIndexBits)); duplicates |= !nodeRefs.TryAdd(new int2(triangles[i+2], triangles[i+0]), (uint)j | (2 << TriangleIndexBits)); } for (int i = 0; i < numIndices; i += 3) { var cnt = 0; for (int edge = 0; edge < 3; edge++) { if (nodeRefs.TryGetValue(new int2(triangles[i+((edge+1) % 3)], triangles[i+edge]), out var match)) { var other = match & ((1 << TriangleIndexBits) - 1); var otherEdge = (int)(match >> TriangleIndexBits); neighbours.Add(other); var edgeInfo = Connection.PackShapeEdgeInfo((byte)edge, (byte)otherEdge, true, true, true); neighbours.Add((int)edgeInfo); cnt += 1; } } neighbourCounts.Add(cnt); } } nodeConnections[ti] = new TileNodeConnectionsUnsafe { neighbours = neighbours, neighbourCounts = neighbourCounts, }; } if (duplicates) { UnityEngine.Debug.LogWarning("Duplicate triangle edges were found in the input mesh. These have been removed. Are you sure your mesh is suitable for being used as a navmesh directly?\nThis could be caused by the mesh's normals not being consistent."); } } } }