code wiki / _hdl_build / nx_cornell_dyn_gate.nx

nx_cornell_dyn_gate.nx source

↩ module page · 121 lines · 6126 B

1// nx_cornell_dyn_gate.nx -- ★R3 DYNAMIC GI (the Lumen direction, taken the fusion way): the radiosity REACTS to scene 2// changes. Form factors are CACHED (the Surface-Cache move); a moved LIGHT invalidates only its own pairs (~20x less 3// work, integer-EXACTLY equal to a from-scratch rebuild -- a proof only a bit-exact stack can make); moved GEOMETRY 4// recomputes occlusion and the SHADOW RELOCATES. All effects measured on patch radiosities, evidence rendered. 5// T1 light moves -> bleeding shifts (incremental). T2 incremental == full rebuild EXACTLY. T3 block moves -> shadow 6// relocates. T4 evidence (baseline | light moved | block moved). license_tier: ORIGINAL expect_exit: 0 7import "nx_syscalls.nx" 8import "nx_png.nx" 9import "nx_trimesh.nx" 10import "nx_cornell.nx" 11 12func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 13func pn(v: i64) -> i64 { let b: *u8=sys_mmap(32) as *u8; var x: i64=v; var ng: i64=0; if x<0{ng=1;x=0-x} var i: i64=31; if x==0{b[i]=48 as u8;i=i-1} while x>0{b[i]=(48+x%10) as u8;x=x/10;i=i-1} if ng==1{b[i]=45 as u8;i=i-1} sys_write(1,(b as i64+i+1) as *u8,31-i); return 0 } 14func clearfb(fb: *i64, n: i64, c: i64) -> i64 { var i: i64=0; while i<n { fb[i]=c; i=i+1 } return 0 } 15 16const BG: i64 = 10 + 10*256 + 14*65536 17const W: i64 = 360 18const H: i64 = 380 19 20func col_rg(i: i64) -> i64 { 21 let b3: *i64 = sys_mmap(24) as *i64 22 var s: i64 = 0 23 var j: i64 = 0 24 while j < 12 { cor_b(200 + i*12 + j, b3); s = s + (b3[0] - b3[1]); j = j + 1 } 25 return s/12 26} 27func floor_near(x: i64, z: i64) -> i64 { 28 let c3: *i64 = sys_mmap(24) as *i64 29 var best: i64 = 0-1 30 var bd: i64 = 9000000000 31 var i: i64 = 0 32 while i < 100 { 33 cor_center(i, c3) 34 let dx: i64 = c3[0]-x 35 let dz: i64 = c3[2]-z 36 let d: i64 = dx*dx + dz*dz 37 if d < bd { bd = d; best = i } 38 i = i + 1 39 } 40 return best 41} 42func lum(i: i64) -> i64 { let b3: *i64 = sys_mmap(24) as *i64; cor_b(i, b3); return (b3[0]+b3[1]+b3[2])/3 } 43func rendpanel(gal: *i64, GW: i64, slot: i64) -> i64 { 44 let npx: i64 = W*H 45 let fb: *i64 = sys_mmap(npx*8) as *i64 46 let zb: *i64 = sys_mmap(npx*8) as *i64 47 cornell_tomesh(1900) 48 clearfb(fb, npx, BG) 49 trimesh_zclear(zb, npx) 50 trimesh_render(fb, zb, W, H, 0, 0, 800, 500, 3) 51 var y: i64 = 0 52 while y < H { var x: i64=0; while x<W { gal[y*GW+slot*W+x]=fb[y*W+x]; x=x+1 } y=y+1 } 53 return 0 54} 55 56func main() -> i64 { 57 hw("=== nx_cornell_dyn_gate -- R3 DYNAMIC GI: cached form factors + incremental invalidation, exact ===\n" as *u8) 58 var fails: i64 = 0 59 tm_set_spec(0) 60 tm_set_tex(0) 61 tm_set_image(0 as *u8, 0, 0) 62 let np: i64 = cornell_build() 63 let fullWork: i64 = cornell_formfactors() 64 cornell_solve(4) 65 let GW: i64 = W*3 66 let gal: *i64 = sys_mmap(GW*H*8) as *i64 67 clearfb(gal, GW*H, BG) 68 rendpanel(gal, GW, 0) 69 let base_red: i64 = col_rg(0) 70 let base_grn: i64 = 0 - col_rg(11) 71 hw(" baseline: patches="); pn(np); hw(" F-pairs="); pn(fullWork); hw(" red-side bleed=+"); pn(base_red); hw(" green-side=+"); pn(base_grn); hw("\n" as *u8) 72 73 // ---- T1 DYNAMIC LIGHT: slide the lamp toward the RED wall; invalidate only its pairs ---- 74 cornell_move_light(0-140, 0) 75 let partWork: i64 = cornell_ff_partial(544, 560) 76 cornell_solve(4) 77 rendpanel(gal, GW, 1) 78 let l_red: i64 = col_rg(0) 79 let l_grn: i64 = 0 - col_rg(11) 80 hw(" light moved toward red: red-side=+"); pn(l_red); hw(" green-side=+"); pn(l_grn); hw(" incremental work="); pn(partWork); hw(" pairs (full="); pn(fullWork); hw(", x10 ratio="); pn(fullWork*10/partWork); hw(")\n" as *u8) 81 var t1: i64 = 0 82 if l_red > base_red { if l_grn < base_grn { if partWork*10 < fullWork { t1 = 1 } } } 83 if t1 == 1 { hw("T1 PASS DYNAMIC LIGHT: the GI field REACTS (red bleed up, green down) via incremental invalidation (>10x less work than rebuild)\n" as *u8) } 84 else { fails=fails+1; hw("T1 FAIL\n" as *u8) } 85 86 // ---- T2 EXACTNESS: incremental result == full rebuild, bit for bit ---- 87 let keep_red: i64 = l_red 88 let keep_grn: i64 = l_grn 89 let keep_f15: i64 = lum(floor_near(0-230, 330)) 90 cornell_formfactors() 91 cornell_solve(4) 92 var t2: i64 = 0 93 if col_rg(0) == keep_red { if (0-col_rg(11)) == keep_grn { if lum(floor_near(0-230,330)) == keep_f15 { t2 = 1 } } } 94 if t2 == 1 { hw("T2 PASS EXACT: incremental invalidation == from-scratch rebuild BIT-FOR-BIT (integer determinism -- a proof float engines cannot make)\n" as *u8) } 95 else { fails=fails+1; hw("T2 FAIL\n" as *u8) } 96 97 // ---- T3 DYNAMIC GEOMETRY: slide the tall block +300 -> the shadow must RELOCATE ---- 98 let oldSh: i64 = floor_near(0-230, 330) 99 let newSh: i64 = floor_near(350, 330) 100 let preOld: i64 = lum(oldSh) 101 let preNew: i64 = lum(newSh) 102 cornell_move_tall(300) 103 cornell_formfactors() // occlusion changed globally -> full recompute (honest) 104 cornell_solve(4) 105 rendpanel(gal, GW, 2) 106 let postOld: i64 = lum(oldSh) 107 let postNew: i64 = lum(newSh) 108 hw(" block moved +300: old-shadow lum "); pn(preOld); hw("->"); pn(postOld); hw(" new-shadow lum "); pn(preNew); hw("->"); pn(postNew); hw("\n" as *u8) 109 var t3: i64 = 0 110 if postOld*10 > preOld*14 { if postNew*10 < preNew*7 { t3 = 1 } } 111 if t3 == 1 { hw("T3 PASS DYNAMIC GEOMETRY: the shadow RELOCATES with the moved occluder (old spot brightens >=1.4x, new spot darkens <=0.7x)\n" as *u8) } 112 else { fails=fails+1; hw("T3 FAIL\n" as *u8) } 113 114 write_png(gal, GW, H, "knowledge/nx_cornell_dyn.png" as *u8) 115 hw("T4 evidence -> knowledge/nx_cornell_dyn.png (baseline | light moved | block moved)\n" as *u8) 116 117 if fails == 0 { hw("CORNELL-DYN-GATE GREEN -- R3 dynamic GI: cached form factors + incremental invalidation (Surface-Cache-kin), light AND geometry changes re-light the scene correctly, incremental == rebuild EXACTLY. Residual vs Lumen: per-frame scale, specular reflections, screen traces.\n" as *u8); sys_exit(0); return 0 } 118 hw("CORNELL-DYN-GATE RED fails="); pn(fails); hw("\n" as *u8) 119 sys_exit(1) 120 return 1 121}