nx_gi_path_lib.nx
buildroot/runtime/nx_gi_path_lib.nx
about
nx_gi_path_lib.nx -- THE BEAUTY TIER'S FIRST BYTE (LIBRARY: every function of the sovereign path tracer; nx_gi_path.nx is the CLI, nx_gi_path_gate.nx the teeth): a sovereign INTEGER PATH TRACER over the procgen heightfield.
graphics GR42 (env_beauty_scene) + GR10 (gp_bounce_gi); operator 2026-09-02, looking at /world/beach: "that looks like
our junk cpu stuff ... lets get things infinigen generating to photoreal". Infinigen renders offline through a path
tracer; this organ is that twin, first byte up: no float, no library, no third party -- the same fx1024 arithmetic,
the same fBm heightfield (nx_worldgen wg_terrain_h), the same sky model (wg_sky), the same soft-shadow march
(wg_sun_pen) and the same PNG writer the estate already ships. What is NEW is the light transport: every pixel is
the mean of spp Monte Carlo paths, each path = primary ray -> Lambertian hit (direct sun x soft shadow) -> cosine-
weighted bounce (BRDF x cos / pdf = albedo, so no division noise) -> up to GP_BOUNCES hits -> sky gather when the
path escapes. Colour bleed and sky occlusion therefore emerge from transport instead of being painted on, which is
the difference between the raymarcher's "ambient = 42" and a beauty tier.
DETERMINISM: the sampler is a seeded integer LCG advanced per draw; two runs with the same argv are byte-identical,
so a gate can diff frames (the GR10 cache-vs-rebuild law carried into path tracing).
NO TERRACING: the march step grows with distance (footprint-sized) and every hit is REFINED by GP_REFINE bisections,
so the surface lands within a fraction of a unit -- the stair-steps visible in every nx_worldgen slope are gone.
HONEST LIMITS OF THIS FIRST BYTE, stated so the next reader does not credit them: terrain is Lambertian only (no
specular, no BRDF model beyond albedo); water is a single mirror event tinted by a deep colour, not refraction;
the sky is nx_worldgen's gradient+sun+cloud model, not GR26's Rayleigh/Mie atmosphere; no cast meshes yet; no
depth/normal/semantic ground-truth siblings yet (the dataset half of GR42). Each of those is a named rung.
UNITS: directions are fx1024 unit vectors; radiance is carried as throughput(fx1024) x colour(0..255), then averaged,
Reinhard-mapped and display-encoded ONCE at output (GR14's linear-light law: all transport in linear).
nx_gi_path <out.png> [seed] [spp] [weather 0 clear | 1 sunset | 2 overcast] [yaw 0..4095]
exit: 0 written | 2 usage | 5 png-write-fail. license_tier: ORIGINAL No hw writes (Rule 26).
dependencies 5 imports · 2 importers
imports: nx_syscalls.nxnx_itrig.nxnx_vecmath.nxnx_worldgen.nxnx_png_write.nx
imported by: nx_gi_path.nxnx_gi_path_gate.nx
structs
| none |
consts
| 33 | const GP_FRAC_NUM: i64 = 3 |
| 34 | const GP_FRAC_DEN: i64 = 8 |
| 35 | const GP_FX: i64 = 1024 // the estate's fixed-point unit, the one nx_worldgen's vectors already use |
| 36 | const GP_HALF: i64 = 512 // half a fx unit: the pixel-jitter recentring term |
| 37 | const GP_CIRCLE: i64 = 4096 // it_sin4096: 4096 angle units per turn AND amplitude 4096 |
| 38 | const GP_SPP_DEFAULT: i64 = 4 |
| 39 | const GP_BOUNCES: i64 = 2 // primary + 2 diffuse bounces: the shortest transport that carries colour bleed AND sky occlusion |
| 40 | const GP_T0: i64 = 4 // first march distance in front of an origin |
| 41 | const GP_BIAS: i64 = 8 // bounce origin lifted along the normal so a path never re-hits its own surface |
| 42 | const GP_TMAX: i64 = 60000 // nx_worldgen's far plane |
| 43 | const GP_SKY_Y: i64 = 2900 // nx_worldgen's sun-march ceiling: no terrain exists above it |
| 44 | const GP_STEP_MIN: i64 = 6 |
| 45 | const GP_STEP_DIV: i64 = 96 // step = min + t/96: half the raymarcher's growth (t/48), then bisection-refined |
| 46 | const GP_REFINE: i64 = 8 // bisections per hit: the last step / 256 -> sub-unit placement, no terracing |
| 47 | const GP_MAX_STEPS: i64 = 400 |
| 48 | const GP_NRM_EPS: i64 = 24 // the raymarcher's normal footprint, kept so both tiers agree on the same surface |
| 49 | const GP_SUN_OVER_SKY: i64 = 2 // sun irradiance relative to the sky dome on a Lambertian surface; DECLARED, to be fitted against the reference frame |
| 50 | const GP_EXPOSURE_NUM: i64 = 3 // Reinhard exposure 3/2 |
| 51 | const GP_EXPOSURE_DEN: i64 = 2 |
| 52 | const GP_MAXCH: i64 = 255 // display channel ceiling, the PNG's own |
| 53 | const GP_LCG_A: i64 = 1103515245 // the classic 31-bit LCG (Numerical Recipes / glibc rand family) |
| 54 | const GP_LCG_C: i64 = 12345 |
| 55 | const GP_LCG_MASK: i64 = 2147483647 |
| 56 | const GP_RND_SHIFT: i64 = 11 // drop the weak low bits of the LCG |
| 57 | const GP_RND_MASK: i64 = 1023 // a draw is an fx1024 fraction |
| 58 | const GP_AXIS_TILT: i64 = 600 // |n.x| above this: pick z as the helper axis when building the tangent frame |
| 59 | const GP_STEEP_NY: i64 = 640 // the raymarcher's rock threshold on the normal's y |
| 60 | const GP_SAND_BAND: i64 = 130 // the raymarcher's shoreline band above water |
| 61 | const GP_SNOW_NY: i64 = 600 // the raymarcher's snow slope threshold |
| 62 | const GP_VEG_SCALE: i64 = 1500 // the raymarcher's vegetation patch scale (world units per noise cell) |
| 63 | const GP_VEG_SEED: i64 = 99 |
| 64 | const GP_NOISE_SPAN: i64 = 65536 // wg_vnoise range |
| 66 | const GP_GRASS_R: i64 = 60 |
| 67 | const GP_GRASS_G: i64 = 94 |
| 68 | const GP_GRASS_B: i64 = 42 |
| 69 | const GP_GRASS_VR: i64 = 44 |
| 70 | const GP_GRASS_VG: i64 = 50 |
| 71 | const GP_GRASS_VB: i64 = 22 |
| 72 | const GP_ROCK_R: i64 = 112 |
| 73 | const GP_ROCK_G: i64 = 101 |
| 74 | const GP_ROCK_B: i64 = 92 |
| 75 | const GP_SAND_R: i64 = 198 |
| 76 | const GP_SAND_G: i64 = 186 |
| 77 | const GP_SAND_B: i64 = 152 |
| 78 | const GP_SNOW_R: i64 = 234 |
| 79 | const GP_SNOW_G: i64 = 240 |
| 80 | const GP_SNOW_B: i64 = 248 |
| 81 | const GP_WATER_R: i64 = 24 |
| 82 | const GP_WATER_G: i64 = 74 |
| 83 | const GP_WATER_B: i64 = 116 |
| 84 | const GP_OUT: i64 = 4096 |
| 85 | const GP_WORDS: i64 = 16 // scratch vectors are 16 words each (page-rounded by mmap anyway) |
| 86 | const GP_EXIT_OK: i64 = 0 |
| 87 | const GP_EXIT_USAGE: i64 = 2 |
| 88 | const GP_EXIT_WRITE: i64 = 5 |
| 89 | const GP_CH_0: i64 = 48 |
| 90 | const GP_CH_9: i64 = 57 |
| 91 | const GP_CH_MINUS: i64 = 45 |
| 92 | const GP_ST_SKY: i64 = 0 |
| 93 | const GP_ST_WATER: i64 = 1 |
| 94 | const GP_ST_TERRAIN: i64 = 2 |
| 95 | const GP_ST_MARCHES: i64 = 3 |
functions
| 97 | func gp_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } |
| 98 | func gp_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; var p: i64 = o; while s[i] != (0 as u8) { d[p] = s[i]; p = p + 1; i = i + 1 } return p } called by 1: main |
| 99 | func gp_num(d: *u8, o: i64, v: i64) -> i64 |
| 112 | func gp_atoi(s: *u8) -> i64 called by 1: main |
| 125 | func gp_clamp(v: i64, lo: i64, hi: i64) -> i64 { if v < lo { return lo } if v > hi { return hi } return v } |
| 131 | func gp_lin(c: i64) -> i64 { let v: i64 = gp_clamp(c, 0, GP_MAXCH); return v*v*GP_FX/GP_MAXCH } |
| 133 | func gp_rnd(st: *i64) -> i64 |
| 138 | func gp_norm3(v: *i64) -> i64 |
| 146 | func gp_march(ox: i64, oy: i64, oz: i64, dx: i64, dy: i64, dz: i64, seed: i64, out: *i64) -> i64 |
| 190 | func gp_normal(hx: i64, hz: i64, seed: i64, n: *i64) -> i64 |
| 203 | func gp_albedo(hx: i64, hz: i64, hh: i64, ny: i64, seed: i64, a: *i64) -> i64 |
| 214 | func gp_cosine_dir(n: *i64, st: *i64, scr: *i64, d: *i64) -> i64 |
| 245 | func gp_trace(ox: i64, oy: i64, oz: i64, dx: i64, dy: i64, dz: i64, seed: i64, Wp: *i64, st: *i64, |
| 309 | func gp_encode(m: i64) -> i64 |