Missing changes from previous commit. Added dtNavMesh.findLocalNeighbourhood() and dtNavMesh.getPolyWallSegments() and test code for them.

This commit is contained in:
Mikko Mononen 2010-08-09 13:28:26 +00:00
parent 1c4755012f
commit 81c0402116
10 changed files with 2015 additions and 352 deletions

View File

@ -385,7 +385,7 @@ static void calcRect(const float* va, const float* vb,
static void drawMeshTilePortal(duDebugDraw* dd, const dtMeshTile* tile)
{
// Draw portals
const float padx = 0.01f;
const float padx = 0.02f;
const float pady = tile->header->walkableClimb;
dd->begin(DU_DRAW_LINES, 2.0f);
@ -414,7 +414,7 @@ static void drawMeshTilePortal(duDebugDraw* dd, const dtMeshTile* tile)
{
unsigned int col = side == 0 ? duRGBA(128,0,0,128) : duRGBA(128,0,128,128);
const float x = va[0] + ((side == 0) ? -0.02f : 0.02f);
const float x = va[0] + ((side == 0) ? -padx : padx);
dd->vertex(x,va[1]-pady,va[2], col);
dd->vertex(x,va[1]+pady,va[2], col);
@ -450,7 +450,7 @@ static void drawMeshTilePortal(duDebugDraw* dd, const dtMeshTile* tile)
{
unsigned int col = side == 2 ? duRGBA(0,128,0,128) : duRGBA(0,128,128,128);
const float z = va[2] + ((side == 2) ? -0.02f : 0.02f);
const float z = va[2] + ((side == 2) ? -padx : padx);
dd->vertex(va[0],va[1]-pady,z, col);
dd->vertex(va[0],va[1]+pady,z, col);

View File

@ -201,6 +201,8 @@ bool dtIntersectSegmentPoly2D(const float* p0, const float* p1,
float& tmin, float& tmax,
int& segMin, int& segMax);
bool dtPointInPolygon(const float* pt, const float* verts, const int nverts);
bool dtDistancePtPolyEdgesSqr(const float* pt, const float* verts, const int nverts,
float* ed, float* et);
@ -208,4 +210,7 @@ float dtDistancePtSegSqr2D(const float* pt, const float* p, const float* q, floa
void dtCalcPolyCenter(float* tc, const unsigned short* idx, int nidx, const float* verts);
bool dtOverlapPolyPoly2D(const float* polya, const int npolya,
const float* polyb, const int npolyb);
#endif // DETOURCOMMON_H

View File

@ -324,19 +324,24 @@ public:
const dtPolyRef* path, const int pathSize,
float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
const int maxStraightPathSize) const;
// Moves towards end position a long the path corridor.
// The start location is assumed to be roughly at inside the first polygon on the path.
// The return value can be used to advance the path pointer along the path.
// Moves from startPos to endPos constrained to the navmesh.
// If the endPos is reachable, the resultPos will be endPos,
// or else the resultPos will be the nearest point in navmesh.
// Note: The resulting point is not projected to the ground, use getPolyHeight() to get height.
// Note: The algorithm is optimized for small delta movement and small number of polygons.
// Params:
// startPos[3] - (in) current position of the agent.
// endPos[3] - (in) new position of the agent.
// resultPos[3] - (out) new positio after the move, constrained to be inside the path polygons.
// path - (in) remainder of the path to follow.
// pathSize - (in) number of polygons on the path.
// Returns: Index to the path polygon where the result position lies.
int moveAlongPathCorridor(const float* startPos, const float* endPos, float* resultPos,
const dtPolyRef* path, const int pathSize) const;
// startRef - (in) ref to the polygon where startPos lies.
// startPos[3] - (in) start position of the mover.
// endPos[3] - (in) desired end position of the mover.
// filter - (in) path polygon filter.
// resultPos[3] - (out) new position of the mover.
// visited - (out) array of visited polygons.
// maxVisitedSize - (in) max number of polygons in the visited array.
// Returns: Number of entries in the visited array.
int moveAlongSurface(dtPolyRef startRef, const float* startPos, const float* endPos,
const dtQueryFilter* filter,
float* resultPos, dtPolyRef* visited, const int maxVisitedSize) const;
// Casts 'walkability' ray along the navmesh surface from startPos towards the endPos.
// Params:
@ -375,7 +380,7 @@ public:
// resultCost - (out, opt) search cost at each result polygon.
// maxResult - (int) maximum capacity of search results.
// Returns: Number of results.
int findPolysAroundCircle(dtPolyRef startRef, const float* centerPos, float radius,
int findPolysAroundCircle(dtPolyRef startRef, const float* centerPos, const float radius,
const dtQueryFilter* filter,
dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost,
const int maxResult) const;
@ -396,6 +401,29 @@ public:
dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost,
const int maxResult) const;
// Finds non-overlapping local neighbourhood around center location.
// Note: The algorithm is optimized for small query radius and small number of polygons.
// Params:
// startRef - (in) ref to the polygon where the search starts.
// centerPos[3] - (in) center if the query circle.
// radius - (in) radius of the query circle.
// filter - (in) path polygon filter.
// resultRef - (out) refs to the polygons touched by the circle.
// resultParent - (out, opt) parent of each result polygon.
// maxResult - (int) maximum capacity of search results.
// Returns: Number of results.
int findLocalNeighbourhood(dtPolyRef startRef, const float* centerPos, const float radius,
const dtQueryFilter* filter,
dtPolyRef* resultRef, dtPolyRef* resultParent, const int maxResult) const;
// Returns wall segments of specified polygon.
// Params:
// ref - (in) ref to the polygon.
// filter - (in) path polygon filter.
// segments[DT_VERTS_PER_POLYGON*3*2] - (out) wall segments.
// Returns: Number of wall segments.
int getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* filter, float* segments);
// Returns closest point on navigation polygon.
// Uses detail polygons to find the closest point to the navigation polygon surface.
// Params:
@ -561,6 +589,7 @@ private:
float m_areaCost[DT_MAX_AREAS]; // Cost per area.
class dtNodePool* m_tinyNodePool; // Pointer to node pool.
class dtNodePool* m_nodePool; // Pointer to node pool.
class dtNodeQueue* m_openList; // Pointer to open list queue.
};

View File

@ -238,6 +238,22 @@ bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b
return false;
}
bool dtPointInPolygon(const float* pt, const float* verts, const int nverts)
{
// TODO: Replace pnpoly with triArea2D tests?
int i, j;
bool c = false;
for (i = 0, j = nverts-1; i < nverts; j = i++)
{
const float* vi = &verts[i*3];
const float* vj = &verts[j*3];
if (((vi[2] > pt[2]) != (vj[2] > pt[2])) &&
(pt[0] < (vj[0]-vi[0]) * (pt[2]-vi[2]) / (vj[2]-vi[2]) + vi[0]) )
c = !c;
}
return c;
}
bool dtDistancePtPolyEdgesSqr(const float* pt, const float* verts, const int nverts,
float* ed, float* et)
{
@ -255,3 +271,59 @@ bool dtDistancePtPolyEdgesSqr(const float* pt, const float* verts, const int nve
}
return c;
}
static void projectPoly(const float* axis, const float* poly, const int npoly,
float& rmin, float& rmax)
{
rmin = rmax = dtVdot2D(axis, &poly[0]);
for (int i = 1; i < npoly; ++i)
{
const float d = dtVdot2D(axis, &poly[i*3]);
rmin = dtMin(rmin, d);
rmax = dtMax(rmax, d);
}
}
inline bool overlapRange(const float amin, const float amax,
const float bmin, const float bmax,
const float eps)
{
return ((amin+eps) > bmax || (amax-eps) < bmin) ? false : true;
}
bool dtOverlapPolyPoly2D(const float* polya, const int npolya,
const float* polyb, const int npolyb)
{
const float eps = 1e-4f;
for (int i = 0, j = npolya-1; i < npolya; j=i++)
{
const float* va = &polya[j*3];
const float* vb = &polya[i*3];
const float n[3] = { vb[2]-va[2], 0, -(vb[0]-va[0]) };
float amin,amax,bmin,bmax;
projectPoly(n, polya, npolya, amin,amax);
projectPoly(n, polyb, npolyb, bmin,bmax);
if (!overlapRange(amin,amax, bmin,bmax, eps))
{
// Found separating axis
return false;
}
}
for (int i = 0, j = npolyb-1; i < npolyb; j=i++)
{
const float* va = &polyb[j*3];
const float* vb = &polyb[i*3];
const float n[3] = { vb[2]-va[2], 0, -(vb[0]-va[0]) };
float amin,amax,bmin,bmax;
projectPoly(n, polya, npolya, amin,amax);
projectPoly(n, polyb, npolyb, bmin,bmax);
if (!overlapRange(amin,amax, bmin,bmax, eps))
{
// Found separating axis
return false;
}
}
return true;
}

View File

@ -176,6 +176,7 @@ dtNavMesh::dtNavMesh() :
m_saltBits(0),
m_tileBits(0),
m_polyBits(0),
m_tinyNodePool(0),
m_nodePool(0),
m_openList(0)
{
@ -198,8 +199,10 @@ dtNavMesh::~dtNavMesh()
m_tiles[i].dataSize = 0;
}
}
m_tinyNodePool->~dtNodePool();
m_nodePool->~dtNodePool();
m_openList->~dtNodeQueue();
dtFree(m_tinyNodePool);
dtFree(m_nodePool);
dtFree(m_openList);
dtFree(m_posLookup);
@ -242,6 +245,13 @@ bool dtNavMesh::init(const dtNavMeshParams* params)
if (!m_nodePool)
return false;
}
if (!m_tinyNodePool)
{
m_tinyNodePool = new (dtAlloc(sizeof(dtNodePool), DT_ALLOC_PERM)) dtNodePool(64, 32);
if (!m_tinyNodePool)
return false;
}
// TODO: check the open list size too.
if (!m_openList)
@ -1762,100 +1772,170 @@ int dtNavMesh::findStraightPath(const float* startPos, const float* endPos,
return straightPathSize;
}
// Moves towards end position a long the path corridor.
// Returns: Index to the result path polygon.
int dtNavMesh::moveAlongPathCorridor(const float* startPos, const float* endPos, float* resultPos,
const dtPolyRef* path, const int pathSize) const
int dtNavMesh::moveAlongSurface(dtPolyRef startRef, const float* startPos, const float* endPos,
const dtQueryFilter* filter,
float* resultPos, dtPolyRef* visited, const int maxVisitedSize) const
{
if (!pathSize)
return 0;
float verts[DT_VERTS_PER_POLYGON*3];
float edged[DT_VERTS_PER_POLYGON];
float edget[DT_VERTS_PER_POLYGON];
int n = 0;
static const float SLOP = 0.01f;
if (!startRef) return 0;
if (!getPolyByRef(startRef)) return 0;
if (!m_tinyNodePool) return 0;
dtVcopy(resultPos, startPos);
static const int MAX_STACK = 48;
dtNode* stack[MAX_STACK];
int nstack = 0;
while (n < pathSize)
{
// Get current polygon and poly vertices.
unsigned int salt, it, ip;
decodePolyId(path[n], salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return n;
if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return n;
if (ip >= (unsigned int)m_tiles[it].header->polyCount) return n;
const dtMeshTile* tile = &m_tiles[it];
const dtPoly* poly = &tile->polys[ip];
m_tinyNodePool->clear();
dtNode* startNode = m_tinyNodePool->getNode(startRef);
startNode->pidx = 0;
startNode->cost = 0;
startNode->total = 0;
startNode->id = startRef;
startNode->flags = DT_NODE_CLOSED;
stack[nstack++] = startNode;
// In case of Off-Mesh link, just snap to the end location and advance over it.
if (poly->type == DT_POLYTYPE_OFFMESH_CONNECTION)
{
if (n+1 < pathSize)
{
float left[3], right[3];
unsigned char fromType, toType;
if (!getPortalPoints(path[n], path[n+1], left, right, fromType, toType))
return n;
dtVcopy(resultPos, endPos);
}
return n+1;
}
float bestPos[3];
float bestDist = FLT_MAX;
dtNode* bestNode = 0;
dtVcopy(bestPos, startPos);
// Search constraints
float searchPos[3], searchRadSqr;
dtVlerp(searchPos, startPos, endPos, 0.5f);
searchRadSqr = dtSqr(dtVdist(startPos, endPos)/2.0f + 0.001f);
unsigned int it, ip;
float verts[DT_VERTS_PER_POLYGON*3];
while (nstack)
{
// Pop front.
dtNode* curNode = stack[0];
for (int i = 0; i < nstack-1; ++i)
stack[i] = stack[i+1];
nstack--;
// Get poly and tile.
// The API input has been cheked already, skip checking internal data.
const dtPolyRef curRef = curNode->id;
it = decodePolyIdTile(curRef);
ip = decodePolyIdPoly(curRef);
const dtMeshTile* curTile = &m_tiles[it];
const dtPoly* curPoly = &curTile->polys[ip];
// Collect vertices.
int nv = 0;
for (int i = 0; i < (int)poly->vertCount; ++i)
const int nverts = curPoly->vertCount;
for (int i = 0; i < nverts; ++i)
dtVcopy(&verts[i*3], &curTile->verts[curPoly->verts[i]*3]);
// If target is inside the poly, stop search.
if (dtPointInPolygon(endPos, verts, nverts))
{
dtVcopy(&verts[nv*3], &tile->verts[poly->verts[i]*3]);
nv++;
bestNode = curNode;
dtVcopy(bestPos, endPos);
break;
}
const bool inside = dtDistancePtPolyEdgesSqr(endPos, verts, nv, edged, edget);
if (inside)
// Find wall edges and find nearest point inside the walls.
for (int i = 0, j = (int)curPoly->vertCount-1; i < (int)curPoly->vertCount; j = i++)
{
// The end point is inside the current polygon.
dtVcopy(resultPos, endPos);
return n;
}
// Constraint the point on the polygon boundary.
// This results sliding movement.
float dmin = FLT_MAX;
int imin = -1;
for (int i = 0; i < nv; ++i)
{
if (edged[i] < dmin)
// Skip non-solid edges.
dtPolyRef neighbourRef = 0;
if (curPoly->neis[j] & DT_EXT_LINK)
{
dmin = edged[i];
imin = i;
// Tile border.
for (unsigned int k = curPoly->firstLink; k != DT_NULL_LINK; k = curTile->links[k].next)
{
const dtLink* link = &curTile->links[k];
if (link->edge == j)
{
if (link->ref != 0 && passFilter(filter, getPolyFlags(link->ref)))
neighbourRef = link->ref;
break;
}
}
}
else if (curPoly->neis[j] && passFilter(filter, curTile->polys[curPoly->neis[j]-1].flags))
{
// Internal edge, encode id.
neighbourRef = getTilePolyRefBase(curTile) | (unsigned int)(curPoly->neis[j]-1);
}
if (!neighbourRef)
{
// Wall edge, calc distance.
const float* vj = &verts[j*3];
const float* vi = &verts[i*3];
float tseg;
const float distSqr = dtDistancePtSegSqr2D(endPos, vj, vi, tseg);
if (distSqr < bestDist)
{
// Update nearest distance.
dtVlerp(bestPos, vj,vi, tseg);
bestDist = distSqr;
bestNode = curNode;
}
}
else
{
// Skip if no node can be allocated.
dtNode* neighbourNode = m_tinyNodePool->getNode(neighbourRef);
if (!neighbourNode)
continue;
// Skip if already visited.
if (neighbourNode->flags & DT_NODE_CLOSED)
continue;
// Skip the link if it is too far from search constraint.
const float* vj = &verts[j*3];
const float* vi = &verts[i*3];
float tseg;
float distSqr = dtDistancePtSegSqr2D(searchPos, vj, vi, tseg);
if (distSqr > searchRadSqr)
continue;
// Mark as the node as visited and push to queue.
if (nstack < MAX_STACK)
{
neighbourNode->pidx = m_tinyNodePool->getNodeIdx(curNode);
neighbourNode->flags |= DT_NODE_CLOSED;
stack[nstack++] = neighbourNode;
}
}
}
const float* va = &verts[imin*3];
const float* vb = &verts[((imin+1)%nv)*3];
dtVlerp(resultPos, va, vb, edget[imin]);
// Check to see if the point is on the portal edge to the next polygon.
if (n+1 >= pathSize)
return n;
// TODO: optimize
float left[3], right[3];
unsigned char fromType, toType;
if (!getPortalPoints(path[n], path[n+1], left, right, fromType, toType))
return n;
// If the dtClamped point is close to the next portal edge, advance to next poly.
float t;
const float d = dtDistancePtSegSqr2D(resultPos, left, right, t);
if (d > SLOP*SLOP)
return n;
// Advance to next polygon.
n++;
}
int n = 0;
if (bestNode)
{
// Reverse the path.
dtNode* prev = 0;
dtNode* node = bestNode;
do
{
dtNode* next = m_tinyNodePool->getNodeAtIdx(node->pidx);
node->pidx = m_tinyNodePool->getNodeIdx(prev);
prev = node;
node = next;
}
while (node);
// Store result
node = prev;
do
{
visited[n++] = node->id;
node = m_tinyNodePool->getNodeAtIdx(node->pidx);
}
while (node && n < maxVisitedSize);
}
dtVcopy(resultPos, bestPos);
return n;
}
bool dtNavMesh::getPortalPoints(dtPolyRef from, dtPolyRef to, float* left, float* right,
unsigned char& fromType, unsigned char& toType) const
{
@ -2198,7 +2278,8 @@ int dtNavMesh::raycast(dtPolyRef centerRef, const float* startPos, const float*
return n;
}
int dtNavMesh::findPolysAroundCircle(dtPolyRef centerRef, const float* centerPos, float radius, const dtQueryFilter* filter,
int dtNavMesh::findPolysAroundCircle(dtPolyRef centerRef, const float* centerPos, const float radius,
const dtQueryFilter* filter,
dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost,
const int maxResult) const
{
@ -2497,6 +2578,217 @@ int dtNavMesh::findPolysAroundShape(dtPolyRef centerRef, const float* verts, con
return n;
}
int dtNavMesh::findLocalNeighbourhood(dtPolyRef centerRef, const float* centerPos, const float radius,
const dtQueryFilter* filter,
dtPolyRef* resultRef, dtPolyRef* resultParent, const int maxResult) const
{
if (!centerRef) return 0;
if (!getPolyByRef(centerRef)) return 0;
if (!m_tinyNodePool) return 0;
static const int MAX_STACK = 48;
dtNode* stack[MAX_STACK];
int nstack = 0;
m_tinyNodePool->clear();
dtNode* startNode = m_tinyNodePool->getNode(centerRef);
startNode->pidx = 0;
startNode->id = centerRef;
startNode->flags = DT_NODE_CLOSED;
stack[nstack++] = startNode;
const float radiusSqr = dtSqr(radius);
float pa[DT_VERTS_PER_POLYGON*3];
float pb[DT_VERTS_PER_POLYGON*3];
unsigned int it, ip;
int n = 0;
if (n < maxResult)
{
resultRef[n] = startNode->id;
if (resultParent)
resultParent[n] = 0;
++n;
}
while (nstack)
{
// Pop front.
dtNode* curNode = stack[0];
for (int i = 0; i < nstack-1; ++i)
stack[i] = stack[i+1];
nstack--;
// Get poly and tile.
// The API input has been cheked already, skip checking internal data.
const dtPolyRef curRef = curNode->id;
it = decodePolyIdTile(curRef);
ip = decodePolyIdPoly(curRef);
const dtMeshTile* curTile = &m_tiles[it];
const dtPoly* curPoly = &curTile->polys[ip];
for (unsigned int i = curPoly->firstLink; i != DT_NULL_LINK; i = curTile->links[i].next)
{
const dtLink* link = &curTile->links[i];
dtPolyRef neighbourRef = link->ref;
// Skip invalid neighbours.
if (!neighbourRef)
continue;
// Skip if cannot alloca more nodes.
dtNode* neighbourNode = m_tinyNodePool->getNode(neighbourRef);
if (!neighbourNode)
continue;
// Skip visited.
if (neighbourNode->flags & DT_NODE_CLOSED)
continue;
// Expand to neighbour
it = decodePolyIdTile(neighbourRef);
ip = decodePolyIdPoly(neighbourRef);
const dtMeshTile* neighbourTile = &m_tiles[it];
const dtPoly* neighbourPoly = &neighbourTile->polys[ip];
// Skip off-mesh connections.
if (neighbourPoly->type == DT_POLYTYPE_OFFMESH_CONNECTION)
continue;
// Do not advance if the polygon is excluded by the filter.
if (!passFilter(filter, neighbourPoly->flags))
continue;
// Find edge and calc distance to the edge.
float va[3], vb[3];
if (!getPortalPoints(curRef, curPoly, curTile, neighbourRef, neighbourPoly, neighbourTile, va, vb))
continue;
// If the circle is not touching the next polygon, skip it.
float tseg;
float distSqr = dtDistancePtSegSqr2D(centerPos, va, vb, tseg);
if (distSqr > radiusSqr)
continue;
// Mark node visited, this is done before the overlap test so that
// we will not visit the poly again if the test fails.
neighbourNode->flags |= DT_NODE_CLOSED;
neighbourNode->pidx = m_tinyNodePool->getNodeIdx(curNode);
// Check that the polygon does not collide with existing polygons.
// Collect vertices of the neighbour poly.
const int npa = neighbourPoly->vertCount;
for (int k = 0; k < npa; ++k)
dtVcopy(&pa[k*3], &neighbourTile->verts[neighbourPoly->verts[k]*3]);
bool overlap = false;
for (int j = 0; j < n; ++j)
{
dtPolyRef pastRef = resultRef[j];
// Connected polys do not overlap.
bool areConnected = false;
for (unsigned int k = curPoly->firstLink; k != DT_NULL_LINK; k = curTile->links[k].next)
{
if (curTile->links[k].ref == pastRef)
{
areConnected = true;
break;
}
}
if (areConnected)
continue;
// Potentially overlapping.
it = decodePolyIdTile(pastRef);
ip = decodePolyIdPoly(pastRef);
const dtMeshTile* pastTile = &m_tiles[it];
const dtPoly* pastPoly = &pastTile->polys[ip];
// Get vertices and test overlap
const int npb = pastPoly->vertCount;
for (int k = 0; k < npb; ++k)
dtVcopy(&pb[k*3], &pastTile->verts[pastPoly->verts[k]*3]);
if (dtOverlapPolyPoly2D(pa,npa, pb,npb))
{
overlap = true;
break;
}
}
if (overlap)
continue;
// This poly is fine, store and advance to the poly.
if (n < maxResult)
{
resultRef[n] = neighbourRef;
if (resultParent)
resultParent[n] = curRef;
++n;
}
if (nstack < MAX_STACK)
{
stack[nstack++] = neighbourNode;
}
}
}
return n;
}
int dtNavMesh::getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* filter, float* segments)
{
unsigned int salt, it, ip;
decodePolyId(ref, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return 0;
const dtMeshTile* tile = &m_tiles[it];
if (tile->salt != salt || tile->header == 0) return 0;
if (ip >= (unsigned int)tile->header->polyCount) return 0;
const dtPoly* poly = &tile->polys[ip];
int n = 0;
for (int i = 0, j = (int)poly->vertCount-1; i < (int)poly->vertCount; j = i++)
{
// Skip non-solid edges.
if (poly->neis[j] & DT_EXT_LINK)
{
// Tile border.
bool solid = true;
for (unsigned int k = poly->firstLink; k != DT_NULL_LINK; k = tile->links[k].next)
{
const dtLink* link = &tile->links[k];
if (link->edge == j)
{
if (link->ref != 0 && passFilter(filter, getPolyFlags(link->ref)))
solid = false;
break;
}
}
if (!solid) continue;
}
else if (poly->neis[j] && passFilter(filter, tile->polys[poly->neis[j]-1].flags))
{
// Internal edge
continue;
}
// Store segment.
const float* vj = &tile->verts[poly->verts[j]*3];
const float* vi = &tile->verts[poly->verts[i]*3];
float* seg = &segments[n*6];
n++;
dtVcopy(seg+0, vj);
dtVcopy(seg+3, vi);
}
return n;
}
float dtNavMesh::findDistanceToWall(dtPolyRef centerRef, const float* centerPos, float maxRadius, const dtQueryFilter* filter,
float* hitPos, float* hitNormal) const
{
@ -2574,7 +2866,7 @@ float dtNavMesh::findDistanceToWall(dtPolyRef centerRef, const float* centerPos,
}
if (!solid) continue;
}
else if (bestPoly->neis[j] && passFilter(filter, bestTile->polys[bestPoly->neis[j]].flags))
else if (bestPoly->neis[j] && passFilter(filter, bestTile->polys[bestPoly->neis[j]-1].flags))
{
// Internal edge
continue;

File diff suppressed because it is too large Load Diff

View File

@ -283,8 +283,8 @@
<key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
<array>
<array>
<integer>14</integer>
<integer>11</integer>
<integer>10</integer>
<integer>2</integer>
<integer>1</integer>
<integer>0</integer>
</array>
@ -337,7 +337,7 @@
<key>_historyCapacity</key>
<integer>0</integer>
<key>bookmark</key>
<string>6BAF3A3112101D4B008CFCDF</string>
<string>6BAF3AC3121039C7008CFCDF</string>
<key>history</key>
<array>
<string>6BBB4AA1115B4F3400CF791D</string>
@ -357,7 +357,6 @@
<string>6BF5F31C117490A1000502A6</string>
<string>6BF5F32E11759C3C000502A6</string>
<string>6BF5F474117644A2000502A6</string>
<string>6BF5F475117644A2000502A6</string>
<string>6BF5F5041176F5F8000502A6</string>
<string>6B4214D911803923006C347B</string>
<string>6B2CDC911197F0720090FA4D</string>
@ -380,7 +379,6 @@
<string>6BF9B1F211EC43FC0043574C</string>
<string>6BF9B20B11EC450E0043574C</string>
<string>6BF9B21211EC49A30043574C</string>
<string>6BF9B21311EC49A30043574C</string>
<string>6BF9B21B11EC49F90043574C</string>
<string>6BAF37D411FEAC16008CFCDF</string>
<string>6BAF37F911FEB4BB008CFCDF</string>
@ -395,20 +393,21 @@
<string>6BAF3873120AD32F008CFCDF</string>
<string>6BAF3874120AD32F008CFCDF</string>
<string>6BAF3875120AD32F008CFCDF</string>
<string>6BAF38F2120FD8CC008CFCDF</string>
<string>6BAF390F120FEB27008CFCDF</string>
<string>6BAF3910120FEB27008CFCDF</string>
<string>6BAF3938120FEF30008CFCDF</string>
<string>6BAF3971120FF609008CFCDF</string>
<string>6BAF39D012100A22008CFCDF</string>
<string>6BAF39D112100A22008CFCDF</string>
<string>6BAF39D212100A22008CFCDF</string>
<string>6BAF39DB12100D84008CFCDF</string>
<string>6BAF39E712100DE4008CFCDF</string>
<string>6BAF39F012100ED1008CFCDF</string>
<string>6BAF39F112100ED1008CFCDF</string>
<string>6BAF3A2E12101D4B008CFCDF</string>
<string>6BAF3A2F12101D4B008CFCDF</string>
<string>6BAF3A5F12102BB9008CFCDF</string>
<string>6BAF3A7812103373008CFCDF</string>
<string>6BAF3AAB1210369A008CFCDF</string>
<string>6BAF3AB3121038F9008CFCDF</string>
<string>6BAF3AB4121038F9008CFCDF</string>
<string>6BAF3AB5121038F9008CFCDF</string>
<string>6BAF3AB6121038F9008CFCDF</string>
<string>6BAF3AC2121039C7008CFCDF</string>
</array>
<key>prevStack</key>
<array>
@ -428,7 +427,6 @@
<string>6BBB4AEF115B4F3400CF791D</string>
<string>6BBB4AF0115B4F3400CF791D</string>
<string>6BBB4AF1115B4F3400CF791D</string>
<string>6BBB4AF4115B4F3400CF791D</string>
<string>6BBB4AF7115B4F3400CF791D</string>
<string>6BBB4AF8115B4F3400CF791D</string>
<string>6BBB4AF9115B4F3400CF791D</string>
@ -448,7 +446,6 @@
<string>6BF5F33911759C3C000502A6</string>
<string>6B4215D1118066FE006C347B</string>
<string>6B4215DF1180672F006C347B</string>
<string>6B4216881180725E006C347B</string>
<string>6B5562681193EF2F00843384</string>
<string>6B2CDD181197FE370090FA4D</string>
<string>6B10005C11AD08FA0098A59A</string>
@ -474,12 +471,9 @@
<string>6BF9B14911EB8CF20043574C</string>
<string>6BAF37D611FEAC16008CFCDF</string>
<string>6BAF37FE11FEB4BB008CFCDF</string>
<string>6BAF380211FEB4BB008CFCDF</string>
<string>6BAF382612019EDA008CFCDF</string>
<string>6BAF382712019EDA008CFCDF</string>
<string>6BAF382812019EDA008CFCDF</string>
<string>6BAF382912019EDA008CFCDF</string>
<string>6BAF382A12019EDA008CFCDF</string>
<string>6BAF385F120A8A8E008CFCDF</string>
<string>6BAF3860120A8A8E008CFCDF</string>
<string>6BAF3861120A8A8E008CFCDF</string>
@ -507,40 +501,63 @@
<string>6BAF3919120FEB27008CFCDF</string>
<string>6BAF391B120FEB27008CFCDF</string>
<string>6BAF391C120FEB27008CFCDF</string>
<string>6BAF393B120FEF30008CFCDF</string>
<string>6BAF393D120FEF30008CFCDF</string>
<string>6BAF3944120FEF7A008CFCDF</string>
<string>6BBB4AD2115B4F3400CF791D</string>
<string>6BBB4AD4115B4F3400CF791D</string>
<string>6BAF38431202CBF8008CFCDF</string>
<string>6BAF395E120FF37D008CFCDF</string>
<string>6BAF395F120FF37D008CFCDF</string>
<string>6BAF3969120FF483008CFCDF</string>
<string>6BAF396A120FF483008CFCDF</string>
<string>6BAF396B120FF483008CFCDF</string>
<string>6BAF396C120FF483008CFCDF</string>
<string>6BAF3973120FF609008CFCDF</string>
<string>6BAF3974120FF609008CFCDF</string>
<string>6BAF3982120FF75F008CFCDF</string>
<string>6BAF3983120FF75F008CFCDF</string>
<string>6BAF398E120FF809008CFCDF</string>
<string>6BAF3990120FF809008CFCDF</string>
<string>6BAF3992120FF809008CFCDF</string>
<string>6BAF39C112100714008CFCDF</string>
<string>6BAF39CA1210074E008CFCDF</string>
<string>6BAF39D412100A22008CFCDF</string>
<string>6BAF39D512100A22008CFCDF</string>
<string>6BAF39D612100A22008CFCDF</string>
<string>6BAF39DD12100D84008CFCDF</string>
<string>6BAF39DE12100D84008CFCDF</string>
<string>6BAF39DF12100D84008CFCDF</string>
<string>6BAF39E412100DA6008CFCDF</string>
<string>6BAF39E912100DE4008CFCDF</string>
<string>6BAF39EA12100DE4008CFCDF</string>
<string>6BAF39F312100ED1008CFCDF</string>
<string>6BAF39F412100ED1008CFCDF</string>
<string>6BAF39F512100ED1008CFCDF</string>
<string>6BAF3A3012101D4B008CFCDF</string>
<string>6BAF3A3412102220008CFCDF</string>
<string>6BAF3A3B1210235F008CFCDF</string>
<string>6BAF3A3D1210235F008CFCDF</string>
<string>6BAF3A3F1210235F008CFCDF</string>
<string>6BAF3A46121023ED008CFCDF</string>
<string>6BAF3A4F121028E6008CFCDF</string>
<string>6BAF3A50121028E6008CFCDF</string>
<string>6BAF3A51121028E6008CFCDF</string>
<string>6BAF3A6212102BB9008CFCDF</string>
<string>6BAF3A6312102BB9008CFCDF</string>
<string>6BAF3A6512102BB9008CFCDF</string>
<string>6BAF3A6612102BB9008CFCDF</string>
<string>6BAF3A7C12103373008CFCDF</string>
<string>6BAF3A7D12103373008CFCDF</string>
<string>6BAF3A7E12103373008CFCDF</string>
<string>6BAF3A7F12103373008CFCDF</string>
<string>6BAF3A8012103373008CFCDF</string>
<string>6BAF3A8212103373008CFCDF</string>
<string>6BAF3A8412103373008CFCDF</string>
<string>6BAF3A8512103373008CFCDF</string>
<string>6BAF3A8612103373008CFCDF</string>
<string>6BAF3A8712103373008CFCDF</string>
<string>6BAF3A8812103373008CFCDF</string>
<string>6BAF3A8912103373008CFCDF</string>
<string>6BAF3A8A12103373008CFCDF</string>
<string>6BAF3A8B12103373008CFCDF</string>
<string>6BAF3A8C12103373008CFCDF</string>
<string>6BAF3A8D12103373008CFCDF</string>
<string>6BAF3A8E12103373008CFCDF</string>
<string>6BAF3A8F12103373008CFCDF</string>
<string>6BAF3A9012103373008CFCDF</string>
<string>6BAF3A9112103373008CFCDF</string>
<string>6BAF3A9212103373008CFCDF</string>
<string>6BAF3A9312103373008CFCDF</string>
<string>6BAF3A9512103373008CFCDF</string>
<string>6BAF3A9612103373008CFCDF</string>
<string>6BAF3AB7121038F9008CFCDF</string>
<string>6BAF3AB8121038F9008CFCDF</string>
<string>6BAF3AB9121038F9008CFCDF</string>
<string>6BAF3ABA121038F9008CFCDF</string>
<string>6BAF3ABB121038F9008CFCDF</string>
<string>6BAF3ABC121038F9008CFCDF</string>
<string>6BAF3ABD121038F9008CFCDF</string>
</array>
</dict>
<key>SplitCount</key>
@ -554,18 +571,18 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{0, 0}, {887, 567}}</string>
<string>{{0, 0}, {887, 530}}</string>
<key>RubberWindowFrame</key>
<string>33 87 1173 691 0 0 1280 778 </string>
</dict>
<key>Module</key>
<string>PBXNavigatorGroup</string>
<key>Proportion</key>
<string>567pt</string>
<string>530pt</string>
</dict>
<dict>
<key>Proportion</key>
<string>79pt</string>
<string>116pt</string>
<key>Tabs</key>
<array>
<dict>
@ -633,7 +650,7 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{10, 27}, {887, 52}}</string>
<string>{{10, 27}, {887, 89}}</string>
<key>RubberWindowFrame</key>
<string>33 87 1173 691 0 0 1280 778 </string>
</dict>
@ -855,6 +872,7 @@
<integer>5</integer>
<key>WindowOrderList</key>
<array>
<string>6BAF3AC4121039C7008CFCDF</string>
<string>6BAF394F120FF023008CFCDF</string>
<string>6BAF3950120FF023008CFCDF</string>
<string>/Users/memon/Code/recastnavigation/RecastDemo/Build/Xcode/Recast.xcodeproj</string>

View File

@ -37,7 +37,8 @@ class NavMeshTesterTool : public SampleTool
TOOLMODE_RAYCAST,
TOOLMODE_DISTANCE_TO_WALL,
TOOLMODE_FIND_POLYS_IN_CIRCLE,
TOOLMODE_FIND_POLYS_IN_POLY,
TOOLMODE_FIND_POLYS_IN_SHAPE,
TOOLMODE_FIND_LOCAL_NEIGHBOURHOOD,
};
ToolMode m_toolMode;
@ -65,6 +66,7 @@ class NavMeshTesterTool : public SampleTool
float m_hitNormal[3];
bool m_hitResult;
float m_distanceToWall;
float m_neighbourhoodRadius;
bool m_sposSet;
bool m_eposSet;

View File

@ -31,6 +31,7 @@
#include "DetourNavMesh.h"
#include "DetourNavMeshBuilder.h"
#include "DetourDebugDraw.h"
#include "DetourCommon.h"
#ifdef WIN32
# define snprintf _snprintf
@ -161,6 +162,8 @@ NavMeshTesterTool::NavMeshTesterTool() :
m_polyPickExt[0] = 2;
m_polyPickExt[1] = 4;
m_polyPickExt[2] = 2;
m_neighbourhoodRadius = 2.5f;
}
NavMeshTesterTool::~NavMeshTesterTool()
@ -199,6 +202,7 @@ void NavMeshTesterTool::init(Sample* sample)
m_sample->setNavMeshDrawFlags(flags);
}
m_neighbourhoodRadius = sample->getAgentRadius() * 20.0f;
}
void NavMeshTesterTool::handleMenu()
@ -228,9 +232,14 @@ void NavMeshTesterTool::handleMenu()
m_toolMode = TOOLMODE_FIND_POLYS_IN_CIRCLE;
recalc();
}
if (imguiCheck("Find Polys in Poly", m_toolMode == TOOLMODE_FIND_POLYS_IN_POLY))
if (imguiCheck("Find Polys in Poly", m_toolMode == TOOLMODE_FIND_POLYS_IN_SHAPE))
{
m_toolMode = TOOLMODE_FIND_POLYS_IN_POLY;
m_toolMode = TOOLMODE_FIND_POLYS_IN_SHAPE;
recalc();
}
if (imguiCheck("Find Local Neighbourhood", m_toolMode == TOOLMODE_FIND_LOCAL_NEIGHBOURHOOD))
{
m_toolMode = TOOLMODE_FIND_LOCAL_NEIGHBOURHOOD;
recalc();
}
@ -738,7 +747,7 @@ void NavMeshTesterTool::recalc()
}
}
else if (m_toolMode == TOOLMODE_FIND_POLYS_IN_POLY)
else if (m_toolMode == TOOLMODE_FIND_POLYS_IN_SHAPE)
{
if (m_sposSet && m_startRef && m_eposSet)
{
@ -774,6 +783,19 @@ void NavMeshTesterTool::recalc()
m_polys, m_parent, 0, MAX_POLYS);
}
}
else if (m_toolMode == TOOLMODE_FIND_LOCAL_NEIGHBOURHOOD)
{
if (m_sposSet && m_startRef)
{
#ifdef DUMP_REQS
printf("fln %f %f %f %f 0x%x 0x%x\n",
m_spos[0],m_spos[1],m_spos[2], m_neighbourhoodRadius,
m_filter.includeFlags, m_filter.excludeFlags);
#endif
m_npolys = m_navMesh->findLocalNeighbourhood(m_startRef, m_spos, m_neighbourhoodRadius, &m_filter,
m_polys, m_parent, MAX_POLYS);
}
}
}
static void getPolyCenter(dtNavMesh* navMesh, dtPolyRef ref, float* center)
@ -1000,7 +1022,7 @@ void NavMeshTesterTool::handleRender()
dd.depthMask(true);
}
}
else if (m_toolMode == TOOLMODE_FIND_POLYS_IN_POLY)
else if (m_toolMode == TOOLMODE_FIND_POLYS_IN_SHAPE)
{
for (int i = 0; i < m_npolys; ++i)
{
@ -1033,6 +1055,67 @@ void NavMeshTesterTool::handleRender()
dd.end();
dd.depthMask(true);
}
}
else if (m_toolMode == TOOLMODE_FIND_LOCAL_NEIGHBOURHOOD)
{
for (int i = 0; i < m_npolys; ++i)
{
duDebugDrawNavMeshPoly(&dd, *m_navMesh, m_polys[i], pathCol);
dd.depthMask(false);
if (m_parent[i])
{
float p0[3], p1[3];
dd.depthMask(false);
getPolyCenter(m_navMesh, m_parent[i], p0);
getPolyCenter(m_navMesh, m_polys[i], p1);
duDebugDrawArc(&dd, p0[0],p0[1],p0[2], p1[0],p1[1],p1[2], 0.25f, 0.0f, 0.4f, duRGBA(0,0,0,128), 2.0f);
dd.depthMask(true);
}
float segs[DT_VERTS_PER_POLYGON*3*2];
const int nsegs = m_navMesh->getPolyWallSegments(m_polys[i], &m_filter, segs);
dd.begin(DU_DRAW_LINES, 2.0f);
for (int j = 0; j < nsegs; ++j)
{
const float* s = &segs[j*6];
// Skip too distant segments.
float tseg;
float distSqr = dtDistancePtSegSqr2D(m_spos, s, s+3, tseg);
if (distSqr > dtSqr(m_neighbourhoodRadius))
continue;
float delta[3], norm[3], p0[3], p1[3];
rcVsub(delta, s+3,s);
rcVmad(p0, s, delta, 0.5f);
norm[0] = delta[2];
norm[1] = 0;
norm[2] = -delta[0];
rcVnormalize(norm);
rcVmad(p1, p0, norm, agentRadius*0.5f);
// Skip backfacing segments.
unsigned int col = duRGBA(255,255,255,192);
if (dtTriArea2D(m_spos, s, s+3) < 0.0f)
col = duRGBA(255,255,255,64);
dd.vertex(p0[0],p0[1]+agentClimb,p0[2],duRGBA(0,0,0,128));
dd.vertex(p1[0],p1[1]+agentClimb,p1[2],duRGBA(0,0,0,128));
dd.vertex(s[0],s[1]+agentClimb,s[2],col);
dd.vertex(s[3],s[4]+agentClimb,s[5],col);
}
dd.end();
dd.depthMask(true);
}
if (m_sposSet)
{
dd.depthMask(false);
duDebugDrawCircle(&dd, m_spos[0], m_spos[1]+agentHeight/2, m_spos[2], m_neighbourhoodRadius, duRGBA(64,16,0,220), 2.0f);
dd.depthMask(true);
}
}
}