MIRPAMO integration groundwork: strip_skin converter, --self-anim render mode
- pipeline/strip_skin.py: with-skin Mixamo FBX -> anim-only, normalises numbered bone namespaces (mixamorigN: -> mixamorig:) - render_moves.py --self-anim renders actions baked into the char file (MIRPAMO retarget output) - phrtt2-nsfw + daphne rigged via MIRPAMO autorig (clean weights); 17-clip kit retargeted but pose quality poor — retarget stage needs a bonemap/markers tuning pass before these ship as fighters Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
cdafb83a33
commit
5f2515d89f
@ -26,7 +26,7 @@ def parse_args():
|
||||
argv = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--char", required=True)
|
||||
ap.add_argument("--clips", required=True, help="dir or comma-separated fbx list")
|
||||
ap.add_argument("--clips", default="", help="dir or comma-separated fbx list")
|
||||
ap.add_argument("--out", required=True)
|
||||
ap.add_argument("--size", type=int, default=512)
|
||||
ap.add_argument("--rotz", type=float, default=90.0,
|
||||
@ -42,6 +42,9 @@ def parse_args():
|
||||
help="comma list of mesh-name substrings to tear (punch alpha "
|
||||
"holes in their textures); output dirs get an @torn suffix")
|
||||
ap.add_argument("--torn-seed", type=int, default=7)
|
||||
ap.add_argument("--self-anim", action="store_true",
|
||||
help="ignore --clips; render each action already baked into "
|
||||
"the character file (MIRPAMO retarget output)")
|
||||
ap.add_argument("--strip", default="",
|
||||
help="comma list of mesh-name substrings to REMOVE (clothes "
|
||||
"knocked off); output dirs get an @stripped suffix")
|
||||
@ -301,17 +304,25 @@ def main():
|
||||
attach_gear(arm, args.attach)
|
||||
variant_suffix = "@geared"
|
||||
|
||||
clips_arg = str(Path(args.clips).expanduser())
|
||||
p = Path(clips_arg)
|
||||
if p.is_dir():
|
||||
clip_paths = sorted(p.glob("*.fbx"))
|
||||
# (clip_path, action): external clip files, or the character's own
|
||||
# baked actions when --self-anim (MIRPAMO retarget output)
|
||||
jobs = []
|
||||
if args.self_anim:
|
||||
for act in bpy.data.actions:
|
||||
jobs.append((Path(act.name + ".glb"), act))
|
||||
else:
|
||||
clip_paths = [Path(c).expanduser() for c in args.clips.split(",")]
|
||||
clips_arg = str(Path(args.clips).expanduser())
|
||||
p = Path(clips_arg)
|
||||
if p.is_dir():
|
||||
clip_paths = sorted(p.glob("*.fbx"))
|
||||
else:
|
||||
clip_paths = [Path(c).expanduser() for c in args.clips.split(",")]
|
||||
jobs = [(c, None) for c in clip_paths]
|
||||
|
||||
out_root = Path(args.out).expanduser()
|
||||
sc = bpy.context.scene
|
||||
for clip in clip_paths:
|
||||
action = import_clip_action(str(clip), arm)
|
||||
for clip, baked in jobs:
|
||||
action = baked if baked is not None else import_clip_action(str(clip), arm)
|
||||
assign_action(arm, action)
|
||||
f0, f1 = (int(action.frame_range[0]), int(action.frame_range[1]))
|
||||
if args.max_frames > 0:
|
||||
|
||||
45
pipeline/strip_skin.py
Normal file
45
pipeline/strip_skin.py
Normal file
@ -0,0 +1,45 @@
|
||||
# Blender headless: convert with-skin Mixamo FBX clips to anim-only FBX
|
||||
# (deletes meshes, keeps armature+action). MIRPAMO's retarget mapper needs
|
||||
# anim-only sources.
|
||||
#
|
||||
# Usage: Blender -b --python pipeline/strip_skin.py -- --clips "a.fbx,b.fbx" --out dir
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import bpy
|
||||
|
||||
|
||||
def parse_args():
|
||||
argv = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--clips", required=True)
|
||||
ap.add_argument("--out", required=True)
|
||||
return ap.parse_args(argv)
|
||||
|
||||
|
||||
args = parse_args()
|
||||
out = Path(args.out).expanduser()
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
for clip in args.clips.split(","):
|
||||
clip = Path(clip).expanduser()
|
||||
dest = out / clip.name
|
||||
if dest.exists():
|
||||
print("SKIP", clip.name)
|
||||
continue
|
||||
bpy.ops.wm.read_factory_settings(use_empty=True)
|
||||
bpy.ops.import_scene.fbx(filepath=str(clip), use_anim=True)
|
||||
for o in list(bpy.data.objects):
|
||||
if o.type == "MESH":
|
||||
bpy.data.objects.remove(o, do_unlink=True)
|
||||
# normalise numbered Mixamo namespaces (mixamorig7: -> mixamorig:) so
|
||||
# downstream mappers (MIRPAMO retarget) match by exact name
|
||||
import re
|
||||
for o in bpy.data.objects:
|
||||
if o.type == "ARMATURE":
|
||||
for b in o.data.bones:
|
||||
b.name = re.sub(r"^mixamorig\d+:", "mixamorig:", b.name)
|
||||
bpy.ops.export_scene.fbx(filepath=str(dest), use_selection=False,
|
||||
add_leaf_bones=False, bake_anim=True)
|
||||
print("STRIPPED", clip.name)
|
||||
print("DONE")
|
||||
Loading…
Reference in New Issue
Block a user