code wiki / (root) / nx_gi_path.nx

nx_gi_path.nx source

↩ module page · 126 lines · 7302 B

1// nx_gi_path.nx -- THE BEAUTY TIER'S FIRST BYTE: a sovereign INTEGER PATH TRACER over the procgen heightfield. 2// graphics GR42 (env_beauty_scene) + GR10 (gp_bounce_gi); operator 2026-09-02, looking at /world/beach: "that looks like 3// our junk cpu stuff ... lets get things infinigen generating to photoreal". Infinigen renders offline through a path 4// tracer; this organ is that twin, first byte up: no float, no library, no third party -- the same fx1024 arithmetic, 5// the same fBm heightfield (nx_worldgen wg_terrain_h), the same sky model (wg_sky), the same soft-shadow march 6// (wg_sun_pen) and the same PNG writer the estate already ships. What is NEW is the light transport: every pixel is 7// the mean of spp Monte Carlo paths, each path = primary ray -> Lambertian hit (direct sun x soft shadow) -> cosine- 8// weighted bounce (BRDF x cos / pdf = albedo, so no division noise) -> up to GP_BOUNCES hits -> sky gather when the 9// path escapes. Colour bleed and sky occlusion therefore emerge from transport instead of being painted on, which is 10// the difference between the raymarcher's "ambient = 42" and a beauty tier. 11// 12// DETERMINISM: the sampler is a seeded integer LCG advanced per draw; two runs with the same argv are byte-identical, 13// so a gate can diff frames (the GR10 cache-vs-rebuild law carried into path tracing). 14// NO TERRACING: the march step grows with distance (footprint-sized) and every hit is REFINED by GP_REFINE bisections, 15// so the surface lands within a fraction of a unit -- the stair-steps visible in every nx_worldgen slope are gone. 16// HONEST LIMITS OF THIS FIRST BYTE, stated so the next reader does not credit them: terrain is Lambertian only (no 17// specular, no BRDF model beyond albedo); water is a single mirror event tinted by a deep colour, not refraction; 18// the sky is nx_worldgen's gradient+sun+cloud model, not GR26's Rayleigh/Mie atmosphere; no cast meshes yet; no 19// depth/normal/semantic ground-truth siblings yet (the dataset half of GR42). Each of those is a named rung. 20// UNITS: directions are fx1024 unit vectors; radiance is carried as throughput(fx1024) x colour(0..255), then averaged, 21// Reinhard-mapped and display-encoded ONCE at output (GR14's linear-light law: all transport in linear). 22// 23// nx_gi_path <out.png> [seed] [spp] [weather 0 clear | 1 sunset | 2 overcast] [yaw 0..4095] 24// exit: 0 written | 2 usage | 5 png-write-fail. license_tier: ORIGINAL No hw writes (Rule 26). 25import "nx_syscalls.nx" 26import "nx_gi_path_lib.nx" 27 28// THE BOARD'S CONTRACT SYMBOL (graphics GR10 gp_bounce_gi): one bounce-lit path estimate for a ray. The watch row 29// on /compare/graphics flips when this symbol exists in this organ; the flip is the receipt, the GR42 gate is the proof. 30func gp_bounce_gi(ox: i64, oy: i64, oz: i64, dx: i64, dy: i64, dz: i64, seed: i64, Wp: *i64, st: *i64, 31 hitb: *i64, n: *i64, alb: *i64, scr: *i64, dir: *i64, sky: *i64, L: *i64, stats: *i64) -> i64 { 32 return gp_trace(ox, oy, oz, dx, dy, dz, seed, Wp, st, hitb, n, alb, scr, dir, sky, L, stats) 33} 34 35func main(argc: i64, argv: *i64) -> i64 { 36 let out: *u8 = sys_mmap(GP_OUT) 37 if argc < 2 { 38 var uo: i64 = gp_cat(out, 0, "usage: nx_gi_path <out.png> [seed] [spp] [weather 0 clear|1 sunset|2 overcast] [yaw 0..4095] -- sovereign integer path tracer over the procgen heightfield\n" as *u8) 39 sys_write(1, out, uo) 40 sys_exit(GP_EXIT_USAGE); return GP_EXIT_USAGE 41 } 42 let path: *u8 = argv[1] as *u8 43 var seed: i64 = 77 44 if argc >= 3 { seed = gp_atoi(argv[2] as *u8) } 45 var spp: i64 = GP_SPP_DEFAULT 46 if argc >= 4 { spp = gp_atoi(argv[3] as *u8) } 47 if spp < 1 { spp = 1 } 48 var mode: i64 = 0 49 if argc >= 5 { mode = gp_atoi(argv[4] as *u8) } 50 var yaw: i64 = 0 51 if argc >= 6 { yaw = gp_atoi(argv[5] as *u8) } 52 let gw: i64 = wg_w()*GP_FRAC_NUM/GP_FRAC_DEN 53 let gh: i64 = wg_h()*GP_FRAC_NUM/GP_FRAC_DEN 54 let focal: i64 = WG_FOCAL*GP_FRAC_NUM/GP_FRAC_DEN 55 let horizon: i64 = WG_HORIZON*GP_FRAC_NUM/GP_FRAC_DEN 56 let Wp: *i64 = sys_mmap(32*8) as *i64 57 wg_weather(mode, Wp) 58 let hitb: *i64 = sys_mmap(GP_WORDS*8) as *i64 59 let n: *i64 = sys_mmap(GP_WORDS*8) as *i64 60 let alb: *i64 = sys_mmap(GP_WORDS*8) as *i64 61 let scr: *i64 = sys_mmap(GP_WORDS*8) as *i64 62 let dir: *i64 = sys_mmap(GP_WORDS*8) as *i64 63 let sky: *i64 = sys_mmap(GP_WORDS*8) as *i64 64 let L: *i64 = sys_mmap(GP_WORDS*8) as *i64 65 let stats: *i64 = sys_mmap(GP_WORDS*8) as *i64 66 let st: *i64 = sys_mmap(GP_WORDS*8) as *i64 67 let d: *i64 = sys_mmap(GP_WORDS*8) as *i64 68 st[0] = seed*GP_LCG_A + GP_LCG_C 69 let acc: *i64 = sys_mmap(gw*gh*3*8) as *i64 70 let rgb: *u8 = sys_mmap(gw*gh*3 + 16) 71 let t0: i64 = sys_now_ms() 72 let camx: i64 = 0 73 let camy: i64 = wg_cam_base_y(seed) 74 let camz: i64 = 0 75 let sy4: i64 = it_sin4096(yaw) 76 let cy4: i64 = it_cos4096(yaw) 77 var py: i64 = 0 78 while py < gh { 79 var px: i64 = 0 80 while px < gw { 81 let pi: i64 = (py*gw + px)*3 82 var s: i64 = 0 83 while s < spp { 84 let jx: i64 = gp_rnd(st) 85 let jy: i64 = gp_rnd(st) 86 let sxo: i64 = (px - gw/2)*GP_FX + jx - GP_HALF 87 let syo: i64 = ((gh/2 - py) - horizon)*GP_FX + jy - GP_HALF 88 d[0] = focal*GP_FX*sy4/GP_CIRCLE + sxo*cy4/GP_CIRCLE 89 d[1] = syo 90 d[2] = focal*GP_FX*cy4/GP_CIRCLE - sxo*sy4/GP_CIRCLE 91 gp_norm3(d) 92 gp_bounce_gi(camx, camy, camz, d[0], d[1], d[2], seed, Wp, st, hitb, n, alb, scr, dir, sky, L, stats) 93 acc[pi] = acc[pi] + L[0] 94 acc[pi + 1] = acc[pi + 1] + L[1] 95 acc[pi + 2] = acc[pi + 2] + L[2] 96 s = s + 1 97 } 98 rgb[pi] = gp_encode(acc[pi]/spp) as u8 99 rgb[pi + 1] = gp_encode(acc[pi + 1]/spp) as u8 100 rgb[pi + 2] = gp_encode(acc[pi + 2]/spp) as u8 101 px = px + 1 102 } 103 py = py + 1 104 } 105 let ms: i64 = sys_now_ms() - t0 106 let wrc: i64 = nx_png_write_rgb(path, rgb, gw, gh) 107 var o: i64 = gp_cat(out, 0, "GI-PATH w=" as *u8); o = gp_num(out, o, gw) 108 o = gp_cat(out, o, " h=" as *u8); o = gp_num(out, o, gh) 109 o = gp_cat(out, o, " spp=" as *u8); o = gp_num(out, o, spp) 110 o = gp_cat(out, o, " bounces=" as *u8); o = gp_num(out, o, GP_BOUNCES) 111 o = gp_cat(out, o, " seed=" as *u8); o = gp_num(out, o, seed) 112 o = gp_cat(out, o, " weather=" as *u8); o = gp_num(out, o, mode) 113 o = gp_cat(out, o, " yaw=" as *u8); o = gp_num(out, o, yaw) 114 o = gp_cat(out, o, " marches=" as *u8); o = gp_num(out, o, stats[GP_ST_MARCHES]) 115 o = gp_cat(out, o, " sky_rays=" as *u8); o = gp_num(out, o, stats[GP_ST_SKY]) 116 o = gp_cat(out, o, " water_rays=" as *u8); o = gp_num(out, o, stats[GP_ST_WATER]) 117 o = gp_cat(out, o, " terrain_hits=" as *u8); o = gp_num(out, o, stats[GP_ST_TERRAIN]) 118 o = gp_cat(out, o, " ms=" as *u8); o = gp_num(out, o, ms) 119 o = gp_cat(out, o, " png_rc=" as *u8); o = gp_num(out, o, wrc) 120 o = gp_cat(out, o, " wrote=" as *u8); o = gp_cat(out, o, path) 121 o = gp_cat(out, o, "\n" as *u8) 122 sys_write(1, out, o) 123 if wrc < 0 { sys_exit(GP_EXIT_WRITE); return GP_EXIT_WRITE } 124 sys_exit(GP_EXIT_OK) 125 return GP_EXIT_OK 126}