Skip to content

Commit 28fe1ea

Browse files
committed
2 parents f8bd3ed + ef01c4e commit 28fe1ea

File tree

2 files changed

+45
-16
lines changed

2 files changed

+45
-16
lines changed

tutorials/FixingMixamoRootMotionWithPython.md

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Once our mixamo assets are imported we need to do the following steps:
1616

1717
* Modify the SkeletalMesh bone influences as indexes will be shifted after the adding of a new bone
1818

19-
* Split the 'Hips' related animation curve in two other curves, one containing the root motion (translations, relative to local axis origin) that will be mapped to the 'root' track, and the other mapped to the 'Hips' track that will contain only rotations.
19+
* Split the 'Hips' related animation curve in two other curves, one containing the root motion (translations, relative to local axis origin) that will be mapped to the 'root' track, and the other mapped to the 'Hips' track that will contain only rotations. The 'root' track must be the first one.
2020

2121
To avoid damages, we will generate a copy of each asset, so you will be able to always use the original ones.
2222

@@ -326,31 +326,50 @@ class RootMotionFixer:
326326
new_anim.NumFrames = animation.NumFrames
327327
new_anim.SequenceLength = animation.SequenceLength
328328

329-
# iterate each track to copy/fix
329+
# first step is generatin the 'root' track
330+
# we need to do it before anything else, as the 'root' track must be the 0 one
330331
for index, name in enumerate(animation.AnimationTrackNames):
331-
data = animation.get_raw_animation_track(index)
332332
if name == bone:
333+
data = animation.get_raw_animation_track(index)
333334
# extract root motion
334-
root_motion = [position - data.pos_keys[0] for position in data.pos_keys]
335-
336-
# remove root motion from original track (but leave a single key for position, otherwise the track will break)
337-
data.pos_keys = [data.pos_keys[0]]
338-
new_anim.add_new_raw_track(name, data)
335+
root_motion = [(position - data.pos_keys[0]) for position in data.pos_keys]
339336

340337
# create a new track (the root motion one)
341338
root_data = FRawAnimSequenceTrack()
342339
root_data.pos_keys = root_motion
343340
# ensure empty rotations !
344341
root_data.rot_keys = [FQuat()]
345342

346-
# add the track
343+
# add the track
347344
new_anim.add_new_raw_track('root', root_data)
345+
break
346+
else:
347+
raise DialogException('Unable to find bone {0}'.format(bone))
348+
349+
# now append the original tracks, but removes the position keys
350+
# from the original root bone
351+
for index, name in enumerate(animation.AnimationTrackNames):
352+
data = animation.get_raw_animation_track(index)
353+
if name == bone:
354+
# remove root motion from original track
355+
data.pos_keys = [data.pos_keys[0]]
356+
new_anim.add_new_raw_track(name, data)
348357
else:
349358
new_anim.add_new_raw_track(name, data)
350359

351360
new_anim.save_package()
352361
```
353362

363+
The two 'for loops' is where the fix happens. Take into account that some animation could require additional manipulation,
364+
as an example you may want to remove z and x transformations for a running loop:
365+
366+
```python
367+
# extract root motion
368+
root_motion = [((position - data.pos_keys[0]) * FVector(0, 1, 0)) for position in data.pos_keys]
369+
```
370+
371+
And always remember that modifying the z axis in root motion, requires your Character to be in 'Flying' movement mode.
372+
354373
Now add support for AnimSequence in your final loop:
355374

356375
```python

tutorials/FixingMixamoRootMotionWithPython_Assets/mixamo.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -122,24 +122,34 @@ def split_hips(self, animation, bone='Hips'):
122122
new_anim.NumFrames = animation.NumFrames
123123
new_anim.SequenceLength = animation.SequenceLength
124124

125+
# first step is generatin the 'root' track
126+
# we need to do it before anything else, as the 'root' track must be the 0 one
125127
for index, name in enumerate(animation.AnimationTrackNames):
126-
data = animation.get_raw_animation_track(index)
127128
if name == bone:
129+
data = animation.get_raw_animation_track(index)
128130
# extract root motion
129-
root_motion = [position - data.pos_keys[0] for position in data.pos_keys]
130-
131-
# remove root motion from original track
132-
data.pos_keys = [data.pos_keys[0]]
133-
new_anim.add_new_raw_track(name, data)
131+
root_motion = [(position - data.pos_keys[0]) for position in data.pos_keys]
134132

135133
# create a new track (the root motion one)
136134
root_data = FRawAnimSequenceTrack()
137135
root_data.pos_keys = root_motion
138136
# ensure empty rotations !
139137
root_data.rot_keys = [FQuat()]
140138

141-
# add the track
139+
# add the track
142140
new_anim.add_new_raw_track('root', root_data)
141+
break
142+
else:
143+
raise DialogException('Unable to find bone {0}'.format(bone))
144+
145+
# now append the original tracks, but removes the position keys
146+
# from the original root bone
147+
for index, name in enumerate(animation.AnimationTrackNames):
148+
data = animation.get_raw_animation_track(index)
149+
if name == bone:
150+
# remove root motion from original track
151+
data.pos_keys = [data.pos_keys[0]]
152+
new_anim.add_new_raw_track(name, data)
143153
else:
144154
new_anim.add_new_raw_track(name, data)
145155

0 commit comments

Comments
 (0)