mesh_displace_fbm — 3D terrain op

• Data kinds: mesh → mesh

• Call: import fullseye as fs; fs.ledger.mesh_displace_fbm(V, F, amplitude: 'float', *, scale=None, octaves: 'int' = 4, lacunarity: 'float' = 2.0, gain: 'float' = 0.5, seed: 'int' = 0) (to call the implementation directly, import render3d; render3d.mesh_displace_fbm(V, F, amplitude: 'float', *, scale=None, octaves: 'int' = 4, lacunarity: 'float' = 2.0, gain: 'float' = 0.5, seed: 'int' = 0); from the registry, ops3d.get("mesh_displace_fbm"))

Usage

Roughen a mesh by displacing vertices along their normals with seeded fBm noise → (V, F).

amplitude is the peak displacement in the mesh's own units (the Itokawa STL is in km, so 0.003 = 3 m); every vertex moves by at most amplitude (|fBm| ≤ 1, asserted by tests). scale is the base wavelength (default = bounding-box diagonal / 12); octaves/lacunarity/gain shape the spectrum (multifractal ridges come from the default 4 octaves). Deterministic for a given seed; amplitude=0 returns the input unchanged. Face normals of the displaced mesh carry the matching shading perturbation (no separate bump map is faked). Fail-closed on degenerate meshes / non-finite arguments.

Moves each vertex x_i along its area-weighted vertex normal n_i to x_i + amplitude · fBm(x_i) · n_i. fBm is fbm_noise (lattice value noise with a fixed seed; octaves levels are stacked at lacunarity times the frequency and gain times the amplitude, and divided by the amplitude sum to give [-1, 1]). The face array F is not changed; returns (V' (N,3) float64, copy of F).

• amplitude: maximum displacement in mesh units (0 or more). Negative or non-finite raises ValueError; with 0 a copy of the input is returned as is (no noise is computed).

• scale: base wavelength of the noise (mesh units). None = bounding-box diagonal / 12. 0 or less raises ValueError.

• octaves ∈ [1, 16], lacunarity > 0, gain ∈ (0, 1]; out of range raises ValueError.

• Normals are built from the face winding, so a consistently outward-oriented mesh is assumed. Vertices whose normal cannot be determined because of zero area move toward +Z (the fallback value of _vertex_normals).

To specify the amplitude per wavelength or to avoid aliasing on coarse meshes, use mesh_displace_spectrum (band-limited). To put roughness only into the shading and not into the geometry, use bump_normals_fbm.

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)

terrain_region_mask · mesh_scatter_boulders · mesh_edge_lengths · mesh_subdivide · 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.