mesh_subdivide — 3D terrain op

• Data kinds: mesh → mesh

• Call: import fullseye as fs; fs.ledger.mesh_subdivide(V, F, *, levels: 'int' = 1, target_edge=None, max_faces: 'int' = 4000000) (to call the implementation directly, import render3d; render3d.mesh_subdivide(V, F, *, levels: 'int' = 1, target_edge=None, max_faces: 'int' = 4000000); from the registry, ops3d.get("mesh_subdivide"))

Usage

Refine a triangle mesh → (V, F) by midpoint subdivision or adaptive tessellation.

Either uniform midpoint subdivision (levels passes, ×4 faces each) or adaptive tessellation to a target edge length (target_edge:

median edge = target, edge segments ≤ 1.5×target, in-face Delaunay edges < 2×target).

The geometry is *unchanged* — every new vertex lies on an old facet, so surface area and enclosed volume are preserved exactly (tests pin this) and nothing is ever decimated; only the facet size changes, so a later mesh_displace_spectrum can carry short wavelengths without aliasing.

Adaptive mode cuts each edge into n = round(length / target_edge) (≥ 1) segments — a per-*edge* count, hence conforming across neighbours (no T-junctions) — and fills each face with a hexagonal lattice at spacing target_edge in the face plane, triangulated by a per-face 2-D Delaunay (Qhull). The interior therefore has edges ≈ target_edge *whatever the shape of the source face* (the Gaskell Itokawa faces have a median longest/shortest edge ratio of 1.83, so a per-face lattice pattern inherits that anisotropy; repeated midpoint bisection additionally leaves a factor-2 spread (target/2, target]). Measured on the Itokawa model (edge p5/median/p95 = 2.6/4.7/7.2 m, target 1.5 m): see examples_3d/itokawa_regolith_hero.py — the test pins p95/p5 ≤ 1.5 on a graded plane. max_faces (default MAX_SUBDIVIDE_FACES) is a memory guard: if the plan would exceed it the call raises ValueError (fail-closed) rather than silently under-refining. Deterministic. Fail-closed: degenerate mesh, levels < 0, non-positive target_edge / caps → ValueError.

There are 2 modes, switched by whether target_edge is given.

• target_edge=None (uniform): repeats the subdivision that splits every edge at its midpoint levels times (the face count is multiplied by 4 per 1 round). levels=0 returns the input as is. Before each round, if face_count×4 > max_faces, ValueError.

• target_edge given (adaptive): for each edge the number of segments n = round(length / target_edge) (at least 1) is chosen and shared by the adjacent faces, so no T-junctions appear. The segment count is silently clamped to an internal cap of 64, so edges longer than 64 times target_edge do not reach the target. If no edge needs splitting, a copy of the input is returned. If the face-count estimate Σ(sum of the segment counts of the 3 edges + mean segment count²) exceeds max_faces, it raises ValueError before computing. levels is not used in this mode.

Returns (V (N',3) float64, F (M',3) int64). New vertices are always placed on the original faces, so area and volume do not change (this is not smoothing). Adaptive mode uses a 2-D Delaunay (scipy Qhull) per face, so quality drops on extremely elongated faces. After subdividing, check the edge-length distribution with mesh_edge_lengths and pass the result to mesh_displace_spectrum.

References (sample data, literature)

• Sample-data catalog (download URLs / licences) — 2-D uses skimage.data (BSD/public domain) plus synthetic images; 3-D lists download URLs for real data sources (Stanford, PDS, …).

• Operator provenance and references — the sources of the research/methods this op family came from.

Runnable examples (verified samples that actually call this op)

• itokawa_regolith_hero — py -3.11 examples_3d/itokawa_regolith_hero.py

Ops the type connects to (they accept mesh as input)

mesh_to_voxel · mesh_to_points · to_points · fuse_to_voxel · ambient_occlusion · cast_shadow · supersample_mesh · render_beauty

Same category (terrain)

mesh_displace_fbm · terrain_region_mask · mesh_scatter_boulders · mesh_edge_lengths · displacement_band_weights · mesh_displace_spectrum · bump_normals_fbm


*Provenance: render3d.py — 3D operator registry. This per-op note is generated by tools/opdocs.py md (do not hand-edit).*

© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.