egametang/ET · error · Exception
buildPolyDetail: Could not triangulate polygon ({nverts}) ve
Error message
buildPolyDetail: Could not triangulate polygon ({nverts}) verts). What it means
buildPolyDetail triangulates the polygon hull via TriangulateHull; if the resulting triangle list is empty, the polygon could not be triangulated at all. Rather than emit empty/garbage detail data, it throws so the caller knows the detail mesh is incomplete.
Source
Thrown at Packages/cn.etetet.recast/Scripts/Core/Share/Recast/RecastMeshDetail.cs:1000
}
// If the polygon minimum extent is small (sliver or small triangle), do not try to add internal points.
if (minExtent < sampleDist * 2)
{
TriangulateHull(nverts, verts, nhull, hull, nin, tris);
return nverts;
}
// Tessellate the base mesh.
// We're using the triangulateHull instead of delaunayHull as it tends to
// create a bit better triangulation for long thin triangles when there
// are no internal points.
TriangulateHull(nverts, verts, nhull, hull, nin, tris);
if (tris.Count == 0)
{
// Could not triangulate the poly, make sure there is some valid data there.
throw new Exception("buildPolyDetail: Could not triangulate polygon (" + nverts + ") verts).");
}
if (sampleDist > 0)
{
// Create sample locations in a grid.
RcVec3f bmin = new RcVec3f();
RcVec3f bmax = new RcVec3f();
RcVec3f.Copy(ref bmin, @in, 0);
RcVec3f.Copy(ref bmax, @in, 0);
for (int i = 1; i < nin; ++i)
{
bmin.Min(@in, i * 3);
bmax.Max(@in, i * 3);
}
int x0 = (int)Math.Floor(bmin.x / sampleDist);
int x1 = (int)Math.Ceiling(bmax.x / sampleDist);
int z0 = (int)Math.Floor(bmin.z / sampleDist);View on GitHub (pinned to 5cab01f7a8)
Solutions
- Sanitize input geometry before baking: remove duplicate/colinear vertices and zero-area polygons.
- Increase contour simplification tolerance only if geometry tolerates it; lower it if slivers appear.
- Check the upstream polymesh for degenerate polygons (nverts < 3) and skip them before detail build.
- Scale the world so coordinates aren't extremely small (avoids FP degeneracy in triangulation).
Defensive patterns
Strategy: validation
Validate before calling
// Skip degenerate polygons before detail build
foreach (var poly in mesh.polys) {
int uniqueVerts = CountUniqueVerts(poly, nvp);
if (uniqueVerts < 3 || IsDegenerate(poly, nvp)) {
Log.Warning("Skipping degenerate polygon in detail build");
continue;
}
} Try / catch
// Wrap per-polygon detail build so one bad poly doesn't kill the whole mesh
foreach (var poly in polys) {
try { rcBuildPolyMeshDetail(...); }
catch (Exception e) when (e.Message.Contains("Could not triangulate")) {
Log.Warning($"Skipping un-triangulatable poly: {e.Message}");
continue;
}
} Prevention
- Sanitize input geometry: remove duplicate/colinear vertices before baking.
- Validate base polymesh polygons aren't degenerate before detail build.
- Avoid extremely small world scales that cause FP triangulation issues.
When it happens
Trigger: TriangulateHull(nverts, verts, nhull, hull, nin, tris) leaves tris.Count == 0. Happens with degenerate input polygons: zero-area hulls, collinear vertices, nverts < 3 after hull construction, or malformed contour winding.
Common situations: Corrupted or degenerate input contour passed to rcBuildPolyMeshDetail; very thin sliver polygons from aggressive simplification; near-zero-area regions produced by bad input geometry (duplicate vertices, T-junctions); floating-point edge cases at extremely small scales.
Related errors
- addEdge: Too many edges ({edges.Count / 4}/{maxEdges}).
- rcBuildPolyMeshDetail: Shrinking triangle count from {ntris}
- removeVertex: Too many polygons {mesh.npolys} (max:{maxTris}
- rcBuildPolyMesh: Too many vertices {maxVertices}
- rcBuildPolyMesh: Too many polygons {mesh.npolys} (max:{maxTr
AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13).
Data as JSON: /api/errors/cc934ad3c0a739f6.
Report an issue: GitHub.