mesh_scatter_boulders — 3D terrain op

• Datenarten: mesh → mesh

• Aufruf: import fullseye as fs; fs.ledger.mesh_scatter_boulders(V, F, *, density: 'float', d_min: 'float', d_max=None, exponent: 'float' = 3.1, seed: 'int' = 0, region_weights=None, aspect=(1.0, 0.7, 0.5), embed: 'float' = 0.35, subdiv: 'int' = 1, shape: 'str' = 'ellipsoid', orientation: 'str' = 'normal', burial=(0.3, 0.6), max_count=None, hull_points=None, return_info: 'bool' = False) (die Implementierung direkt: import render3d; render3d.mesh_scatter_boulders(V, F, *, density: 'float', d_min: 'float', d_max=None, exponent: 'float' = 3.1, seed: 'int' = 0, region_weights=None, aspect=(1.0, 0.7, 0.5), embed: 'float' = 0.35, subdiv: 'int' = 1, shape: 'str' = 'ellipsoid', orientation: 'str' = 'normal', burial=(0.3, 0.6), max_count=None, hull_points=None, return_info: 'bool' = False); aus dem Register: ops3d.get("mesh_scatter_boulders"))

Verwendung

Verstreut halb eingesunkene Felsblöcke auf einem Mesh (Potenzgesetz-Größen, geseedet) → (V, F).

(oder (V, F, info) mit return_info=True).

shape='ellipsoid' (Standard, unverändertes Verhalten): Icosphere-Ellipsoide mit Halbachsen D/2 × aspect (1 : 0.7 : 0.5, kürzeste Achse entlang der lokalen Oberflächennormale), um die Normale gedreht und um embed eingesenkt (0 = aufliegend, 1 = Mittelpunkt auf der Oberfläche). shape='hull': kantige Blöcke — die konvexe Hülle geseedeter Zufallspunkte auf einem Ellipsoid gleicher Proportion mit 20 % radialem Jitter (ebene Facetten, scharfe Kanten, das Aussehen der Felsbrocken auf Itokawa), hull_points pro Block (Standard größenabhängig:

10 + 8·log2(D/d_min), 10..40). orientation='random' gibt jedem Block eine gleichverteilte Zufallsrotation, statt seine kurze Achse an der Normale auszurichten. Bei Hüllen ist die Einsenkung der größenabhängige burial-Anteil aus sample_boulders (standardmäßig 30–60 % der Blockhöhe unter der Oberfläche; embed wird ignoriert). max_count begrenzt die erwartete Anzahl, indem d_min nach demselben Gesetz angehoben wird (siehe sample_boulders; info['d_min_effective'] meldet den Wert).

Platzierung und Größen stammen aus sample_boulders (Poisson-Prozess, N(>D) ∝ D^-exponent); die Brocken liegen auf dem Mesh *wie übergeben* — übergeben Sie das verschobene / unterteilte Gelände, damit sie auf der endgültigen Oberfläche ruhen. region_weights aus terrain_region_mask hält die Meere glatt. Die Brocken werden als echte Geometrie angehängt, werfen also Eigenschatten und Schlagschatten und verdecken über denselben Rasterisierer- / Raycast-Pfad wie das Gelände. info = das Sample-Dict plus faces_per_boulder und n_boulders. Deterministisch unter seed. Fail-closed.

Ablauf: sample_boulders zieht Positionen (gleichverteilte Punkte auf den Flächen), Flächennormalen und Durchmesser D; für jeden Brocken wird ein kleines Mesh erzeugt und hinter das Eingabe-Mesh gehängt (Vertices werden am Ende angefügt, Flächenindizes sind bereits versetzt). Vertices und Flächen der Eingabe bleiben unverändert, sodass man aus info['faces_per_boulder'] und der ursprünglichen Flächenzahl nur die Flächen der Brocken herausschneiden kann.

• density: erwartete Anzahl Brocken mit D ≥ d_min pro Flächeneinheit (Mesh-Einheiten²). Die tatsächliche Anzahl folgt einer Poisson-Verteilung und kann 0 sein (dann wird eine Kopie der Eingabe zurückgegeben).

• d_min < d_max (None = 10·d_min), exponent > 0, aspect sind 3 positive Elemente, embed ∈ [0, 1], subdiv ∈ [0, 3] (Icosphere-Unterteilung des Ellipsoids), hull_points in [6, 200]. Jeder Wert außerhalb des Bereichs löst ValueError aus.

• shape='ellipsoid': legt ein Ellipsoid mit Halbachsen D/2·aspect so, dass die kürzeste Achse entlang der Normale liegt, und hebt den Mittelpunkt um semi_z·(1 − embed) entlang der Normale an.

• shape='hull': konvexe Hülle von Zufallspunkten auf dem Ellipsoid. Vom Höhenbereich entlang der Normale sinkt der Anteil burial (Standard 0.3 bis 0.6, je kleiner der Brocken desto tiefer) unter die Oberfläche. embed wird ignoriert.

• orientation='random' ist eine gleichverteilte Zufallsrotation (Quaternion mit 4 Komponenten). 'normal' ist eine Zufallsrotation um die Normale. Für die Rotationen wird ein Generator mit seed + 1 verwendet.

Die Brocken sind echte Geometrie, daher treffen die Strahlen von ambient_occlusion / cast_shadow / shadow_raycast sie ganz normal. Die Auflagefläche ist genau das übergebene Mesh; rufen Sie die Funktion daher bei mesh_displace_spectrum oder mesh_subdivide danach auf (vorher aufgerufen schweben die Brocken über dem Boden bzw. versinken darin).

Referenzen (Beispieldaten, Literatur)

• Katalog der Beispieldaten (Download-URLs / Lizenzen) — 2-D nutzt skimage.data (BSD/Public Domain) plus synthetische Bilder, 3-D nennt Download-URLs echter Datenquellen (Stanford, PDS, …).

• Herkunft und Literatur der Operatoren — die Quellen der Forschung/Verfahren, auf denen diese Operatorfamilie beruht.

Ausführbare Beispiele (verifizierte Samples, die diesen Operator wirklich aufrufen)

• itokawa_regolith_hero — py -3.11 examples_3d/itokawa_regolith_hero.py

Typkompatible Folge-Operatoren (nehmen mesh als Eingabe)

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

Gleiche Kategorie (terrain)

mesh_displace_fbm · terrain_region_mask · mesh_edge_lengths · mesh_subdivide · displacement_band_weights · mesh_displace_spectrum · bump_normals_fbm


*Provenance: render3d.py — 3D Operator-Registry. Diese Notiz wird von tools/opdocs.py md erzeugt (nicht von Hand bearbeiten).*

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