/// <summary> /// Find shortest path for every position on grid to target position /// </summary> /// <param name="targetDirections">Result table of all shortest paths for every position on grid to targetPosition</param> /// <param name="rowCount">Height of grid</param> /// <param name="targetPosition">Generate all shortest paths to this position.</param> /// <param name="gridWalls">Table representing walls/obstacles in grid. See: CartesianGridMovement</param> public static void CalculateShortestPathsToTarget(NativeArray <byte> targetDirections, NativeArray <int> targetDistances, int rowCount, CartesianGridCoordinates targetPosition, CartesianGridOnCubeFace cubeFace, byte *gridWalls, float4x4 *faceLocalToLocal) { CalculateShortestWalkableDistancesToTarget(targetDistances, rowCount, gridWalls, targetPosition, cubeFace, faceLocalToLocal); CalculateShortestPathGivenDistancesToTarget(targetDirections, rowCount, targetDistances, gridWalls, faceLocalToLocal); }
static void CalculateShortestWalkableDistancesToTargetInner(NativeArray <int> targetDistances, int rowCount, byte *gridWalls, float4x4 *faceLocalToLocal, UnsafeBitArray pending, UnsafeBitArray closed, UnsafeRingQueue <int> open) { var cellCount = rowCount * rowCount; var maxPathLength = 6 * (cellCount + 1); while (open.Length > 0) { var cellIndex = open.Dequeue(); var cellPosition = CartesianGridOnCubeUtility.CellFaceCoordinates(cellIndex, rowCount); var faceIndex = CartesianGridOnCubeUtility.CellFaceIndex(cellIndex, rowCount); var rowStride = (rowCount + 1) / 2; var faceStride = rowCount * rowStride; var faceGridWallsOffset = faceIndex * faceStride; var validDirections = CartesianGridMovement.ValidDirections(cellPosition, rowCount, rowCount, gridWalls + faceGridWallsOffset); var validNorth = ((validDirections & (byte)CartesianGridDirectionBit.North) != 0); var validSouth = ((validDirections & (byte)CartesianGridDirectionBit.South) != 0); var validWest = ((validDirections & (byte)CartesianGridDirectionBit.West) != 0); var validEast = ((validDirections & (byte)CartesianGridDirectionBit.East) != 0); var cellIndexNorth = CartesianGridOnCubeUtility.CellIndexNorth(cellIndex, rowCount, faceLocalToLocal); var cellIndexSouth = CartesianGridOnCubeUtility.CellIndexSouth(cellIndex, rowCount, faceLocalToLocal); var cellIndexWest = CartesianGridOnCubeUtility.CellIndexWest(cellIndex, rowCount, faceLocalToLocal); var cellIndexEast = CartesianGridOnCubeUtility.CellIndexEast(cellIndex, rowCount, faceLocalToLocal); var distanceNorth = maxPathLength; var distanceSouth = maxPathLength; var distanceEast = maxPathLength; var distanceWest = maxPathLength; var closedNorth = false; var closedSouth = false; var closedWest = false; var closedEast = false; if (validNorth) { if (closed.IsSet(cellIndexNorth)) { distanceNorth = targetDistances[cellIndexNorth]; closedNorth = true; } else if (!pending.IsSet(cellIndexNorth)) { open.Enqueue(cellIndexNorth); pending.Set(cellIndexNorth, true); } } if (validSouth) { if (closed.IsSet(cellIndexSouth)) { distanceSouth = targetDistances[cellIndexSouth]; closedSouth = true; } else if (!pending.IsSet(cellIndexSouth)) { open.Enqueue(cellIndexSouth); pending.Set(cellIndexSouth, true); } } if (validWest) { if (closed.IsSet(cellIndexWest)) { distanceWest = targetDistances[cellIndexWest]; closedWest = true; } else if (!pending.IsSet(cellIndexWest)) { open.Enqueue(cellIndexWest); pending.Set(cellIndexWest, true); } } if (validEast) { if (closed.IsSet(cellIndexEast)) { distanceEast = targetDistances[cellIndexEast]; closedEast = true; } else if (!pending.IsSet(cellIndexEast)) { open.Enqueue(cellIndexEast); pending.Set(cellIndexEast, true); } } var closedNeighbor = closedNorth || closedSouth || closedWest || closedEast; Assert.IsTrue(closedNeighbor); var bestDist = math.cmin(new int4(distanceNorth, distanceSouth, distanceEast, distanceWest)) + 1; Assert.IsFalse(bestDist > (maxPathLength + 1)); targetDistances[cellIndex] = bestDist; closed.Set(cellIndex, true); } }
void VisiblePartial(int index) { var chunk = Chunks[index]; var chunkEntityCount = chunk.Count; var chunkVisibleCount = 0; var chunkLODs = chunk.GetNativeArray(MeshLODComponentType); var chunkBounds = chunk.GetNativeArray(WorldMeshRenderBoundsType); var hasMeshLODComponentType = chunkLODs.Length > 0; var hasWorldMeshRenderBounds = chunkBounds.Length > 0; float4x4 *dstPtr = GetVisibleOutputBuffer(chunk); float4x4 *srcPtr = GetLocalToWorldSourceBuffer(chunk); if (srcPtr == null) { return; } // 00 (-WorldMeshRenderBounds -MeshLODComponentType) if ((!hasWorldMeshRenderBounds) && (!hasMeshLODComponentType)) { for (int i = 0; i < chunkEntityCount; i++) { UnsafeUtility.MemCpy(dstPtr + chunkVisibleCount + i, srcPtr + i, UnsafeUtility.SizeOf <float4x4>()); } chunkVisibleCount = chunkEntityCount; } // 01 (-WorldMeshRenderBounds +MeshLODComponentType) else if ((!hasWorldMeshRenderBounds) && (hasMeshLODComponentType)) { for (int i = 0; i < chunkEntityCount; i++) { var instanceLOD = chunkLODs[i]; var instanceLODValid = (ActiveLODGroupMask[instanceLOD.Group].LODMask & instanceLOD.LODMask) != 0; if (instanceLODValid) { UnsafeUtility.MemCpy(dstPtr + chunkVisibleCount, srcPtr + i, UnsafeUtility.SizeOf <float4x4>()); chunkVisibleCount++; } } } // 10 (+WorldMeshRenderBounds -MeshLODComponentType) else if ((hasWorldMeshRenderBounds) && (!hasMeshLODComponentType)) { for (int i = 0; i < chunkEntityCount; i++) { var instanceBounds = chunkBounds[i]; var instanceCullValid = (Planes.Inside(instanceBounds) != FrustumPlanes.InsideResult.Out); if (instanceCullValid) { UnsafeUtility.MemCpy(dstPtr + chunkVisibleCount, srcPtr + i, UnsafeUtility.SizeOf <float4x4>()); chunkVisibleCount++; } } } // 11 (+WorldMeshRenderBounds +MeshLODComponentType) else { for (int i = 0; i < chunkEntityCount; i++) { var instanceLOD = chunkLODs[i]; var instanceLODValid = (ActiveLODGroupMask[instanceLOD.Group].LODMask & instanceLOD.LODMask) != 0; if (instanceLODValid) { var instanceBounds = chunkBounds[i]; var instanceCullValid = (Planes.Inside(instanceBounds) != FrustumPlanes.InsideResult.Out); if (instanceCullValid) { UnsafeUtility.MemCpy(dstPtr + chunkVisibleCount, srcPtr + i, UnsafeUtility.SizeOf <float4x4>()); chunkVisibleCount++; } } } } ChunkVisibleCount[index] = chunkVisibleCount; }
// Sample valid neighboring distances from point. // - Smallest distance less than current position's distance is best next path to target. // - May result in more than one best direction (any of NSWE) // - May result in no best direction if on island (result=0xff) static void CalculateShortestPathGivenDistancesToTarget(NativeArray <byte> targetDirections, int rowCount, NativeArray <int> cellDistances, byte *gridWalls, float4x4 *faceLocalToLocal) { var cellCount = rowCount * rowCount; var maxPathLength = 6 * (cellCount + 1); for (int i = 0; i < targetDirections.Length; i++) { targetDirections[i] = 0; } for (var cellIndex = 0; cellIndex < (6 * cellCount); cellIndex++) { var cellPosition = CartesianGridOnCubeUtility.CellFaceCoordinates(cellIndex, rowCount); var faceIndex = CartesianGridOnCubeUtility.CellFaceIndex(cellIndex, rowCount); var rowStride = (rowCount + 1) / 2; var faceStride = rowCount * rowStride; var faceGridWallsOffset = faceIndex * faceStride; var validDirections = CartesianGridMovement.ValidDirections(cellPosition, rowCount, rowCount, gridWalls + faceGridWallsOffset); var validNorth = ((validDirections & (byte)CartesianGridDirectionBit.North) != 0); var validSouth = ((validDirections & (byte)CartesianGridDirectionBit.South) != 0); var validWest = ((validDirections & (byte)CartesianGridDirectionBit.West) != 0); var validEast = ((validDirections & (byte)CartesianGridDirectionBit.East) != 0); var cellIndexNorth = CartesianGridOnCubeUtility.CellIndexNorth(cellIndex, rowCount, faceLocalToLocal); var cellIndexSouth = CartesianGridOnCubeUtility.CellIndexSouth(cellIndex, rowCount, faceLocalToLocal); var cellIndexWest = CartesianGridOnCubeUtility.CellIndexWest(cellIndex, rowCount, faceLocalToLocal); var cellIndexEast = CartesianGridOnCubeUtility.CellIndexEast(cellIndex, rowCount, faceLocalToLocal); var distanceNorth = maxPathLength; var distanceSouth = maxPathLength; var distanceEast = maxPathLength; var distanceWest = maxPathLength; if (validNorth) { distanceNorth = cellDistances[cellIndexNorth]; } if (validSouth) { distanceSouth = cellDistances[cellIndexSouth]; } if (validWest) { distanceWest = cellDistances[cellIndexWest]; } if (validEast) { distanceEast = cellDistances[cellIndexEast]; } var bestDist = math.cmin(new int4(distanceNorth, distanceSouth, distanceEast, distanceWest)); var dist = cellDistances[cellIndex]; if ((bestDist < dist) && (bestDist < maxPathLength)) { var bestDir = 0; if (distanceNorth == bestDist) { bestDir |= (byte)CartesianGridDirectionBit.North; } if (distanceSouth == bestDist) { bestDir |= (byte)CartesianGridDirectionBit.South; } if (distanceWest == bestDist) { bestDir |= (byte)CartesianGridDirectionBit.West; } if (distanceEast == bestDist) { bestDir |= (byte)CartesianGridDirectionBit.East; } var targetDirectionsIndex = (faceIndex * faceStride) + (cellPosition.y * rowStride) + (cellPosition.x / 2); targetDirections[targetDirectionsIndex] |= (byte)(bestDir << (4 * (cellPosition.x & 1))); } } }
// Simple grassfire to calculate shortest distance along path to target position for every position. // - i.e. breadth-first expansion from target position. static void CalculateShortestWalkableDistancesToTarget(NativeArray <int> targetDistances, int rowCount, byte *gridWalls, CartesianGridCoordinates targetPosition, CartesianGridOnCubeFace cubeFace, float4x4 *faceLocalToLocal) { var cellCount = rowCount * rowCount; var closed = new UnsafeBitArray(6 * cellCount, Allocator.Temp, NativeArrayOptions.ClearMemory); var pending = new UnsafeBitArray(6 * cellCount, Allocator.Temp, NativeArrayOptions.ClearMemory); var open = new UnsafeRingQueue <int>(6 * cellCount, Allocator.Temp); var faceIndex = cubeFace.Value; var faceTargetCellIndex = (targetPosition.y * rowCount) + targetPosition.x; for (int i = 0; i < targetDistances.Length; i++) { targetDistances[i] = -1; } var targetCellIndex = (faceIndex * cellCount) + faceTargetCellIndex; targetDistances[targetCellIndex] = 0; pending.Set(targetCellIndex, true); closed.Set(targetCellIndex, true); var cellIndexNorth = CartesianGridOnCubeUtility.CellIndexNorth(targetCellIndex, rowCount, faceLocalToLocal); var cellIndexSouth = CartesianGridOnCubeUtility.CellIndexSouth(targetCellIndex, rowCount, faceLocalToLocal); var cellIndexWest = CartesianGridOnCubeUtility.CellIndexWest(targetCellIndex, rowCount, faceLocalToLocal); var cellIndexEast = CartesianGridOnCubeUtility.CellIndexEast(targetCellIndex, rowCount, faceLocalToLocal); var rowStride = (rowCount + 1) / 2; var faceStride = rowCount * rowStride; var faceGridWallsOffset = faceIndex * faceStride; var validDirections = CartesianGridMovement.ValidDirections(targetPosition, rowCount, rowCount, gridWalls + faceGridWallsOffset); var validNorth = ((validDirections & (byte)CartesianGridDirectionBit.North) != 0); var validSouth = ((validDirections & (byte)CartesianGridDirectionBit.South) != 0); var validWest = ((validDirections & (byte)CartesianGridDirectionBit.West) != 0); var validEast = ((validDirections & (byte)CartesianGridDirectionBit.East) != 0); if (validNorth) { open.Enqueue(cellIndexNorth); pending.Set(cellIndexNorth, true); } if (validSouth) { open.Enqueue(cellIndexSouth); pending.Set(cellIndexSouth, true); } if (validWest) { open.Enqueue(cellIndexWest); pending.Set(cellIndexWest, true); } if (validEast) { open.Enqueue(cellIndexEast); pending.Set(cellIndexEast, true); } CalculateShortestWalkableDistancesToTargetInner(targetDistances, rowCount, gridWalls, faceLocalToLocal, pending, closed, open); closed.Dispose(); pending.Dispose(); open.Dispose(); }
public static void FillCubeFaceTransforms(int rowCount, float4x4 *faceLocalToWorld, float4x4 *faceWorldToLocal, float4x4 *faceLocalToLocal) { for (int faceIndex = 0; faceIndex < 6; faceIndex++) { ref var localToWorld = ref m_FaceLocalToWorldRotation[faceIndex]; // Translate along normal of face by width localToWorld.c3.xyz = localToWorld.c1.xyz * rowCount * 0.5f; faceLocalToWorld[faceIndex] = localToWorld; faceWorldToLocal[faceIndex] = math.fastinverse(faceLocalToWorld[faceIndex]); }
public static NativeList <RayIntersectResult> RayIntersectToMesh(int *triangles, int triangleCount, MeshAppdata *appdatas, float3 origin, float3 dir, float4x4 *transformMatrix, Allocator alloc) { NativeList <RayIntersectResult> allResults = new NativeList <RayIntersectResult>(triangleCount, alloc); RayIntersectJob jb = new RayIntersectJob { appdatas = appdatas, dir = dir, origin = origin, results = allResults, triangles = triangles, transformMatrix = transformMatrix }; jb.Schedule(triangleCount, max(1, triangleCount / 10)).Complete(); return(allResults); }
public static bool RayIntersectToMesh(int *triangles, int triangleCount, MeshAppdata *appdatas, float3 origin, float3 dir, float4x4 *transformMatrix, out RayIntersectResult result) { NativeList <RayIntersectResult> allResults = new NativeList <RayIntersectResult>(triangleCount, Allocator.Temp); RayIntersectJob jb = new RayIntersectJob { appdatas = appdatas, dir = dir, origin = origin, results = allResults, triangles = triangles, transformMatrix = transformMatrix }; jb.Schedule(triangleCount, max(1, triangleCount / 10)).Complete(); if (allResults.Length <= 0) { result = new RayIntersectResult(); return(false); } float minT = allResults[0].t; int index = 0; for (int i = 1; i < allResults.Length; ++i) { if (minT > allResults[i].t) { index = i; } } result = allResults[index]; return(true); }
public static unsafe void TestIdentityFloat4x4(float4x4 *mat) { *mat = float4x4.identity; }
public static unsafe void TestStaticLoad(float4x4 *mat) { *mat = StaticMat; }
public static unsafe void TestLookAt(float4x4 *mat) { *mat = float4x4.LookAt(new float3(0, 0, 1), new float3(0, 1, 0), new float3(1, 0, 0)); }