//Code almost completely ripped from Recast public void FilterLedges(uint voxelWalkableHeight, int voxelWalkableClimb, float cs, float ch, Vector3 min) { int wd = voxelArea.width * voxelArea.depth; #if !ASTAR_RECAST_CLASS_BASED_LINKED_LIST LinkedVoxelSpan[] spans = voxelArea.linkedSpans; int[] DirectionX = voxelArea.DirectionX; int[] DirectionZ = voxelArea.DirectionZ; #endif int width = voxelArea.width; //Filter all ledges for (int z = 0, pz = 0; z < wd; z += width, pz++) { for (int x = 0; x < width; x++) { #if !ASTAR_RECAST_CLASS_BASED_LINKED_LIST if (spans[x + z].bottom == VoxelArea.InvalidSpanValue) { continue; } for (int s = x + z; s != -1; s = spans[s].next) { //Skip non-walkable spans if (spans[s].area == UnwalkableArea) { continue; } int bottom = (int)spans[s].top; int top = spans[s].next != -1 ? (int)spans[spans[s].next].bottom : VoxelArea.MaxHeightInt; int minHeight = VoxelArea.MaxHeightInt; int aMinHeight = (int)spans[s].top; int aMaxHeight = aMinHeight; for (int d = 0; d < 4; d++) { int nx = x + DirectionX[d]; int nz = z + DirectionZ[d]; //Skip out-of-bounds points if (nx < 0 || nz < 0 || nz >= wd || nx >= width) { spans[s].area = UnwalkableArea; break; } int nsx = nx + nz; int nbottom = -voxelWalkableClimb; int ntop = spans[nsx].bottom != VoxelArea.InvalidSpanValue ? (int)spans[nsx].bottom : VoxelArea.MaxHeightInt; if (System.Math.Min(top, ntop) - System.Math.Max(bottom, nbottom) > voxelWalkableHeight) { minHeight = System.Math.Min(minHeight, nbottom - bottom); } //Loop through spans if (spans[nsx].bottom != VoxelArea.InvalidSpanValue) { for (int ns = nsx; ns != -1; ns = spans[ns].next) { nbottom = (int)spans[ns].top; ntop = spans[ns].next != -1 ? (int)spans[spans[ns].next].bottom : VoxelArea.MaxHeightInt; if (System.Math.Min(top, ntop) - System.Math.Max(bottom, nbottom) > voxelWalkableHeight) { minHeight = System.Math.Min(minHeight, nbottom - bottom); if (System.Math.Abs(nbottom - bottom) <= voxelWalkableClimb) { if (nbottom < aMinHeight) { aMinHeight = nbottom; } if (nbottom > aMaxHeight) { aMaxHeight = nbottom; } } } } } } if (minHeight < -voxelWalkableClimb || (aMaxHeight - aMinHeight) > voxelWalkableClimb) { spans[s].area = UnwalkableArea; } } #else for (VoxelSpan s = voxelArea.cells[z + x].firstSpan; s != null; s = s.next) { //Skip non-walkable spans if (s.area == UnwalkableArea) { continue; } int bottom = (int)s.top; int top = s.next != null ? (int)s.next.bottom : VoxelArea.MaxHeightInt; int minHeight = VoxelArea.MaxHeightInt; int aMinHeight = (int)s.top; int aMaxHeight = (int)s.top; for (int d = 0; d < 4; d++) { int nx = x + voxelArea.DirectionX[d]; int nz = z + voxelArea.DirectionZ[d]; //Skip out-of-bounds points if (nx < 0 || nz < 0 || nz >= wd || nx >= voxelArea.width) { s.area = UnwalkableArea; break; } VoxelSpan nsx = voxelArea.cells[nx + nz].firstSpan; int nbottom = -voxelWalkableClimb; int ntop = nsx != null ? (int)nsx.bottom : VoxelArea.MaxHeightInt; if (AstarMath.Min(top, ntop) - AstarMath.Max(bottom, nbottom) > voxelWalkableHeight) { minHeight = AstarMath.Min(minHeight, nbottom - bottom); } //Loop through spans for (VoxelSpan ns = nsx; ns != null; ns = ns.next) { nbottom = (int)ns.top; ntop = ns.next != null ? (int)ns.next.bottom : VoxelArea.MaxHeightInt; if (AstarMath.Min(top, ntop) - AstarMath.Max(bottom, nbottom) > voxelWalkableHeight) { minHeight = AstarMath.Min(minHeight, nbottom - bottom); if (AstarMath.Abs(nbottom - bottom) <= voxelWalkableClimb) { if (nbottom < aMinHeight) { aMinHeight = nbottom; } if (nbottom > aMaxHeight) { aMaxHeight = nbottom; } } } } } if (minHeight < -voxelWalkableClimb || (aMaxHeight - aMinHeight) > voxelWalkableClimb) { s.area = UnwalkableArea; } } #endif } } }
public void BuildVoxelConnections() { AstarProfiler.StartProfile("Build Voxel Connections"); int wd = voxelArea.width * voxelArea.depth; CompactVoxelSpan[] spans = voxelArea.compactSpans; CompactVoxelCell[] cells = voxelArea.compactCells; //Build voxel connections for (int z = 0, pz = 0; z < wd; z += voxelArea.width, pz++) { //System.Threading.ManualResetEvent[] handles = new System.Threading.ManualResetEvent[voxelArea.depth]; //This will run the loop in multiple threads (speedup by ? 40%) //Parallel.For (0, voxelArea.depth, delegate (int pz) { //System.Threading.WaitCallback del = delegate (System.Object _pz) { //int pz = (int)_pz; //int z = pz*voxelArea.width; for (int x = 0; x < voxelArea.width; x++) { CompactVoxelCell c = cells[x + z]; for (int i = (int)c.index, ni = (int)(c.index + c.count); i < ni; i++) { CompactVoxelSpan s = spans[i]; spans[i].con = 0xFFFFFFFF; for (int d = 0; d < 4; d++) { int nx = x + voxelArea.DirectionX[d]; int nz = z + voxelArea.DirectionZ[d]; if (nx < 0 || nz < 0 || nz >= wd || nx >= voxelArea.width) { continue; } CompactVoxelCell nc = cells[nx + nz]; for (int k = (int)nc.index, nk = (int)(nc.index + nc.count); k < nk; k++) { CompactVoxelSpan ns = spans[k]; int bottom = System.Math.Max(s.y, ns.y); int top = AstarMath.Min((int)s.y + (int)s.h, (int)ns.y + (int)ns.h); if ((top - bottom) >= voxelWalkableHeight && System.Math.Abs((int)ns.y - (int)s.y) <= voxelWalkableClimb) { uint connIdx = (uint)k - nc.index; if (connIdx > MaxLayers) { Debug.LogError("Too many layers"); continue; } spans[i].SetConnection(d, connIdx); break; } } } } } //handles[pz].Set (); //}; //}); } /*for (int z=0, pz = 0;z < wd;z += voxelArea.width, pz++) { * handles[pz] = new System.Threading.ManualResetEvent(false); * System.Threading.ThreadPool.QueueUserWorkItem (del, pz); * } * * System.Threading.WaitHandle.WaitAll (handles);*/ AstarProfiler.EndProfile("Build Voxel Connections"); }