terrain op• 数据种类:normalmap × pointmap → normalmap
• 调用: import fullseye as fs; fs.ledger.bump_normals_fbm(normals, positions, wavelengths=(0.002, 0.001), amplitudes=(0.0002, 0.00012), *, seed: 'int' = 0, rotation=None, step=None, local_edge=None, nyquist: 'float' = 2.0, fade: 'float' = 1.0) -> 'np.ndarray'(要直接调用实现,import render3d; render3d.bump_normals_fbm(normals, positions, wavelengths=(0.002, 0.001), amplitudes=(0.0002, 0.00012), *, seed: 'int' = 0, rotation=None, step=None, local_edge=None, nyquist: 'float' = 2.0, fade: 'float' = 1.0) -> 'np.ndarray';从台账取用则 ops3d.get("bump_normals_fbm"))
用带 seed 的多倍频高度场的梯度扰动法线图。
这是几何上无法承担位移的亚面片起伏 → 单位法线 (H, W, 3)。
h(x) = Σ_k A_k n_k(x) 与 mesh_displace_spectrum 位移时所用的 value-noise 场相同(相同 seed ⇒ 相同格点),因此传入位移的频带门控所拒绝的倍频程,着色就会在面片尺寸以下延续*同一*振幅频谱(不是伪造的砂纸:波长 λ 处振幅为 A 的倍频程最多使法线倾斜约 2πA/λ)。bump 后的法线为 normalize(n − ∇_t h)(表面上高度场的一阶着色法线; ∇_t = 用中心差分求的切向梯度,step = min(λ)/64)。positions 是世界坐标 (H, W, 3)(NaN = 背景, 保持不变);若给出 rotation(3×3,world → 法线坐标系,例如 pose[:3,:3]), 则法线在该坐标系中取得。
local_edge(可选,每个像素下方网格局部边长的 (H, W) 图)使 bump 恰好成为位移频带门控的补集:倍频程 k 以权重 1 − gate_k 做 bump,其中 gate_k 是采用相同 nyquist / fade 的 displacement_band_weights 的规则 —— 因此几何在某像素已承载的倍频程不会被加两次,而几何无法承载的倍频程则完全由 bump 补上。没有它时每个倍频程都以全振幅做 bump。确定性;fail-closed。
输入和输出都是 (H, W, 3) 图像。positions 含 NaN 的像素,或法线长度在 1e-12 以下的像素,作为背景保持原值(render3d.render_mesh 的空像素)。若一个有效像素都没有,则返回输入的副本。
• wavelengths / amplitudes:以网格(= positions)的单位表示、长度相同(1〜32)的正数序列。不一致或为负时抛出 ValueError。
• rotation:3×3(world → 法线的坐标系)。给出时用 N @ R 把法线转回 world 再求梯度,再用 @ R.T 转回原坐标系。render_mesh 的法线在相机空间,因此传入 pose[:3,:3]。非有限、形状不正确时抛出 ValueError。
• step:中心差分的步长(默认 min(wavelengths)/64)。0 以下抛出 ValueError。
• local_edge:(H, W) 的边长图。形状与法线不同,或有效像素下存在非正、非有限值时抛出 ValueError。
高度场按 3 个轴做中心差分求导,因此每 1 像素评估 6 次。法线的倾斜约为 max |∇h| ≈ 2π A_k / λ_k,所以振幅越接近波长,法线倾倒得越厉害(默认 A/λ = 0.1 左右)。结果可直接传给 phong_shade / brdf_hapke 等的法线图输入。
• 示例数据目录(下载 URL / 许可证) —— 2-D 用 skimage.data(BSD/公有领域)加合成图,3-D 给出真实数据源(Stanford/PDS 等)的下载 URL。
• 算子来历与参考文献 —— 该算子族所依据的研究/方法出处。
• itokawa_regolith_hero — py -3.11 examples_3d/itokawa_regolith_hero.py
normalmap 作为输入)fuse_to_voxel · render_shaded · phong_shade · matcap_shade · brdf_lommel_seeliger · brdf_hapke · integrate_normals · render_lambertian
terrain)mesh_displace_fbm · terrain_region_mask · mesh_scatter_boulders · mesh_edge_lengths · mesh_subdivide · displacement_band_weights · mesh_displace_spectrum
*Provenance: render3d.py — 3D 算子登记表。本条目由 tools/opdocs.py md 自动生成(请勿手工编辑)。*
© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.