bump_normals_fbm — 3D 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)(표면 위 높이장의 1차 음영 법선; ∇_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 등의법선 맵 입력에 그대로 넘길 수 있다.

참고(샘플 데이터·문헌)

• 샘플 데이터 카탈로그(DL URL / 라이선스) —— 2-D 는 skimage.data(BSD/public)+ 합성, 3-D 는 실데이터 소스(Stanford/PDS 등)의 DL 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 연산자 레지스트리. 이 op 노트는 tools/opdocs.py md 가 자동 생성합니다(직접 편집하지 마세요).*

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