MIRPAMO/bpy/smoke_mesh.py
jing a148b4a543 MIRPAMO v0: local Mixamo — autorig + retarget via headless Blender
- autorig: landmark detection from vertex cloud (markers JSON override),
  mixamorig 22-bone skeleton fit, bone-heat weights + nearest-bone rescue
- retarget: world-space quaternion delta transfer, hip-height scale
  compensation, fuzzy/explicit bone mapping (CMU map bundled)
- smoke: procedural test humanoid + synthetic BVH -> rig -> retarget -> verify
- deploy: push to gitea, pull + smoke on m3ultra and m1ultra

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 01:26:13 +10:00

80 lines
2.6 KiB
Python

"""Generate a low-poly T-pose test humanoid (no rig) for the smoke test.
Usage: blender -b --python bpy/smoke_mesh.py -- --out out/test_human.glb
"""
import argparse
import math
import os
import sys
import bpy
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from common import clean_scene, export_glb, select_only, stage_args
def cube(name, center, size):
bpy.ops.mesh.primitive_cube_add(location=center)
o = bpy.context.active_object
o.name = name
o.scale = (size[0] / 2, size[1] / 2, size[2] / 2)
return o
def sphere(name, center, r):
bpy.ops.mesh.primitive_uv_sphere_add(
location=center, radius=r, segments=12, ring_count=8)
o = bpy.context.active_object
o.name = name
return o
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--out", required=True)
args = ap.parse_args(stage_args())
clean_scene()
H = 1.75 # meters, floor at z=0, facing -Y, T-pose along X
parts = []
# torso: groin (0.52H) to shoulders (~0.82H)
parts.append(cube("torso", (0, 0, 0.67 * H), (0.32 * H, 0.14 * H, 0.30 * H)))
# head: chin 0.87H to top 1.0H
parts.append(sphere("head", (0, 0, 0.93 * H), 0.075 * H))
parts.append(cube("neck", (0, 0, 0.845 * H), (0.06 * H, 0.06 * H, 0.06 * H)))
# arms straight out along +/-X at shoulder height 0.82H
for s in (1, -1):
parts.append(cube(f"upperarm{s}",
(s * 0.26 * H, 0, 0.82 * H),
(0.17 * H, 0.055 * H, 0.055 * H)))
parts.append(cube(f"forearm{s}",
(s * 0.40 * H, 0, 0.82 * H),
(0.14 * H, 0.045 * H, 0.045 * H)))
parts.append(cube(f"hand{s}",
(s * 0.50 * H, 0, 0.82 * H),
(0.09 * H, 0.04 * H, 0.03 * H)))
# legs down from groin, feet forward (-Y)
for s in (1, -1):
parts.append(cube(f"thigh{s}",
(s * 0.09 * H, 0, 0.40 * H),
(0.075 * H, 0.075 * H, 0.24 * H)))
parts.append(cube(f"shin{s}",
(s * 0.09 * H, 0, 0.165 * H),
(0.06 * H, 0.06 * H, 0.23 * H)))
parts.append(cube(f"foot{s}",
(s * 0.09 * H, -0.05 * H, 0.03 * H),
(0.06 * H, 0.16 * H, 0.05 * H)))
select_only(parts, active=parts[0])
bpy.ops.object.join()
body = bpy.context.active_object
body.name = "test_human"
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
export_glb(args.out, objects=[body])
print("[mirpamo] smoke mesh OK")
main()