code wiki / _hdl_build / nx_viz3d.nx

nx_viz3d.nx source

↩ module page · 92 lines · 4717 B

1// nx_viz3d.nx -- LIB: the SOVEREIGN 3D viewport (foundation of Nishi first-party 3D visualization). Operator: 2// "for all these 3d simulations and visualization from games to cad to stls to blender to zbrush ... lets get our 3// nishi browser and 3rd party visualization and management s class exceed so i can see these things." 4// 5// This is the BEDROCK: fixed-point (NO-FLOAT, sovereign) 3D math -- rotate a point around Y, perspective-project it 6// to 2D screen space -- so a mesh (vertices + edges/triangles) can be rendered to SVG and viewed/animated in the 7// Nishi browser with 0 JavaScript. Fixed-point scale = 1024 (10-bit fraction); a 12-entry sin table (30 deg steps) 8// drives a turntable. Integer division throughout; the camera distance keeps z+DIST > 0 so projection never divides 9// by zero. NEVER-BRICK (#26): pure integer, bounded, deterministic, zero hardware-state writes. 10// license_tier: ORIGINAL 11import "nx_syscalls.nx" 12const VP_MAGIC_1024: i64 = 1024 13 14const VP_DIST: i64 = 400 // camera distance (keeps z+DIST > 0 for objects within +/-150) 15const VP_FOCAL: i64 = 300 // focal length (perspective strength) 16const VP_CX: i64 = 300 // screen center x 17const VP_CY: i64 = 210 // screen center y 18const VP_SCALE: i64 = 1024 // fixed-point fraction (sin/cos are x1024) 19 20// fill a 12-entry sin table (sin(i*30deg) x 1024). cos(a) = sin(a+90deg) = tbl[(i+3)%12]. 21func vp_fill_sin(tbl: *i64) -> i64 { 22 tbl[0]=0; tbl[1]=512; tbl[2]=887; tbl[3]=VP_MAGIC_1024; tbl[4]=887; tbl[5]=512 23 tbl[6]=0; tbl[7]=0-512; tbl[8]=0-887; tbl[9]=0-VP_MAGIC_1024; tbl[10]=0-887; tbl[11]=0-512 24 return 0 25} 26func vp_idx(i: i64) -> i64 { return ((i % 12) + 12) % 12 } 27 28// rotate (x,y,z) around the Y axis by angle index `ang` (each step = 30 deg), perspective-project to screen. 29// writes pp[0]=screen_x, pp[1]=screen_y. tbl = the sin table (so it is corruptible / swappable). 30func vp_project(x: i64, y: i64, z: i64, ang: i64, tbl: *i64, pp: *i64) -> i64 { 31 let s: i64 = tbl[vp_idx(ang)] 32 let c: i64 = tbl[vp_idx(ang + 3)] 33 let xr: i64 = (x*c - z*s) / VP_SCALE // rotated x 34 let zr: i64 = (x*s + z*c) / VP_SCALE // rotated z 35 let zd: i64 = zr + VP_DIST // camera-space depth (> 0) 36 pp[0] = VP_CX + (xr * VP_FOCAL) / zd 37 pp[1] = VP_CY - (y * VP_FOCAL) / zd 38 return 0 39} 40 41// rotate (x,y,z) around Y -> the rotated CAMERA-SPACE point (for depth-sort + shading). out[0..2] = xr,yr,zr. 42func vp_rotate(x: i64, y: i64, z: i64, ang: i64, tbl: *i64, out: *i64) -> i64 { 43 let s: i64 = tbl[vp_idx(ang)]; let c: i64 = tbl[vp_idx(ang + 3)] 44 out[0] = (x*c - z*s) / VP_SCALE 45 out[1] = y 46 out[2] = (x*s + z*c) / VP_SCALE 47 return 0 48} 49// rotate (x,y,z) around X by `ax` THEN around Y by `ay` (each step = 30 deg) -> camera-space point. For arbitrary 50// viewing orientation (tilt + turn) so e.g. a board's top face can be angled toward the camera. 51func vp_rotate_xy(x: i64, y: i64, z: i64, ax: i64, ay: i64, tbl: *i64, out: *i64) -> i64 { 52 let sx: i64 = tbl[vp_idx(ax)]; let cx: i64 = tbl[vp_idx(ax + 3)] 53 let sy: i64 = tbl[vp_idx(ay)]; let cy: i64 = tbl[vp_idx(ay + 3)] 54 let y1: i64 = (y*cx - z*sx) / VP_SCALE 55 let z1: i64 = (y*sx + z*cx) / VP_SCALE 56 out[0] = (x*cy - z1*sy) / VP_SCALE 57 out[1] = y1 58 out[2] = (x*sy + z1*cy) / VP_SCALE 59 return 0 60} 61// perspective-project an already-rotated point to screen. 62func vp_project_pt(xr: i64, yr: i64, zr: i64, pp: *i64) -> i64 { 63 let zd: i64 = zr + VP_DIST 64 pp[0] = VP_CX + (xr * VP_FOCAL) / zd 65 pp[1] = VP_CY - (yr * VP_FOCAL) / zd 66 return 0 67} 68// integer square root (Newton). isqrt(144)=12. 69func vp_isqrt(n: i64) -> i64 { 70 if n <= 0 { return 0 } 71 var x: i64 = n; var y: i64 = (x + 1) / 2 72 while y < x { x = y; y = (x + n/x) / 2 } 73 return x 74} 75// cross product out = a x b. 76func vp_cross(ax: i64, ay: i64, az: i64, bx: i64, by: i64, bz: i64, out: *i64) -> i64 { 77 out[0] = ay*bz - az*by 78 out[1] = az*bx - ax*bz 79 out[2] = ax*by - ay*bx 80 return 0 81} 82// flat-shade brightness (60..255) of a triangle from its 3 rotated verts: faces toward the camera are bright, 83// edge-on dark (view-space lighting, winding-independent via |Nz|/|N|). 84func vp_shade(p0: *i64, p1: *i64, p2: *i64) -> i64 { 85 let n: *i64 = sys_mmap(32) as *i64 86 vp_cross(p1[0]-p0[0], p1[1]-p0[1], p1[2]-p0[2], p2[0]-p0[0], p2[1]-p0[1], p2[2]-p0[2], n) 87 var nz: i64 = n[2]; if nz < 0 { nz = 0 - nz } 88 let nlen: i64 = vp_isqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]) 89 var nl: i64 = nlen; if nl == 0 { nl = 1 } 90 let align: i64 = nz * 256 / nl // 0..256 (256 = face-on to camera) 91 return 60 + align * 195 / 256 // 60..255 92}