code wiki / (root) / nx_relief_lib.nx

nx_relief_lib.nx

buildroot/runtime/nx_relief_lib.nx

29739 B526 linesdepth 2pulls 2 transitivereach 412 importersview sourcekind library
docsdependenciesstructsconstsfunctions

about

nx_relief_lib.nx -- ★THE ONE OWNER OF THE SKIN MICRO-RELIEF LAW, and of the height field the baked normal map is made of. Extracted 2026-08-25 so the BAKER and the SDF RENDERER cannot disagree about the relief they are respectively writing and reading. [@penner2011] /compare/graphics row "RENDER: pre-integrated SSS bound to baked normals". WHY A LEAF LIB AND NOT A MIRROR. Until today nx_sdfrender carried HAND-COPIED constants (SSS_RELIEF_UM / SSS_RELIEF_LAMBDA_UM) with a comment naming the baker as their source, and a gate tooth that compared the copies. That is the duplicate-ruler defect wearing a test: the copy can only be caught AFTER it drifts, and only if somebody keeps running the comparison. The reason given for the copy was real -- importing nx_nxa_texbake_lib drags nx_nxa + nx_trimesh + nx_png + nx_skin_ita into every consumer of the renderer -- so the fix is not "import the baker", it is to give the law its own LEAF home that both sides import. This file imports nothing but nx_syscalls. THE SEAM, stated so the next reader does not move the wrong half: * THIS FILE owns the PHYSICS -- microns of relief, the wavelength it varies over, the slope that follows from the two, and the value-noise field itself. * nx_nxa_texbake_lib keeps the TEXEL ENCODING -- the byte midpoint/scale that turn a slope into an RGB8 tangent-space texel. That is an atlas format decision, not a property of skin. * nx_sdfrender reads the physics and never sees a texel: a ray-marched implicit surface has no UV, so it samples the SAME height field volumetrically at the lattice its own sampler can resolve. license_tier: ORIGINAL No hw writes (Rule 26).

dependencies 1 imports · 30 importers

nx_syscalls.nx nx_relief_lib.nx nx_craft_body_driver_t138.nx nx_craft_combined_emit_t28.nx nx_craft_combined_emit_t29.nx nx_craft_emit.nx nx_craft_feedback_emit_t28.nx nx_craft_garment_emit_t132.nx nx_craft_integrated_emit_t73.nx nx_craft_knight_emit_t25.nx nx_craft_material_body_emit_t61.nx nx_craft_material_emit_t55.nx

diagram shows first 10 each side; +0 more imports, +20 more importers in the complete lists below.

imports: nx_syscalls.nx

imported by: nx_craft_body_driver_t138.nxnx_craft_combined_emit_t28.nxnx_craft_combined_emit_t29.nxnx_craft_emit.nxnx_craft_feedback_emit_t28.nxnx_craft_garment_emit_t132.nxnx_craft_integrated_emit_t73.nxnx_craft_knight_emit_t25.nxnx_craft_material_body_emit_t61.nxnx_craft_material_emit_t55.nxnx_craft_move_emit_t72.nxnx_craft_pipeline_emit_t64.nxnx_craft_recovery_emit_t23.nxnx_craft_search_emit_t53.nxnx_craft_support_emit_t31.nxnx_craft_workspace_emit_t48.nxnx_microscan_gate.nxnx_nxa_texbake_decode_t279.nxnx_nxa_texbake_lib.nxnx_nxa_texbake_region_capacity_t278.nxnx_nxa_texbake_region_edge_t278.nxnx_nxa_texbake_region_lib.nxnx_nxa_texm.nxnx_relief_bands_gate.nxnx_sdfrender.nxnx_sdfrender_attribution_candidate_t344.nxnx_sdfrender_sss_gate.nxnx_trimesh.nxnx_worldpipe_core.nxnx_worldpipe_core_relief_t140.nx

structs

none

consts

31const RLF_HASH_A: i64 = 374761393
32const RLF_HASH_B: i64 = 668265263
33const RLF_HASH_C: i64 = 1610612741
34const RLF_HASH_MIX: i64 = 1274126177
35const RLF_AVAL_1: i64 = 13
36const RLF_AVAL_2: i64 = 16
37const RLF_UNIT: i64 = 1024 // interpolation unit AND the hash codomain modulus
38const RLF_OFF: i64 = 1048576 // coordinate bias so floor-division stays positive for negative coords
41const RLF_H_RANGE: i64 = 1023
73const RLF_RELIEF_UM: i64 = 60
74const RLF_RELIEF_LAMBDA_UM: i64 = 1200
75const RLF_BODY_UM: i64 = 1700000 // a 1.7 m adult; the atlas covers the whole body
78const RLF_TILT_K: i64 = 4
153const RLF_SEC_UM: i64 = 20 // swing, microns
154const RLF_SEC_LAMBDA_UM: i64 = 250 // wavelength, microns
156const RLF_PORE_UM: i64 = 30 // pit depth, microns
157const RLF_PORE_PITCH_UM: i64 = 800 // mean spacing between orifices, microns
158const RLF_PORE_DIA_UM: i64 = 100 // orifice diameter, microns
159const RLF_NBAND: i64 = 3
163const RLF_PORE_JIT: i64 = 512
165const RLF_PORE_D2_INF: i64 = 1000000000
167const RLF_PI_E3: i64 = 3142
391const RLF_TILE_LCM_MULT: i64 = 2
393const RLF_BAND_PRIMARY: i64 = 1
394const RLF_BAND_SECONDARY: i64 = 2
395const RLF_BAND_POREGRID: i64 = 4
396const RLF_BAND_ORIFICE: i64 = 8
397const RLF_BAND_ALL: i64 = 15

