code wiki / _hdl_build / nx_phong_gate.nx
nx_phong_gate.nx source
↩ module page · 88 lines · 5207 B
1// nx_phong_gate.nx -- ★F3 BLINN-PHONG specular: prove a real specular HIGHLIGHT (a bright near-white spot where the
2// half-vector aligns with the normal) that flat/Lambert matte shading cannot produce. T1 shiny sphere has bright
3// highlight pixels, matte does not. T2 determinism. T3 gallery (sphere matte | sphere shiny | being shiny w/ skin sheen).
4// license_tier: ORIGINAL expect_exit: 0
5import "nx_syscalls.nx"
6import "nx_png.nx"
7import "nx_trimesh.nx"
8import "nx_isosurf.nx"
9import "nx_bodyatlas.nx"
10
11func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
12func 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 }
13func clearfb(fb: *i64, n: i64, c: i64) -> i64 { var i: i64=0; while i<n { fb[i]=c; i=i+1 } return 0 }
14// count near-white (specular) pixels: all channels high
15func bright(fb: *i64, n: i64) -> i64 { var c: i64=0; var i: i64=0; while i<n { let p: i64=fb[i]; if (p&255)>210 { if ((p>>8)&255)>210 { if ((p>>16)&255)>210 { c=c+1 } } } i=i+1 } return c }
16
17const BG: i64 = 24 + 26*256 + 34*65536
18const W: i64 = 300
19const H: i64 = 340
20
21func main() -> i64 {
22 hw("=== nx_phong_gate -- F3 Blinn-Phong specular highlight ===\n" as *u8)
23 var fails: i64 = 0
24 let npx: i64 = W*H
25 let fb: *i64 = sys_mmap(npx*8) as *i64
26 let zb: *i64 = sys_mmap(npx*8) as *i64
27
28 // a smooth sphere (mid-blue so a white highlight contrasts)
29 tm_reset()
30 tm_uvsphere(0, 0, 0, 150, 20, 28, 90 + 120*256 + 200*65536)
31 tm_compute_normals()
32
33 tm_set_spec(0)
34 clearfb(fb, npx, BG); trimesh_zclear(zb, npx); trimesh_render(fb, zb, W, H, 400, 0-300, 1400, 520, 1)
35 let matte: i64 = bright(fb, npx)
36 tm_set_spec(140)
37 clearfb(fb, npx, BG); trimesh_zclear(zb, npx); trimesh_render(fb, zb, W, H, 400, 0-300, 1400, 520, 1)
38 let shiny: i64 = bright(fb, npx)
39 hw(" sphere bright(near-white) pixels: matte="); pn(matte); hw(" shiny="); pn(shiny); hw("\n" as *u8)
40 var t1: i64 = 0
41 if matte < 40 { if shiny > 100 { t1 = 1 } }
42 if t1 == 1 { hw("T1 PASS SPECULAR: a real highlight appears with spec on ("); pn(shiny); hw(" bright px) that matte lacks ("); pn(matte); hw(")\n" as *u8) }
43 else { fails=fails+1; hw("T1 FAIL matte="); pn(matte); hw(" shiny="); pn(shiny); hw("\n" as *u8) }
44
45 // T2 determinism (spec on)
46 let f2: *i64 = sys_mmap(npx*8) as *i64
47 clearfb(f2, npx, BG); trimesh_zclear(zb, npx); trimesh_render(f2, zb, W, H, 400, 0-300, 1400, 520, 1)
48 var diff: i64 = 0; var i: i64 = 0
49 while i < npx { if f2[i]!=fb[i] { diff=diff+1 } i=i+1 }
50 var t2: i64 = 0
51 if diff == 0 { t2 = 1 }
52 if t2 == 1 { hw("T2 PASS deterministic\n" as *u8) } else { fails=fails+1; hw("T2 FAIL diff="); pn(diff); hw("\n" as *u8) }
53
54 // T3 gallery: sphere matte | sphere shiny | being skin w/ sheen
55 let GW: i64 = W*3
56 let gal: *i64 = sys_mmap(GW*H*8) as *i64
57 clearfb(gal, GW*H, BG)
58 let cell: *i64 = sys_mmap(npx*8) as *i64
59 // cell 0 matte, cell 1 shiny (sphere)
60 tm_reset(); tm_uvsphere(0,0,0,150,20,28, 90+120*256+200*65536); tm_compute_normals()
61 tm_set_spec(0); clearfb(cell,npx,BG); trimesh_zclear(zb,npx); trimesh_render(cell,zb,W,H,400,0-300,1400,520,1)
62 var y: i64=0
63 while y<H { var x: i64=0; while x<W { gal[y*GW+x]=cell[y*W+x]; x=x+1 } y=y+1 }
64 tm_set_spec(150); clearfb(cell,npx,BG); trimesh_zclear(zb,npx); trimesh_render(cell,zb,W,H,400,0-300,1400,520,1)
65 y=0
66 while y<H { var x: i64=0; while x<W { gal[y*GW+W+x]=cell[y*W+x]; x=x+1 } y=y+1 }
67 // cell 2: being skin mesh with a subtle sheen
68 atlas_build(0)
69 let GXb: i64=32; let GYb: i64=110; let GZb: i64=20; let GCb: i64=18
70 let grid: *i64 = sys_mmap((GXb+1)*(GYb+1)*(GZb+1)*8) as *i64
71 i=0
72 while i<=GXb { var jj: i64=0; while jj<=GYb { var k: i64=0; while k<=GZb { grid[(i*(GYb+1)+jj)*(GZb+1)+k]=ba_sdf(0-288+i*GCb, 0-990+jj*GCb, 0-180+k*GCb, 1); k=k+1 } jj=jj+1 } i=i+1 }
73 tm_reset(); surface_nets(grid, GXb,GYb,GZb, 0-288,0-990,0-180, GCb, 0, 216+172*256+152*65536)
74 let vp: *i64=sys_mmap(24) as *i64
75 i=0; let nv: i64=tm_nv()
76 while i<nv { tm_vpos(i,vp); let kk: i64=ba_nearest(vp[0],vp[1],vp[2],1); if kk>=0 { tm_vcol(i,ba_part_color(kk)) } else { tm_vcol(i,216+172*256+152*65536) } i=i+1 }
77 tm_set_spec(70) // subtle skin sheen
78 clearfb(cell,npx,BG); trimesh_zclear(zb,npx); trimesh_render(cell,zb,W,H,2400,0-260,2900,520,2)
79 y=0
80 while y<H { var x: i64=0; while x<W { gal[y*GW+2*W+x]=cell[y*W+x]; x=x+1 } y=y+1 }
81 write_png(gal, GW, H, "knowledge/nx_phong.png" as *u8)
82 hw("T3 gallery -> knowledge/nx_phong.png (sphere matte | sphere shiny | being w/ skin sheen)\n" as *u8)
83
84 if fails == 0 { hw("PHONG-GATE GREEN -- F3 Blinn-Phong specular: real highlights (opt-in tm_set_spec, zero-cost off), per-vertex + interpolated. Census Phong GAP->HAVE. Residual: per-material roughness/metalness (PBR) + textures.\n" as *u8); sys_exit(0); return 0 }
85 hw("PHONG-GATE RED fails="); pn(fails); hw("\n" as *u8)
86 sys_exit(1)
87 return 1
88}