exec(open(r"D:\HADAL - The Descent\models\dnr-cnc\build\lib2.py").read()) clean_scene() root = bpy.data.objects["DNR_CNC_Root"] for c in list(bpy.data.collections): if c.name.startswith("CNC_"): bpy.data.collections.remove(c) CS = get_coll("DNR_CNC") C_STATIC = get_coll("CNC_Static", CS) C_MOVE = get_coll("CNC_Moving", CS) C_COL = get_coll("CNC_Collision", CS) gm = MAT("Body_Gunmetal"); bd = MAT("Body_Dark"); ti = MAT("Titanium"); td = MAT("Titanium_Dark") cy = MAT("Glow_Cyan"); rd = MAT("Glow_Red"); iw = MAT("Interior_Wall"); gl = MAT("Glass") cyd = MAT("Glow_Cyan_Dim", (0.1, 0.8, 1.0), emit=(0.15, 0.85, 1.0), emit_str=2.5) bz = MAT("Bezel_Black") # ============================================================ HOUSING (loop-cut box, quad reveals, no booleans) WIN_X = (-0.21, 0.79); WIN_Z = (1.05, 2.15) # front window (through the 0.12 front wall) SW_Y = (0.40, 0.76); SW_Z = (1.10, 2.00) # left side window (through the 0.20 side wall) CAV = dict(x=(-1.55, 1.55), y=(-1.28, 1.25), z=(0.62, 2.18)) def cuts(bm): for x in WIN_X: loopcut(bm, 'x', x) for z in WIN_Z + SW_Z: loopcut(bm, 'z', z) for y in SW_Y: loopcut(bm, 'y', y) hb = cube_bm((3.5, 2.8, 2.0), (0, 0, 1.30), bevel=0.05) cuts(hb) f1 = faces_where(hb, (0, -1, 0), 1, -1.40, WIN_X, WIN_Z) punch_and_extrude(hb, f1, (0, 0.12, 0)) f2 = faces_where(hb, (-1, 0, 0), 0, -1.75, SW_Y, SW_Z) punch_and_extrude(hb, f2, (0.20, 0, 0)) bmesh.ops.recalc_face_normals(hb, faces=hb.faces[:]) n_f1, n_f2 = len(f1), len(f2) body = MB("SM_DNR_Body", [gm, bd, ti, td]) body.add_bm(hb, gm) # interior room: same cut lines so the hole loops line up with the reveal tunnels rb = cube_bm((3.10, 2.53, 1.56), (0, -0.015, 1.40)) cuts(rb) g1 = faces_where(rb, (0, -1, 0), 1, CAV['y'][0], WIN_X, WIN_Z) bmesh.ops.delete(rb, geom=g1, context='FACES_ONLY') g2 = faces_where(rb, (-1, 0, 0), 0, CAV['x'][0], SW_Y, SW_Z) bmesh.ops.delete(rb, geom=g2, context='FACES_ONLY') bmesh.ops.reverse_faces(rb, faces=rb.faces[:]) room = MB("SM_DNR_Interior", [iw, MAT("Cast_Grey"), td, MAT("Glow_White")]) room.add_bm(rb, iw) # ============================================================ plinth + feet body.box((3.44, 2.74, 0.20), (0, 0, 0.20), bd, bevel=0.03, drop=('-z',)) FEET = [(-1.45, -1.05), (1.45, -1.05), (-1.45, 0.0), (1.45, 0.0), (-1.45, 1.05), (1.45, 1.05)] glow = MB("SM_DNR_GlowGlass", [cy, rd, MAT("Glow_Amber"), cyd]) for (x, y) in FEET: body.cyl(0.16, 0.19, 0.105, (x, y, 0.0525), td, segs=24, caps='bottom') glow.torus(0.184, 0.011, (x, y, 0.030), cy, segs=24, rsegs=4) # ============================================================ roof relief, side plates (hidden faces dropped) zr = 2.30 body.box((0.95, 1.55, 0.04), (-0.95, -0.025, zr + 0.02), bd, bevel=0.012, drop=('-z',)) body.box((0.95, 1.55, 0.04), (1.05, -0.025, zr + 0.02), bd, bevel=0.012, drop=('-z',)) body.box((2.90, 0.42, 0.04), (0.05, 1.00, zr + 0.02), bd, bevel=0.012, drop=('-z',)) # left side plates (the narrow window sits between them) body.box((0.016, 0.95, 1.70), (-1.758, -0.775, 1.30), bd, bevel=0.008, drop=('+x',)) body.box((0.016, 0.40, 1.70), (-1.758, 1.10, 1.30), bd, bevel=0.008, drop=('+x',)) # right side plate body.box((0.016, 2.30, 1.62), (1.758, 0.0, 1.31), bd, bevel=0.008, drop=('-x',)) # back plate body.box((3.00, 0.016, 1.62), (0, 1.408, 1.31), bd, bevel=0.008, drop=('-y',)) # ============================================================ hex vent panels (raised cells over a glowing back plate) def hexvent(cx, cy_, cz, w, h, r, face, glow_mb, body_mb): """face: 'front' (faces -Y) or 'left' (faces -X). cells are flat-topped hexes.""" gap = 0.008 dx = 1.5 * r + gap dz = math.sqrt(3) * r + gap cols = int((w - 2 * r) / dx) + 1 rows = int(h / dz) rot = (math.radians(90), 0, 0) if face == 'front' else (math.radians(90), 0, math.radians(90)) def P(u, v): return (cx + u, cy_, cz + v) if face == 'front' else (cx, cy_ + u, cz + v) # back plate (emissive), open towards the wall sz = (w, 0.006, h) if face == 'front' else (0.006, w, h) sgn = -1 ctr = P(0, 0) ctr = (ctr[0], ctr[1] + (sgn * 0.003 if face == 'front' else 0), ctr[2]) if face == 'left': ctr = (cx - 0.003, cy_, cz) glow_mb.box(sz, ctr, cyd, drop=('+x',)) else: glow_mb.box(sz, ctr, cyd, drop=('+y',)) ox = -(cols - 1) * dx / 2 for i in range(cols): for j in range(rows): u = ox + i * dx v = (j - (rows - 1) / 2) * dz + (dz / 2 if i % 2 else 0) - dz / 4 if abs(v) + r > h / 2: continue p = P(u, v) if face == 'front': body_mb.cyl(r, r * 0.86, 0.016, (p[0], p[1] - 0.006 - 0.008, p[2]), bd, rot=rot, segs=6, caps='top') else: body_mb.cyl(r, r * 0.86, 0.016, (p[0] - 0.006 - 0.008, p[1], p[2]), bd, rot=rot, segs=6, caps='top') hexvent(1.40, -1.40, 0.545, 0.56, 0.36, 0.040, 'front', glow, body) hexvent(-1.75, 0.05, 0.58, 0.60, 0.40, 0.040, 'left', glow, body) # ============================================================ glow strips on the skin (drop the wall-side face) FY = -1.40 def strip(sz, ctr, mat, drop): glow.box(sz, ctr, mat, drop=drop) strip((1.18, 0.008, 0.014), (-1.09, FY - 0.004, 0.80), cy, ('+y',)) strip((0.62, 0.008, 0.014), (1.37, FY - 0.004, 0.80), cy, ('+y',)) strip((0.014, 0.008, 1.26), (-1.66, FY - 0.004, 1.58), cy, ('+y',)) strip((0.014, 0.008, 1.26), (1.66, FY - 0.004, 1.58), cy, ('+y',)) strip((3.30, 0.010, 0.012), (0, -1.372, 0.306), cy, ('+y',)) strip((0.010, 2.60, 0.012), (-1.723, 0, 0.306), cy, ('+x',)) strip((0.010, 2.60, 0.012), (1.723, 0, 0.306), cy, ('-x',)) strip((3.1, 0.012, 0.006), (0, -1.25, zr + 0.003), cy, ('-z',)) strip((3.1, 0.012, 0.006), (0, 1.25, zr + 0.003), cy, ('-z',)) strip((0.012, 2.5, 0.006), (-1.55, 0, zr + 0.003), cy, ('-z',)) strip((0.012, 2.5, 0.006), (1.55, 0, zr + 0.003), cy, ('-z',)) # red edge caps, back corners (as the red band in the 3/4 photo) strip((0.014, 0.04, 1.72), (-1.757, 1.335, 1.31), rd, ('+x',)) strip((0.014, 0.04, 1.72), (1.757, 1.335, 1.31), rd, ('-x',)) # side window frame + glass (static) # side window glass: one quad recessed in the reveal (normal -X) glow.quad((-1.72, 0.76, 1.10), (-1.72, 0.40, 1.10), (-1.72, 0.40, 2.00), (-1.72, 0.76, 2.00), gl) o_body = body.build(C_STATIC, parent=root) o_room = room.build(C_STATIC, parent=root) o_glow = glow.build(C_STATIC, parent=root) result = {"front_hole_faces": n_f1, "side_hole_faces": n_f2, "audit": [audit(o) for o in (o_body, o_room, o_glow)]}