functions

43func rlf_hash3(a: i64, b: i64, c: i64) -> i64
50func rlf_noise3(x: i64, y: i64, z: i64, S: i64) -> i64
80func rlf_texel_um(res: i64) -> i64
88func rlf_relief_lat(res: i64) -> i64
called by 3: mainrlf_relief_hmain calls 1: rlf_texel_um
94func rlf_relief_h(x: i64, y: i64, res: i64, seed: i64) -> i64
100func rlf_relief_h3(x: i64, y: i64, z: i64, cell: i64) -> i64
106func rlf_slope_um(dh: i64) -> i64 { return dh * RLF_RELIEF_UM / RLF_H_RANGE }
108func rlf_run_um(res: i64) -> i64 { return 2 * rlf_texel_um(res) }
111func rlf_tilt_full(n_full: i64) -> i64 { return n_full * RLF_TILT_K * RLF_RELIEF_UM / RLF_RELIEF_LAMBDA_UM }
115func rlf_atlas_tilt_full(res: i64, n_full: i64) -> i64 { return n_full * RLF_RELIEF_UM / rlf_run_um(res) }
called by 1: main calls 1: rlf_run_um
171func rlf_band_tilt_full(n_full: i64, a_um: i64, lambda_um: i64) -> i64
177func rlf_band_lat(res: i64, lambda_um: i64) -> i64
called by 1: rlf_relief_um2 calls 1: rlf_texel_um
184func rlf_band_resolvable(res: i64, lambda_um: i64) -> i64
191func rlf_band_res_needed(span_um: i64, lambda_um: i64) -> i64
198func rlf_texel_um_span(span_um: i64, res: i64) -> i64
206func rlf_band_resolvable_span(span_um: i64, res: i64, lambda_um: i64) -> i64
212func rlf_pore_centre(cx: i64, cy: i64, axis: i64) -> i64
called by 2: mg_place_boundrlf_pore_d2 calls 1: rlf_hash3
217func rlf_pore_d2(x: i64, y: i64, cell: i64) -> i64
243func rlf_pore_radius() -> i64 { return RLF_UNIT * RLF_PORE_DIA_UM / (2 * RLF_PORE_PITCH_UM) }
246func rlf_pore_area_permil() -> i64
called by 2: mainmain calls 1: rlf_pore_radius
252func rlf_pore_mask(x: i64, y: i64, cell: i64) -> i64
264func rlf_pore_tilt_full(n_full: i64) -> i64
called by 1: main
271func rlf_total_um() -> i64 { return RLF_RELIEF_UM + RLF_SEC_UM + RLF_PORE_UM }
called by 1: main
277func rlf_multi_tilt_full(res: i64, n_full: i64) -> i64
287func rlf_relief_um2(x: i64, y: i64, res: i64, seed: i64) -> i64
305func rlf_band_lat_span(span_um: i64, res: i64, lambda_um: i64) -> i64
311func rlf_run_um_span(span_um: i64, res: i64) -> i64 { return 2 * rlf_texel_um_span(span_um, res) }
314func rlf_bands_carried_span(span_um: i64, res: i64) -> i64
323func rlf_bands_count(mask: i64) -> i64
336func rlf_pore_mask_r(x: i64, y: i64, cell: i64, r: i64) -> i64
called by 1: rlf_relief_um2_span calls 1: rlf_pore_d2
347func rlf_relief_um2_span(x: i64, y: i64, span_um: i64, res: i64, seed: i64) -> i64
399func rlf_gcd(a: i64, b: i64) -> i64
called by 1: rlf_lcm
407func rlf_lcm(a: i64, b: i64) -> i64
called by 1: rlf_tile_px calls 1: rlf_gcd
413func rlf_tile_texel_um() -> i64 { return RLF_PORE_DIA_UM / 2 }
415func rlf_tile_lat(lambda_um: i64) -> i64
421func rlf_tile_px() -> i64
428func rlf_tile_repeat_um() -> i64 { return rlf_tile_px() * rlf_tile_texel_um() }
431func rlf_tile_bands_carried() -> i64 { return rlf_bands_carried_span(rlf_tile_repeat_um(), rlf_tile_px()) }
433func rlf_wrap(x: i64, px: i64) -> i64
439func rlf_hash3_per(gx: i64, gy: i64, z: i64, per: i64) -> i64
446func rlf_noise3_per(x: i64, y: i64, z: i64, S: i64, per: i64) -> i64
463func rlf_pore_centre_per(cx: i64, cy: i64, axis: i64, per: i64) -> i64
called by 1: rlf_pore_d2_per calls 1: rlf_hash3_per
469func rlf_pore_d2_per(x: i64, y: i64, cell: i64, per: i64) -> i64
495func rlf_pore_mask_per(x: i64, y: i64, cell: i64, r: i64, per: i64) -> i64
505func rlf_relief_um2_tile_bands(x: i64, y: i64, seed: i64, mask: i64) -> i64
524func rlf_relief_um2_tile(x: i64, y: i64, seed: i64) -> i64
called by 1: main calls 1: rlf_relief_um2_tile_bands