egametang/ET · critical · Exception

rcBuildPolyMesh: Too many polygons {mesh.npolys} (max:{maxTr

Error message

rcBuildPolyMesh: Too many polygons {mesh.npolys} (max:{maxTris}).

What it means

While storing polygons into the polymesh, rcBuildPolyMesh checks npolys against maxTris on every insert and throws once the pre-allocated polygon array is exceeded. maxTris is the sum of (contour.nverts - 2) over contours, so this trips when triangulation of the contours produces more polygons than the conservative estimate allowed for.

Source

Thrown at Packages/cn.etetet.recast/Scripts/Core/Share/Recast/RecastMesh.cs:1136

                            // Could not merge any polygons, stop.
                            break;
                        }
                    }
                }

                // Store polygons.
                for (int j = 0; j < npolys; ++j)
                {
                    int p = mesh.npolys * nvp * 2;
                    int q = j * nvp;
                    for (int k = 0; k < nvp; ++k)
                        mesh.polys[p + k] = polys[q + k];
                    mesh.regs[mesh.npolys] = cont.reg;
                    mesh.areas[mesh.npolys] = cont.area;
                    mesh.npolys++;
                    if (mesh.npolys > maxTris)
                    {
                        throw new Exception(
                            "rcBuildPolyMesh: Too many polygons " + mesh.npolys + " (max:" + maxTris + ").");
                    }
                }
            }

            // Remove edge vertices.
            for (int i = 0; i < mesh.nverts; ++i)
            {
                if (vflags[i] != 0)
                {
                    if (!CanRemoveVertex(ctx, mesh, i))
                        continue;
                    RemoveVertex(ctx, mesh, i, maxTris);
                    // Remove vertex
                    // Note: mesh.nverts is already decremented inside RemoveVertex()!
                    // Fixup vertex flags
                    for (int j = i; j < mesh.nverts; ++j)
                        vflags[j] = vflags[j + 1];

View on GitHub (pinned to 5cab01f7a8)

Solutions

  1. Increase rcConfig.maxVertsPerPoly (e.g. to 6, the Detour default) so large contours become fewer polygons.
  2. Lower the input contour density (raise cellSize, raise contour simplification tolerance via contourSimplificationError).
  3. Tile the world (set rcConfig.tileSize) so no single build exceeds the polygon budget.
  4. Audit that the contour set wasn't accidentally built with nvp lower than intended.

Example fix

// before: triangles only, explodes polygon count
cfg.maxVertsPerPoly = 3;
// after: allow convex polys up to 6 verts (Detour default)
cfg.maxVertsPerPoly = 6;
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check polygon budget using the same formula as the allocator
int maxTris = 0;
for (int i = 0; i < cset.conts.Count; i++)
    if (cset.conts[i].nverts >= 3)
        maxTris += cset.conts[i].nverts - 2;
if (maxTris > 0xfffe)
    throw new InvalidOperationException($"rcBuildPolyMesh would exceed polygon budget: {maxTris}");

Prevention

When it happens

Trigger: The loop that converts simplified contour polygons into nvp-gons pushes mesh.npolys past maxTris. Happens when contours have many vertices and the per-contour (nverts-2) underestimate is collectively overrun, or when nvp (max verts per polygon) is small forcing many polygons.

Common situations: Setting rcConfig.maxVertsPerPoly low (e.g. 3 = pure triangles) on geometry with large contours; degenerate or very noisy contour sets from aggressive simplification settings; mismatched nvp between contour generation and polygon storage.

Related errors


AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13). Data as JSON: /api/errors/b6f0a7bd26d9ded9. Report an issue: GitHub.