# Spearfish: objects, rig, sockets, collision, report (exec'd by build_spearfish.py) def finish(mb, parent=root, coll=C_ROOT, origin=None): return mb.build(coll, parent=parent, recalc=False, origin=origin) o_hull = finish(hull) o_glass = finish(glass) o_cab = finish(cab) o_frames = finish(frames) o_att = finish(att) o_clip = finish(clip) o_hatch = finish(hatch, origin=HATCH_HINGE) o_hatch.matrix_parent_inverse.identity() o_hatch.location = HATCH_HINGE # rig: the two whip masts fold aft for stowing (0 raised as drawn, 1 folded), one axis-angle each root["masts_folded"] = 0.0 root.id_properties_ui("masts_folded").update(min=0.0, max=1.0, description="whip masts: 0 raised (the blueprint), 1 folded aft along the stern for the carousel") for side, (mb_m, base, d_r, ln) in MASTS.items(): om = finish(mb_m, origin=base) om.matrix_parent_inverse.identity() om.location = base om.rotation_mode = 'AXIS_ANGLE' axis, ang, _ = MAST_FOLD[side] om.rotation_axis_angle = (0.0, axis.x, axis.y, axis.z) fcm = om.driver_add("rotation_axis_angle", 0) drm = fcm.driver; drm.type = 'SCRIPTED' vm = drm.variables.new(); vm.name = "p"; vm.type = 'SINGLE_PROP' vm.targets[0].id = root; vm.targets[0].data_path = '["masts_folded"]' drm.expression = "p*%.6f" % ang # rig: the hatch swings up about its aft edge (the X axis through the hinge); simple-expression driver root["hatch_open_deg"] = 0.0 root.id_properties_ui("hatch_open_deg").update(min=0.0, max=100.0, description="top hatch: 0 shut .. 100 deg open, hinged on its aft edge") fc = o_hatch.driver_add("rotation_euler", 0) dr = fc.driver; dr.type = 'SCRIPTED' v = dr.variables.new(); v.name = "p"; v.type = 'SINGLE_PROP' v.targets[0].id = root; v.targets[0].data_path = '["hatch_open_deg"]' dr.expression = "-p*0.0174533" # sockets for the game for nm, p in (("SOCKET_Clamp", CL_C + Vector((0, 0, 1.94))), ("SOCKET_Lamp_L", TIP_POD[1] * 0 + Vector((POD_L * S, Yi(POD_X0) - 0.01, Zi(BIGFIN_Y) - math.tan(math.radians(BIGFIN_ANHEDRAL)) * (POD_L - BIG_LS[0]) * S))), ("SOCKET_Lamp_R", Vector((-POD_L * S, Yi(POD_X0) - 0.01, Zi(BIGFIN_Y) - math.tan(math.radians(BIGFIN_ANHEDRAL)) * (POD_L - BIG_LS[0]) * S))), ("SOCKET_Pilot_Eye", Vector((0, SY - 0.05, ZF + 0.86))), ("SOCKET_Thrust", Vector((0, Y_TAIL + 0.05, ZMf(Y_TAIL)))), ("SOCKET_Hatch", HATCH_HINGE + Vector((0, -0.30, 0.05)))): e = bpy.data.objects.new(nm, None); C_SOCK.objects.link(e); e.parent = root; e.location = p e.empty_display_size = 0.15 # collision: convex hulls in slices def ucx_from(obj, name, sel): bm2 = bmesh.new() pts = [obj.matrix_world @ v.co for v in obj.data.vertices if sel(obj.matrix_world @ v.co)] for p in pts: bm2.verts.new(p) bmesh.ops.convex_hull(bm2, input=bm2.verts[:]) me = bpy.data.meshes.new(name); bm2.to_mesh(me); bm2.free() o = bpy.data.objects.new(name, me); C_COL.objects.link(o); o.display_type = 'WIRE'; o.hide_render = True return o cuts = [Y_NOSE - 0.1, -3.6, -2.4, -1.2, 0.0, 1.2, 2.4, 3.6, Y_TAIL + 0.3] k = 0 for j in range(len(cuts) - 1): k += 1 ucx_from(o_hull, "UCX_SM_Spearfish_Hull_%02d" % k, lambda p, a=cuts[j], b=cuts[j + 1]: a - 0.01 <= p.y <= b + 0.01) for nm, sel in (("finL", lambda p: p.x > 1.0 and p.z < 0.0 and p.y > -0.2), ("finR", lambda p: p.x < -1.0 and p.z < 0.0 and p.y > -0.2), ("canL", lambda p: p.x > 0.9 and p.z > 0.15 and p.y < 0.0), ("canR", lambda p: p.x < -0.9 and p.z > 0.15 and p.y < 0.0)): k += 1 ucx_from(o_att, "UCX_SM_Spearfish_Hull_%02d" % k, sel) k += 1 ucx_from(o_clip, "UCX_SM_Spearfish_Hull_%02d" % k, lambda p: p.z > 1.05) # one static exterior mesh: skin, fittings, clips, window frames (glass, cabin and hatch stay their own) with bpy.context.temp_override(active_object=o_hull, selected_editable_objects=[o_hull, o_att, o_clip, o_frames]): bpy.ops.object.join() o_hull.name = "SM_Spearfish_Hull" allp = [] for o in C_ROOT.all_objects: if o.type == 'MESH': allp += [o.matrix_world @ v.co for v in o.data.vertices] mn = Vector((min(p.x for p in allp), min(p.y for p in allp), min(p.z for p in allp))) mx = Vector((max(p.x for p in allp), max(p.y for p in allp), max(p.z for p in allp))) REPORT["bounds_min"] = [round(c, 3) for c in mn]; REPORT["bounds_max"] = [round(c, 3) for c in mx] REPORT["dimensions"] = [round(c, 3) for c in (mx - mn)] REPORT["audit"] = [audit(o) for o in C_ROOT.all_objects if o.type == 'MESH'] REPORT["build_seconds"] = round(time.time() - t_start, 2) json.dump(REPORT, open(os.path.join(HERE, "build_report.json"), "w"), indent=1) # drivers created in this run can stay flagged invalid until re-set (dump_spearfish.refresh_drivers does the same) for ob in C_ROOT.all_objects: if ob.animation_data: for fc in ob.animation_data.drivers: fc.driver.expression = fc.driver.expression fc.driver.is_valid = True