New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
find path enters an infinite loop. #343
Comments
same problem |
I have been unable to get your navmesh file to load correctly, it seems like it is corrupt in some way. When loading it fails to load any tiles because all tile-refs are 0. |
I can also confirm I had this several times, very rare though. It happens for me when I set the additional HScale value of the pathfind algorightm too high. I was unable to completely fix it on my end, added a hacky failsafe, but afaik it happens because the node weights are using not only the 'already traveled distance' as costs but in addition such a HScale value. This kinda made the pathfinding rotate between a few nodes until you run out of available nodes... |
I have the same issue, with detour entering an infinite loop in getPathToNode() looping through nodes with circular reference (A -> B -> C -> A) https://github.com/recastnavigation/recastnavigation/blob/master/Detour/Source/DetourNavMeshQuery.cpp#L1212
Some guard check should be added, either max number of iterations, a hashset checking for pidx or some check in the m_nodePool so that there is no circular reference. I will try to setup a case in recastdemo. |
Validate input values, including that points are finite. This would have saved everyone some time in recastnavigation#343/recastnavigation#373.
Validate input values, including that points are finite. This would have saved everyone some time in recastnavigation#343/recastnavigation#373.
I was able to identify the issue in my project:
In a particular region we have terrain data from 2 different sources, one has ground and one has liquid. The way the overlap made recast mark some parts as ground and some part as liquid, creating a lot of small polys If I change the way the flags are prioritized, making ground win against water, I get a clean result. This is also why I couldn't reproduce the issue in RecastDemo as the .obj file doesn't have any area flag data. |
I think it is very possible that one voxel wide ideas inside another area collapses into a degenerate polygon. Should be avoided, but sometimes tricky. These sliver areas tend to create heaps of other problems too, even if well behaving with triangulation. Like weird paths because very uneven tesselation. Some of the degenerate problems are caused by contour simplification. Especially at the tip of an area. One solution would be to disallow two turns in same direction. So a straight segment would need to be staircase like. I once experimented using filtering to solve these issues and it works some times too. There's area median filter to try out. |
@jakobbotsch did you have any idea about how to deal with dtClosestHeightPointTriangle() having denom = 0 ? |
No, |
The epsilon is there because the Potential solutions:
Pt 2 could be something like this: bool dtClosestHeightPointSeg(const float* pt, const float* p, const float* q, float size, float& h)
{
float t;
float d = dtDistancePtSegSqr2D(pt, p, q, t);
if (d > size*size)
return false;
h = p[1]+(q[1]-p[1])*t;
return true;
}
...
float edgeSize = walkableRadius * 0.1f; // Size of the edge
float maxh = -FLT_MAX;
float h;
if (dtClosestHeightPointTriangle(closest, v[0], v[1], v[2], h))
maxh = dtMax(maxh, h);
if (dtClosestHeightPointSeg(closest, v[0], v[1], edgeSize, h))
maxh = dtMax(maxh, h);
if (dtClosestHeightPointSeg(closest, v[1], v[2], edgeSize, h))
maxh = dtMax(maxh, h);
if (dtClosestHeightPointSeg(closest, v[2], v[0], edgeSize, h))
maxh = dtMax(maxh, h);
if (maxh > -FLT_MAX)
{
closest[1] = h;
break;
} Pt 1 could traverse all edges, pick nearest edges first and then calculate height. That way you would not need edges size, which makes things nicer. Bonus points for figuring out how to traverse the detail mesh edges only once :) |
Number 2 is essentially what I wanted to do initially, but it can be done inside The problem we have right now is that EDIT: Unless the entire poly is a single degenerate triangle, but I don't think it was the case in this scenario. |
IIRC there's only one call to I'm suggesting to following:
bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b, const float* c, float& h)
{
const float EPS = 1e-6f;
float v0[3], v1[3], v2[3];
dtVsub(v0, c,a);
dtVsub(v1, b,a);
dtVsub(v2, p,a);
// Compute scaled barycentric coordinates
float denom = v0[0] * v1[2] - v0[2] * v1[0];
if (fabsf(denom) < EPS)
return false;
float u = v1[2] * v2[0] - v1[0] * v2[2];
float v = v0[0] * v2[2] - v0[2] * v2[0];
if (denom < 0) {
denom = -denom;
u = -u;
v = -v;
}
// If point lies inside the triangle, return interpolated y-coord.
if (u >= 0.0f && v >= 0.0f && (u+v) <= denom) {
h = a[1] + (v0[1]*u + v1[1]*v) / denom;
return true;
}
return false;
}
float dtLerp(float a, float b, float t)
{
return a + (b - a) * t;
}
...
// Find height at the location.
float dmin = FLT_MAX, d, t;
float safeHeight = closest[1];
for (int j = 0; j < pd->triCount; ++j)
{
const unsigned char* t = &tile->detailTris[(pd->triBase+j)*4];
const float* v[3];
for (int k = 0; k < 3; ++k)
{
if (t[k] < poly->vertCount)
v[k] = &tile->verts[poly->verts[t[k]]*3];
else
v[k] = &tile->detailVerts[(pd->vertBase+(t[k]-poly->vertCount))*3];
}
float h;
if (dtClosestHeightPointTriangle(closest, v[0], v[1], v[2], h))
{
closest[1] = h;
break;
}
// Track nearest extrapolated height in case we fail raycast.
d = dtDistancePtSegSqr2D(closest, v[0], v[1], t);
if (d < dmin)
{
dmin = d;
safeHeight = dtLerp(v[0][1], v[1][1], t);
}
d = dtDistancePtSegSqr2D(closest, v[1], v[2], t);
if (d < dmin)
{
dmin = d;
safeHeight = dtLerp(v[1][1], v[2][1], t);
}
d = dtDistancePtSegSqr2D(closest, v[2], v[0], t);
if (d < dmin)
{
dmin = d;
safeHeight = dtLerp(v[2][1], v[0][1], t);
}
}
// We failed to recast any of the detail triangles, use extrapolated value of nearest edge instead.
closest[1] = safeHeight;
... |
And one more thing:
|
Thank you, that is pretty clear. What I'm wondering is whether it is possible for an internal point in the polygons to fail all the What I mean is: can we replace this part with just finding the nearest edge for all detail triangles, and then keep the loop the same when |
Also I am a little perplexed at what the difference between |
I think I have seen the raycast (that is, I think |
I believe this was fixed by #381. |
Hi,
all_tiles_navmesh.zip
Thanks
The text was updated successfully, but these errors were encountered: