nx_indoor.nx source
↩ module page · 244 lines · 12060 B
1// nx_indoor.nx -- ★R8 of the Infinigen ladder: INDOOR scenes (their CVPR'24 Infinigen-Indoors track). A room
2// shell (floor/ceiling/4 walls) + procedural FURNITURE placed by a CONSTRAINT SOLVER (rule-based positions +
3// collision rejection + in-bounds) -> a valid, seed-varied furnished room, rendered by an integer AABB interior
4// raycaster (rays from a camera inside the room hit the nearest box; shaded by face + a ceiling light). The
5// constraint-solved layout is the intellectual core (their paper is about realistic arrangement). license_tier: ORIGINAL
6import "nx_syscalls.nx"
7const RM_MAGIC_6364136223846793005: i64 = 6364136223846793005
8const RM_MAGIC_1442695040888963407: i64 = 1442695040888963407
9const RM_MAGIC_2147483647: i64 = 2147483647
10const RM_MAGIC_2654435761: i64 = 2654435761
11const RM_MAGIC_1013904223: i64 = 1013904223
12const RM_MAGIC_65536: i64 = 65536
13const RM_MAGIC_1469598103934665603: i64 = 1469598103934665603
14const RM_MAGIC_1099511628211: i64 = 1099511628211
15const RM_MAGIC_2000000000: i64 = 2000000000
16const RM_MAGIC_1024: i64 = 1024
17
18const RM_W: i64 = 1000 // room x
19const RM_H: i64 = 700 // room y (height)
20const RM_D: i64 = 1200 // room z (depth)
21const IN_STR: i64 = 8 // per-box: x0,y0,z0,x1,y1,z1,color,kind (0 structure / 1 furniture)
22const IN_CAP: i64 = 64
23static IN_BOX: i64 // box list ptr
24static IN_N: i64 // box count
25static IN_NF: i64 // furniture count (subset)
26
27func in_isqrt(x: i64) -> i64 { if x<=0 {return 0} var a: i64=x; var b: i64=(a+1)/2; while b<a {a=b; b=(a+x/a)/2} return a }
28func in_iabs(v: i64) -> i64 { if v<0 {return 0-v} return v }
29func in_min(a: i64, b: i64) -> i64 { if a<b {return a} return b }
30func in_max(a: i64, b: i64) -> i64 { if a>b {return a} return b }
31func in_next(st: *i64) -> i64 { var h: i64=st[0]; h=h*RM_MAGIC_6364136223846793005+RM_MAGIC_1442695040888963407; st[0]=h; return (h>>33)&RM_MAGIC_2147483647 }
32func in_rng(st: *i64, lo: i64, hi: i64) -> i64 { return lo + in_next(st) % (hi-lo+1) }
33
34func in_addbox(x0: i64, y0: i64, z0: i64, x1: i64, y1: i64, z1: i64, col: i64, kind: i64) -> i64 {
35 let B: *i64 = IN_BOX as *i64
36 let i: i64 = IN_N*IN_STR
37 B[i]=x0; B[i+1]=y0; B[i+2]=z0; B[i+3]=x1; B[i+4]=y1; B[i+5]=z1; B[i+6]=col; B[i+7]=kind
38 IN_N = IN_N + 1
39 if kind == 1 { IN_NF = IN_NF + 1 }
40 return 0
41}
42// AABB overlap (with a small clearance margin) between box a and box b
43func in_overlap(ax0: i64, ay0: i64, az0: i64, ax1: i64, ay1: i64, az1: i64, bx0: i64, by0: i64, bz0: i64, bx1: i64, by1: i64, bz1: i64, marg: i64) -> i64 {
44 if ax1+marg <= bx0 { return 0 }
45 if bx1+marg <= ax0 { return 0 }
46 if az1+marg <= bz0 { return 0 }
47 if bz1+marg <= az0 { return 0 }
48 return 1 // overlap on x AND z (footprint) -- y ignored (stacking ok)
49}
50// try to place a furniture box: reject if it overlaps any existing FURNITURE box or leaves the room. 1=placed.
51func in_try_furniture(x0: i64, y0: i64, z0: i64, x1: i64, y1: i64, z1: i64, col: i64) -> i64 {
52 if x0 < 0 { return 0 }
53 if z0 < 0 { return 0 }
54 if x1 > RM_W { return 0 }
55 if z1 > RM_D { return 0 }
56 let B: *i64 = IN_BOX as *i64
57 var k: i64 = 0
58 while k < IN_N {
59 if B[k*IN_STR+7] == 1 {
60 if in_overlap(x0,y0,z0,x1,y1,z1, B[k*IN_STR],B[k*IN_STR+1],B[k*IN_STR+2],B[k*IN_STR+3],B[k*IN_STR+4],B[k*IN_STR+5], 6) == 1 { return 0 }
61 }
62 k = k + 1
63 }
64 in_addbox(x0,y0,z0,x1,y1,z1,col,1)
65 return 1
66}
67
68// ★build a furnished room from a seed: shell + constraint-placed furniture.
69func indoor_build(seed: i64) -> i64 {
70 if IN_BOX == 0 { IN_BOX = sys_mmap(IN_CAP*IN_STR*8) as i64 }
71 IN_N = 0; IN_NF = 0
72 let st: *i64 = sys_mmap(16) as *i64
73 st[0] = seed*RM_MAGIC_2654435761 + RM_MAGIC_1013904223; in_next(st); in_next(st)
74 // ---- shell (thin slabs, camera-outside each) ----
75 in_addbox(0, 0-20, 0, RM_W, 0, RM_D, 92 + 70*256 + 48*RM_MAGIC_65536, 0) // floor (wood)
76 in_addbox(0, RM_H, 0, RM_W, RM_H+20, RM_D, 232 + 230*256 + 222*RM_MAGIC_65536, 0) // ceiling
77 in_addbox(0, 0, RM_D, RM_W, RM_H, RM_D+20, 206 + 198*256 + 180*RM_MAGIC_65536, 0) // back wall (cream)
78 in_addbox(0-20, 0, 0, 0, RM_H, RM_D, 198 + 190*256 + 172*RM_MAGIC_65536, 0) // left wall
79 in_addbox(RM_W, 0, 0, RM_W+20, RM_H, RM_D, 198 + 190*256 + 172*RM_MAGIC_65536, 0) // right wall
80 // rug (floor, seed-jittered center) -- placed first as a floor decal (kind 1 but overlap allowed under others? mark structure)
81 let rcx: i64 = 500 + in_rng(st, 0-60, 60)
82 let rcz: i64 = 560 + in_rng(st, 0-60, 60)
83 in_addbox(rcx-220, 0, rcz-220, rcx+220, 8, rcz+220, 150 + 60*256 + 54*RM_MAGIC_65536, 0) // rug = structure (no collide)
84 // ---- constraint-placed furniture (greedy: rule position + jitter, reject on overlap) ----
85 // bed against back-left wall (slides along the back wall by seed)
86 let bx: i64 = 40 + in_rng(st, 0, 90)
87 let bw: i64 = in_rng(st, 420, 480)
88 in_try_furniture(bx, 0, RM_D-380, bx+bw, 170, RM_D-30, 74 + 96*256 + 150*RM_MAGIC_65536)
89 // nightstand beside the bed
90 in_try_furniture(bx+10+bw, 0, RM_D-150, bx+10+bw+90, 210, RM_D-60, 96 + 70*256 + 44*RM_MAGIC_65536)
91 // lamp on the nightstand
92 in_try_furniture(bx+20+bw, 210, RM_D-135, bx+20+bw+60, 330, RM_D-75, 230 + 210*256 + 120*RM_MAGIC_65536)
93 // dining table (center-front, seed-jittered -- wide jitter for layout variety)
94 let tcx: i64 = 400 + in_rng(st, 0, 170)
95 let tcz: i64 = 360 + in_rng(st, 0, 130)
96 in_try_furniture(tcx-130, 0, tcz-100, tcx+130, 150, tcz+100, 88 + 60*256 + 38*RM_MAGIC_65536)
97 // 4 chairs around the table (each collision-checked -> the solver keeps only the ones that fit)
98 in_try_furniture(tcx-190, 0, tcz-45, tcx-140, 200, tcz+45, 110 + 80*256 + 50*RM_MAGIC_65536)
99 in_try_furniture(tcx+140, 0, tcz-45, tcx+190, 200, tcz+45, 110 + 80*256 + 50*RM_MAGIC_65536)
100 in_try_furniture(tcx-45, 0, tcz-160, tcx+45, 200, tcz-110, 110 + 80*256 + 50*RM_MAGIC_65536)
101 in_try_furniture(tcx-45, 0, tcz+110, tcx+45, 200, tcz+160, 110 + 80*256 + 50*RM_MAGIC_65536)
102 // bookshelf against the right wall (z slides by seed)
103 let shz: i64 = 120 + in_rng(st, 0, 300)
104 in_try_furniture(RM_W-140, 0, shz, RM_W-20, 560, shz+160, 70 + 50*256 + 36*RM_MAGIC_65536)
105 // a plant in a corner
106 in_try_furniture(40, 0, 40, 150, 260, 150, 52 + 104*256 + 44*RM_MAGIC_65536)
107 return IN_NF
108}
109
110func in_n() -> i64 { return IN_N }
111func in_nf() -> i64 { return IN_NF }
112func in_box(i: i64, out: *i64) -> i64 { let B: *i64 = IN_BOX as *i64; var k: i64=0; while k<IN_STR { out[k]=B[i*IN_STR+k]; k=k+1 } return 0 }
113// count overlapping FURNITURE pairs (the constraint-validity metric; must be 0)
114func in_furniture_overlaps() -> i64 {
115 let B: *i64 = IN_BOX as *i64
116 var c: i64 = 0
117 var i: i64 = 0
118 while i < IN_N {
119 if B[i*IN_STR+7] == 1 {
120 var j: i64 = i+1
121 while j < IN_N {
122 if B[j*IN_STR+7] == 1 {
123 if in_overlap(B[i*IN_STR],B[i*IN_STR+1],B[i*IN_STR+2],B[i*IN_STR+3],B[i*IN_STR+4],B[i*IN_STR+5], B[j*IN_STR],B[j*IN_STR+1],B[j*IN_STR+2],B[j*IN_STR+3],B[j*IN_STR+4],B[j*IN_STR+5], 0) == 1 { c = c + 1 }
124 }
125 j = j + 1
126 }
127 }
128 i = i + 1
129 }
130 return c
131}
132// layout signature -- a rolling positional hash over the furniture boxes (order+position sensitive so
133// different arrangements never cancel the way a plain centroid sum would). Identical layout -> identical hash.
134func in_layout_sig() -> i64 {
135 let B: *i64 = IN_BOX as *i64
136 var s: i64 = RM_MAGIC_1469598103934665603
137 var i: i64 = 0
138 while i < IN_N {
139 if B[i*IN_STR+7] == 1 {
140 let cx: i64 = (B[i*IN_STR]+B[i*IN_STR+3])/2
141 let cz: i64 = (B[i*IN_STR+2]+B[i*IN_STR+5])/2
142 s = (s + cx) * RM_MAGIC_1099511628211
143 s = (s + cz) * RM_MAGIC_1099511628211
144 }
145 i = i + 1
146 }
147 if s < 0 { s = 0 - s }
148 return s & RM_MAGIC_2147483647
149}
150
151// ---- integer AABB interior raycaster ----
152// ray vs one box (slab method). Returns nearest t>0 (or -1), fills nrm[0]=axis, nrm[1]=sign.
153func in_ray_box(ox: i64, oy: i64, oz: i64, dx: i64, dy: i64, dz: i64, bi: i64, nrm: *i64) -> i64 {
154 let B: *i64 = IN_BOX as *i64
155 let b0x: i64=B[bi*IN_STR]; let b0y: i64=B[bi*IN_STR+1]; let b0z: i64=B[bi*IN_STR+2]
156 let b1x: i64=B[bi*IN_STR+3]; let b1y: i64=B[bi*IN_STR+4]; let b1z: i64=B[bi*IN_STR+5]
157 var tmin: i64 = 0 - RM_MAGIC_2000000000
158 var tmax: i64 = RM_MAGIC_2000000000
159 var axmin: i64 = 0
160 // x slab
161 if dx == 0 { if ox < b0x { return 0-1 } if ox > b1x { return 0-1 } }
162 else {
163 var ta: i64 = (b0x-ox)*RM_MAGIC_1024/dx
164 var tb: i64 = (b1x-ox)*RM_MAGIC_1024/dx
165 if ta > tb { let t: i64=ta; ta=tb; tb=t }
166 if ta > tmin { tmin = ta; axmin = 0 }
167 if tb < tmax { tmax = tb }
168 }
169 if dy == 0 { if oy < b0y { return 0-1 } if oy > b1y { return 0-1 } }
170 else {
171 var ta: i64 = (b0y-oy)*RM_MAGIC_1024/dy
172 var tb: i64 = (b1y-oy)*RM_MAGIC_1024/dy
173 if ta > tb { let t: i64=ta; ta=tb; tb=t }
174 if ta > tmin { tmin = ta; axmin = 1 }
175 if tb < tmax { tmax = tb }
176 }
177 if dz == 0 { if oz < b0z { return 0-1 } if oz > b1z { return 0-1 } }
178 else {
179 var ta: i64 = (b0z-oz)*RM_MAGIC_1024/dz
180 var tb: i64 = (b1z-oz)*RM_MAGIC_1024/dz
181 if ta > tb { let t: i64=ta; ta=tb; tb=t }
182 if ta > tmin { tmin = ta; axmin = 2 }
183 if tb < tmax { tmax = tb }
184 }
185 if tmin > tmax { return 0-1 }
186 if tmin <= 0 { return 0-1 }
187 nrm[0] = axmin
188 var sgn: i64 = 1
189 if axmin == 0 { if dx > 0 { sgn = 0-1 } }
190 if axmin == 1 { if dy > 0 { sgn = 0-1 } }
191 if axmin == 2 { if dz > 0 { sgn = 0-1 } }
192 nrm[1] = sgn
193 return tmin
194}
195
196// render the furnished room from a camera inside it, looking toward +z. Writes fb (W*H).
197func indoor_render(fb: *i64, W: i64, H: i64) -> i64 {
198 let B: *i64 = IN_BOX as *i64
199 let ox: i64 = RM_W/2
200 let oy: i64 = 300
201 let oz: i64 = 0 - 250 // just outside the front (open) wall, looking in
202 let focal: i64 = 520
203 let nrm: *i64 = sys_mmap(16) as *i64
204 let bn: *i64 = sys_mmap(16) as *i64
205 var py: i64 = 0
206 while py < H {
207 var px: i64 = 0
208 while px < W {
209 var dx: i64 = px - W/2
210 var dy: i64 = H/2 - py - 40
211 var dz: i64 = focal
212 let dl: i64 = in_isqrt(dx*dx+dy*dy+dz*dz)
213 dx = dx*RM_MAGIC_1024/dl; dy = dy*RM_MAGIC_1024/dl; dz = dz*RM_MAGIC_1024/dl
214 var best: i64 = RM_MAGIC_2000000000
215 var bcol: i64 = 0
216 var bax: i64 = 1
217 var bsg: i64 = 1
218 var k: i64 = 0
219 while k < IN_N {
220 let t: i64 = in_ray_box(ox, oy, oz, dx, dy, dz, k, bn)
221 if t > 0 { if t < best { best = t; bcol = B[k*IN_STR+6]; bax = bn[0]; bsg = bn[1] } }
222 k = k + 1
223 }
224 var r: i64 = 40; var g: i64 = 42; var b: i64 = 52 // bg (shouldn't show -- room is closed)
225 if best < RM_MAGIC_2000000000 {
226 // face shading: ceiling light from above; top faces bright, side faces medium, floor gets bounce
227 var lit: i64 = 62
228 if bax == 1 { if bsg > 0 { lit = 100 } else { lit = 74 } } // up-facing bright, down-facing (ceiling underside) medium
229 if bax == 0 { lit = 78 }
230 if bax == 2 { lit = 70 }
231 // distance shading
232 let fog: i64 = in_min(best/40, 30)
233 lit = lit - fog
234 r = (bcol&255)*lit/100; g = ((bcol>>8)&255)*lit/100; b = ((bcol>>16)&255)*lit/100
235 if r>255{r=255} if g>255{g=255} if b>255{b=255}
236 }
237 fb[py*W+px] = r + g*256 + b*RM_MAGIC_65536
238 px = px + 1
239 }
240 py = py + 1
241 }
242 return 0
243}
244func in_rw() -> i64 { return RM_W }