KhronosGroup / glTF-Blender-IO

Blender glTF 2.0 importer and exporter
https://docs.blender.org/manual/en/latest/addons/import_export/scene_gltf2.html
Apache License 2.0
1.5k stars 319 forks source link

Scaling affects exported animation #1083

Closed emackey closed 8 months ago

emackey commented 4 years ago

I feel like this might already be known, but I'll write it up anyway, as I have a nearly minimal reproduce case for it.

If a parent object has non-uniform scaling (or possibly, non-identity scaling), animations on child objects can become distorted on export.

In this sample Blender 2.8x project, there are two cubes. The orange cube has a node scaling that makes it elongated, and the blue cube is a child.

ScaleExport_Blender

When exporting to glTF, the orange cube exports correctly. But the blue child cube has its rotation distorted by the scaling factor.

ScaleExport_glTF

Here's the Blender project:

ScaledExportTest.zip

julienduroure commented 4 years ago

Note this is not only animation error. Still rotation are also false: image

Probably a missing _matrix_parentinverse multiplication somewhere

scurest commented 3 years ago

It is actually impossible to represent this scene in glTF with only two nodes.

The TRS for the blue box must be (world matrix for orange box).inverted() @ (world matrix for blue box) (modulo Zup2Yup conversion). However in this scene, at, say, frame 100

badmat

This matrix is not a TRS matrix (or that dot-product would be zero).

It's not possible to fix this without inserting another node between the two boxes.

emackey commented 3 years ago

Bummer. Thanks for confirming. Should we print a warning, or try to insert the in-between node?

scurest commented 3 years ago

Probably print a warning, but not sure if the current animation code actually knows when it's indecomposable. I think it would be possible to insert a static in-between node in some special cases but not all cases (edit: actually I think all cases are ok), and not sure how "noisy" it would be, or how complex the implementation would be.

btw export->reimport with both .dae and .fbx also show this effect.

fire commented 1 year ago

https://github.com/iimachines/Maya2glTF/issues/67 @ziriax mentioned a way to decompose scaled objects.

julienduroure commented 1 year ago

@fire Thanks, I will have a look soon.

Another solution is to implement flatten tree, as we did for armatures (See #1683)

julienduroure commented 8 months ago

Closing this ticket, as we now have an option to export flatten tree (all object at root of scene), avoiding this issue

IncredibleMeh commented 2 weeks ago

I'm aware this issue has been closed and I may drawing ire by commenting. But after facing this exact problem and stumbling here after extended time searching I have to make it clear that flattening the bone hierarchy of an armature is not an adequate solution. Techniques like inverse kinematics rely heavily on there being a discernible bone chain, which is very often utilized in real-time engines for assisting already rendered animations (such as keeping feet level with the ground.) So presenting a flat hierarchy as a solution does not make sense and would result in choosing between scaling issues or losing major functionality. Ideally, this issue should be revisited.

emackey commented 2 weeks ago

@IncredibleMeh This issue frustrates me too, but the root cause is fundamental to the way basic transformation math works in its simplest form. Blender avoids it with its magical "Parent Inverse" matrices, which cause a number of side-effects of their own but are believed to be less-bad than allowing objects to become distorted by child rotations. So there's no "bug fix" to be had here. glTF and all of its many clients and implementations across the industry just implement a normal TRS scene hierarchy, and a normal scene hierarchy is susceptible to this problem. There's no quick patch to this exporter that will solve it.

There's a much better workaround than flattening everything, of course. You can "Apply Scale" (in Blender) to any non-uniformly-scaled parent objects that have rotating children below them.

That's the root of this problem: A non-uniform scale (where X, Y, and/or Z are scaled by different amounts) interferes with the normal math for rotating child objects, as the children inherit the scale and rotate through differently-sized axes. So any parents that have non-uniform scale need to be converted to uniformly-scaled objects prior to export. This is needed not just for glTF, but for any rendering engine that uses simple, traditional TRS scene hierarchy. Blender's "Apply Scale" option, used surgically on the offending parent objects, may provide an escape from this issue.