"""Grouper: its outside in its own (Tender) frame for the checks against the ship and the docking arm (the cabin left out), after the Tiger's tg_dump.py. Every outside mesh: hull (collar, fittings), glass, hatch shut, doors shut, rotor, antenna. checks/grouper_tris.npz all triangles (v, t, names), the antenna FOLDED (70 deg): the docked pose checks/grouper_points.npy every vertex and face centre, antenna folded checks/grouper_tris_raised.npz the same with the antenna RAISED as drawn (0 deg), for the record checks/grouper_points_raised.npy blender -b Tender_Grouper.blend --python build/gr_dump_tris.py (the file is not saved; the handles are put back)""" import bpy import os import numpy as np HERE = os.path.dirname(os.path.abspath(__file__)) os.makedirs(os.path.join(HERE, "checks"), exist_ok=True) root = bpy.data.objects["Grouper_Root"] sc = bpy.context.scene NAMES = ("SM_Grouper_Hull", "SM_Grouper_Glass", "SM_Grouper_Hatch", "SM_Grouper_Door_L", "SM_Grouper_Door_R", "SM_Grouper_Rotor", "SM_Grouper_Antenna") FOLD_DOCKED = 70.0 def refresh(): for ob in bpy.data.objects: if ob.animation_data: for fc in ob.animation_data.drivers: fc.driver.expression = fc.driver.expression fc.driver.is_valid = True ob.update_tag() root.update_tag() sc.frame_set(sc.frame_current + 1) bpy.context.view_layer.update() def collect(): dg = bpy.context.evaluated_depsgraph_get() V, T, N, P, off = [], [], [], [], 0 for n in NAMES: o = bpy.data.objects[n] ev = o.evaluated_get(dg) me = ev.to_mesh() me.calc_loop_triangles() M = np.array(ev.matrix_world) co = np.empty(len(me.vertices) * 3) me.vertices.foreach_get("co", co) co = co.reshape(-1, 3) @ M[:3, :3].T + M[:3, 3] tr = np.empty(len(me.loop_triangles) * 3, np.int64) me.loop_triangles.foreach_get("vertices", tr) tr = tr.reshape(-1, 3) ev.to_mesh_clear() V.append(co) T.append(tr + off) N += [n] * len(tr) P.append(np.concatenate([co, co[tr].mean(1)])) off += len(co) return np.concatenate(V), np.concatenate(T), np.array(N), np.concatenate(P) keep = {k: root.get(k, 0.0) for k in ("antenna_fold_deg", "hatch_open_deg", "door_l_deg", "door_r_deg", "rotor_turns")} for k in ("hatch_open_deg", "door_l_deg", "door_r_deg", "rotor_turns"): root[k] = 0.0 root["antenna_fold_deg"] = 0.0 refresh() v, t, n, p = collect() np.save(os.path.join(HERE, "checks", "grouper_points_raised.npy"), p) np.savez(os.path.join(HERE, "checks", "grouper_tris_raised.npz"), v=v, t=t, names=n) zr = float(v[:, 2].max()) root["antenna_fold_deg"] = FOLD_DOCKED refresh() v, t, n, p = collect() np.save(os.path.join(HERE, "checks", "grouper_points.npy"), p) np.savez(os.path.join(HERE, "checks", "grouper_tris.npz"), v=v, t=t, names=n) for k, val in keep.items(): root[k] = val refresh() print("DUMP", len(v), len(t), "y range %.3f .. %.3f" % (p[:, 1].min(), p[:, 1].max()), "x range %.3f .. %.3f" % (p[:, 0].min(), p[:, 0].max()), "z range %.3f .. %.3f" % (p[:, 2].min(), p[:, 2].max()), "raised top z %.3f" % zr)