mesh_scatter_boulders — 3D terrain op

• Data kinds: mesh → mesh

• Call: 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) (implementation को सीधे call करना हो तो 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), registry से लेना हो तो ops3d.get("mesh_scatter_boulders"))

उपयोग

mesh पर आंशिक रूप से दबे boulders बिखेरता है (power-law sizes, seeded) → (V, F)

(या return_info=True होने पर (V, F, info))।

shape='ellipsoid' (default, व्यवहार अपरिवर्तित): icosphere ellipsoid, जिनकी semi-axes D/2 × aspect हैं (1 : 0.7 : 0.5, सबसे छोटी axis स्थानीय surface normal की दिशा में), इन्हें normal के चारों ओर घुमाया जाता है और embed जितना धँसाया जाता है (0 = सतह पर टिका, 1 = केंद्र सतह पर)। shape='hull': कोणीय blocks — समान aspect वाले, 20 % radial jitter के साथ ellipsoid पर seed किए गए random points का convex hull (सपाट facets, तीखे edges, Itokawa के boulders जैसा रूप), हर block में hull_points points (default आकार पर निर्भर:

10 + 8·log2(D/d_min), 10..40)। orientation='random' हर block को short axis को normal के साथ संरेखित करने के बजाय एक uniform random rotation देता है। hulls के लिए धँसाव sample_boulders से मिला आकार-निर्भर burial अंश है (default रूप से block की ऊँचाई का 30–60 % सतह के नीचे; embed अनदेखा किया जाता है)। max_count उसी नियम के अनुसार d_min बढ़ाकर अपेक्षित संख्या को सीमित करता है (देखें sample_boulders; info['d_min_effective'] यह मान बताता है)।

स्थान और आकार sample_boulders से आते हैं (Poisson process, N(>D) ∝ D^-exponent); boulders mesh पर *जैसा pass किया गया* वैसे ही रखे जाते हैं — displaced / subdivided terrain pass करें ताकि वे अंतिम सतह पर टिकें। terrain_region_mask से मिले region_weights "समुद्र" (maria) वाले क्षेत्रों को चिकना रखते हैं। boulders असली geometry के रूप में जोड़े जाते हैं, इसलिए terrain जैसे ही rasteriser / ray-cast path से वे self-shadow बनाते हैं, छाया डालते हैं और occlude करते हैं। info = sample dict और साथ में faces_per_boulder तथा n_boulders। seed के तहत deterministic। Fail-closed।

प्रक्रिया: sample_boulders से position (faces पर uniform points), face normal और व्यास D लिए जाते हैं; हर boulder के लिए एक छोटा mesh बनाकर input mesh के पीछे जोड़ा जाता है (vertices अंत में जोड़े जाते हैं, face index पहले से offset किए होते हैं)। input के vertices और faces जैसे के तैसे रहते हैं, इसलिए info['faces_per_boulder'] और मूल face संख्या से केवल boulders के faces अलग किए जा सकते हैं।

• density: प्रति इकाई क्षेत्रफल (mesh इकाई²) D ≥ d_min वाले boulders की अपेक्षित संख्या। वास्तविक संख्या Poisson distribution से तय होती है और 0 भी हो सकती है (तब input की copy लौटाई जाती है)।

• d_min < d_max (None = 10·d_min), exponent > 0, aspect 3 धनात्मक elements, embed ∈ [0, 1], subdiv ∈ [0, 3] (ellipsoid का icosphere subdivision), hull_points [6, 200] में। इनमें से कोई भी सीमा से बाहर हो तो ValueError।

• shape='ellipsoid': semi-axes D/2·aspect वाला ellipsoid इस तरह रखा जाता है कि सबसे छोटी axis normal के साथ हो, और केंद्र को normal की दिशा में semi_z·(1 − embed) ऊपर उठाया जाता है।

• shape='hull': ellipsoid पर random points का convex hull। normal दिशा की ऊँचाई की सीमा में से burial (default 0.3 से 0.6, boulder जितना छोटा उतना गहरा) अंश सतह के नीचे धँसता है। embed अनदेखा किया जाता है।

• orientation='random' uniform random rotation है (4 घटकों वाला quaternion)। 'normal' normal के चारों ओर random rotation है। rotation के random मानों के लिए seed + 1 वाला generator उपयोग होता है।

boulders असली geometry हैं, इसलिए ambient_occlusion / cast_shadow / shadow_raycast की rays उनसे सामान्य रूप से टकराती हैं। जिस सतह पर उन्हें रखा जाता है वह pass किया गया mesh ही है, इसलिए mesh_displace_spectrum या mesh_subdivide के बाद इसे call करें (पहले call करने पर boulders ज़मीन से ऊपर तैरते हैं / उसमें दब जाते हैं)।

संदर्भ (sample data, साहित्य)

• Sample data catalog (DL URL / license) — 2-D के लिए skimage.data (BSD/public) + synthetic, 3-D के लिए real data sources (Stanford/PDS आदि) के DL URL।

• Operators का स्रोत और संदर्भ — इस op family के मूल research/methods के स्रोत।

चलाए जा सकने वाले उदाहरण (verified samples जो सच में यह op call करते हैं)

• itokawa_regolith_hero — py -3.11 examples_3d/itokawa_regolith_hero.py

वे अगले ops जिनसे type जुड़ता है (mesh को input के रूप में लेते हैं)

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

इसी category के (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. यह per-op note tools/opdocs.py md से अपने-आप generate होता है (हाथ से edit न करें)।*

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