Page MenuHome

FBX partial animation fixes
Needs ReviewPublic

Authored by Evan Todd (et1337) on Feb 11 2016, 10:26 PM.

Details

Summary
  1. When sampling animations, the armature is not reset when switching from one action to the next. If an action leaves some channels unkeyed, you'll see a pose from the previous action on those channels. This patch resets the armature between actions.
  2. The exported bind pose is whatever pose the armature happens to be in at export time, rather than the T-pose specified in edit mode. Animations that only key certain channels often rely on the bind pose being accurate. This patch resets armatures to the bind pose before exporting.
  3. For single-frame animations (poses), the exporter simplifies all keyframes out of existence, because there is never any change. This patch keeps the first keyframe if it is different from the bind pose.
  4. The exporter simplifies keyframes on a per-component basis, e.g. X, Y, Z positions are simplified separately. Some pipelines (Assimp for example) can't handle individual components. This patch keys all components together if any one of them is changed.

Diff Detail

Event Timeline

Evan Todd (et1337) retitled this revision from to FBX partial animation fixes.
Evan Todd (et1337) updated this object.
Evan Todd (et1337) set the repository for this revision to rBA Blender Add-ons.
Campbell Barton (campbellbarton) requested changes to this revision.Feb 12 2016, 7:33 AM

This change clears users actions after exporting, other minor issues noted below.

io_scene_fbx/export_fbx_bin.py
2071

can just use scene.update() here.

2084

This removes ob.animation_data.action = org_act, the action isn't being restored after this patch is applied (meaning users will have their actions cleared after export...).

Exporting shouldn't be non-destructive from a user perspective.

io_scene_fbx/fbx_utils.py
797

Checking start frame is zero seems a bit fragile if the intention is to check the first frame. (depends on start_zero argument to fbx_animations_do(...))

Since the first frame may not be zero. could check idx instead?

This revision now requires changes to proceed.Feb 12 2016, 7:33 AM

As it is right now it seems like simplify will not drop any curves anymore at all, even those that do not differ from the rest pose and are redundant.

io_scene_fbx/fbx_utils.py
797

Instead of checking for the initial frame at all, the better solution would be to initialize p_key with default_values so that it always compares the first key to the rest pose. Initializing p_key with keys[0], as it is done currently, does absolutely nothing.

Evan Todd (et1337) edited edge metadata.

The original action and armature pose should now be restored after export. Also, the method of detecting the first keyframe should now be more robust. I rebased this diff on the latest version, not sure if that works or if I need to make a new revision.

As it is right now it seems like simplify will not drop any curves anymore at all, even those that do not differ from the rest pose and are redundant.

This patch only changes the behavior on the first frame.

Before, p_key and key would always be identical on the first frame, so it would get simplified away unless there was a different frame later on. If you wanted to have just a single keyframe on a channel, it would always get simplified away.

Now, on the first frame, if the value is the same as the bind pose, it simplifies it away. If it's different, it keys it.

I think the problem here for me is floating point inaccuracy.
This check if val == self.default_values[idx] will fail if the keys are close but not quite the same.
I do not key any scale curves on my bones, but after resampling it will usually come out as something like 0.999994.
This should probably use the same comparison as the other keys including the min_reldiff_fac and min_absdiff_fac.

Evan Todd (et1337) edited edge metadata.

Bind pose comparison now uses the same epsilon logic as the other keyframes.

I keep rebasing on the latest commit - tell me if I'm doing this wrong. I'm used to GitHub.

@Evan Todd (et1337), rebasing is fine here, noted some minor points but best to get @Bastien Montagne (mont29)'s input here.

Regarding:

The exporter simplifies keyframes on a per-component basis, e.g. X, Y, Z positions are simplified separately. Some pipelines (Assimp for example) can't handle individual components. This patch keys all components together if any one of them is changed.

This seems unnecessary to limit Blender's exports based on limits in assimp. Having separate keyframes per channel isn't an advanced feature.
But would like feedback from other devs too.

io_scene_fbx/export_fbx_bin.py
2103

this can use __slots__, (convention, but also avoids accidents).

Evan Todd (et1337) updated this revision to Diff 6188.EditedMar 1 2016, 4:55 AM

AnimatedObjectSnapshot uses __slots__ now.

This seems unnecessary to limit Blender's exports based on limits in assimp. Having separate keyframes per channel isn't an advanced feature.
But would like feedback from other devs too.

That's fair, but I'll point out that partial animations are currently broken for *all* content pipelines. It outputs incorrect keyframes where none exist.

Also just to kick in my 2 cents, per-component keyframes don't make much sense from a game dev perspective. The animation systems I've used always deal with complete positions, orientations, and scales. They're keyed separately, but each always has all of its components.

Any word on getting this merged?

Bump.

I've been using this in production for three months now.