This commit is contained in:
Nicholas Butzke
2026-08-09 01:31:44 -04:00
parent 922983429e
commit 9358746582
43 changed files with 4324 additions and 481 deletions
+19 -7
View File
@@ -9,7 +9,12 @@ full one-time character build.
Usage:
blender --background --python tools/inject_wallrun.py -- \
<character.glb> <_wallrun.glb> <output.glb>
<character.glb> <animation_library.glb> <output.glb> [ClipName ...]
With no clip names it keeps the original wall-run behavior. Supplying names
also makes this the small post-export repair used for libraries that Blender's
first, very large NLA export occasionally omits (notably RunBackward on some
Auto-Rig Pro characters).
"""
import math
import os
@@ -25,13 +30,20 @@ from retarget_pose import authored_world_rotation, build_segment_pairs
argv = sys.argv
argv = argv[argv.index("--") + 1:] if "--" in argv else []
if len(argv) != 3:
if len(argv) < 3:
print(__doc__)
sys.exit(1)
CHARACTER, LIBRARY, OUTPUT = argv
CHARACTER, LIBRARY, OUTPUT = argv[:3]
UP = Vector((0.0, 0.0, 1.0))
CLIPS = ("WallRunLeft", "WallRunRight")
RAW_CLIPS = tuple(argv[3:]) or ("WallRunLeft", "WallRunRight")
# ``Source=Destination`` lets the compact repair give a source action its
# canonical runtime name (used by strafe_back-cycle -> RunBackward).
CLIP_SPECS = tuple(
tuple(raw.split("=", 1)) if "=" in raw else (raw, raw)
for raw in RAW_CLIPS
)
CLIPS = tuple(destination for _source, destination in CLIP_SPECS)
def find_armature(objects):
@@ -270,10 +282,10 @@ def main():
scale = target_h / src_h if src_h > 1e-5 else 1.0
by_name = {action.name.split(".")[0]: action for action in new_actions}
for clip in CLIPS:
source = by_name.get(clip)
for source_name, clip in CLIP_SPECS:
source = by_name.get(source_name)
if source is None:
raise RuntimeError(f"{LIBRARY}: missing {clip}")
raise RuntimeError(f"{LIBRARY}: missing {source_name}")
baked = retarget_action(
target_arm,
target_roles,