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