"""Mako: a Tender ("sub tub") after the user's reference sheet (reference/user_reference.webp), 2026-10-20: "can you create me a 3d tender model that can be usable as an real asset in the descent vessel. try to create similiar from that referance picture. red line indicates where the the arm holder clips place so arms can hold the sub tub." "Mako" is a working name after the orange shark's dorsal fin; the user has not named it. All measurements, the scale and the choices where the sheet's views disagree are in mk_measure.py. Axes as the Kazah, the Manta and the Spearfish: 1 unit = 1 m, nose to -Y, port +X, Z up, origin 9 cm behind the docking clamp's axis. No booleans. The hull is one quad grid whose columns are pinned to the measured outlines, so the canopy, the side windows and the hatch are regions of whole grid faces with their frames and sleeves in the same topology (mk_hull.py); fins, pods and fittings are lofted or revolved quads with quad caps (mk_topo.py), pruned where they sink into the hull. Runs headless (run_build_headless.py) or inside an open Blender; it rebuilds only its own collections.""" import bpy, bmesh, math, os, sys, json, time from mathutils import Vector, Matrix, Euler HERE = r"D:\HADAL - The Descent\models\tender-mako\build" exec(open(os.path.join(HERE, "lib2.py")).read()) exec(open(os.path.join(HERE, "tender_lib.py")).read()) exec(open(os.path.join(HERE, "mk_measure.py")).read()) OUT = os.path.dirname(HERE) t_start = time.time() REPORT = {} PFX = "MAKO | " for cname in (PFX + "Tender (exported)", PFX + "Collision (UCX)", PFX + "Sockets"): c = bpy.data.collections.get(cname) if c: for o in list(c.all_objects): bpy.data.objects.remove(o) bpy.data.collections.remove(c) for me in list(bpy.data.meshes): if me.users == 0: bpy.data.meshes.remove(me) # ================================================================== materials (look only; the surfaces pass dresses them) PAINT = MAT(PFX + "Hull paint", (0.86, 0.30, 0.025), rough=0.30, coat=1.0) # the sheet's orange JAW = MAT(PFX + "Jaw paint", (0.62, 0.14, 0.028), rough=0.32, coat=1.0) # the jaw: the sheet draws it a redder orange DARK = MAT(PFX + "Lower hull", (0.040, 0.046, 0.054), rough=0.45) # the dark slate under the shell, pods GRAPH = MAT(PFX + "Graphite", (0.024, 0.026, 0.030), rough=0.42) FIN = MAT(PFX + "Fin grey", (0.30, 0.37, 0.43), rough=0.36) # the sheet's light blue-grey fins (v04: its (148,163,176)) FRAMEL = MAT(PFX + "Frame light", (0.55, 0.60, 0.64), rough=0.35) # v04: the thin light frames on the glass PODG = MAT(PFX + "Side body", (0.19, 0.23, 0.28), rough=0.40) # v04: the side bodies (the sheet's cheek panel grey) RECESS = MAT(PFX + "Recess grey", (0.12, 0.15, 0.19), rough=0.45) # v04 round 2: the lit cavity behind the collar GLASSUP = MAT(PFX + "Glass upper", (0.70, 0.92, 1.0), rough=0.02) # v04 round 2: the canopy's pale upper glass BAYGLASS = MAT(PFX + "Bay glass", (0.06, 0.10, 0.16), rough=0.04) # v04 round 2: the rear bay's dark tinted glass SENSOR = MAT(PFX + "Black gloss", (0.006, 0.007, 0.009), rough=0.08, coat=1.0) STEEL = MAT(PFX + "Steel", (0.60, 0.61, 0.63), metal=1.0, rough=0.28) RUBBER = MAT(PFX + "Rubber", (0.017, 0.017, 0.018), rough=0.80) YELLOW = MAT(PFX + "Yellow marking", (0.85, 0.55, 0.04), rough=0.40, coat=0.5) GLASS = MAT(PFX + "Glass", (0.62, 0.84, 0.96), rough=0.03) LENS = MAT(PFX + "Lamp lens", (0.95, 0.97, 1.0), rough=0.03) LAMP = MAT(PFX + "Lamp light", (0.9, 0.9, 0.9), rough=0.3, emit=(1.0, 0.90, 0.75), emit_str=25.0) CAB = MAT(PFX + "Cabin panel", (0.30, 0.33, 0.37), rough=0.6) FLOOR = MAT(PFX + "Cabin floor", (0.05, 0.05, 0.055), rough=0.65) SEAT = MAT(PFX + "Seat", (0.20, 0.24, 0.30), rough=0.55) SCREEN = MAT(PFX + "Screen", (0.01, 0.02, 0.025), rough=0.15, emit=(0.35, 0.75, 1.0), emit_str=3.0) CABGLOW = MAT(PFX + "Cabin light", (0.05, 0.06, 0.07), rough=0.4, emit=(0.70, 0.85, 1.0), emit_str=12.0) for m in (GLASS, LENS, GLASSUP, BAYGLASS): b = m.node_tree.nodes["Principled BSDF"] b.inputs["Transmission Weight"].default_value = 1.0 b.inputs["IOR"].default_value = 1.49 C_ROOT = get_coll(PFX + "Tender (exported)") C_COL = get_coll(PFX + "Collision (UCX)") C_SOCK = get_coll(PFX + "Sockets") root = bpy.data.objects.new("Mako_Root", None) C_ROOT.objects.link(root) root.empty_display_type = 'ARROWS' for f in ("mk_shape.py", "mk_hull.py", "mk_fittings.py", "mk_clamp.py", "mk_cabin.py", "mk_tools.py", "mk_finish.py"): exec(open(os.path.join(HERE, f)).read())