[SOLVED] OgreXML model animation broken after exporting to J3O

Hello everyone.

I have an Ogre dotScene file which works perfectly fine when loaded, but when I convert it to J3O (using the SDK), here’s what I get:

I tried investigating the problem a bit, and by using the XMLExporter class I noticed that the order of the bones differs between the spatial loaded from the ‘raw’ dotScene file and the one loaded from the J3O file. I also tried to manually update the bones, but that didn’t help either.

EDIT: Here’s what I mean by ‘the order of the bones differs’:

For the sake of completeness, here’s the code I have in my simpleInitApp():

private Map<String, AnimControl> findAnimControls(final Spatial parent, final Map<String, AnimControl> map) {
    final AnimControl animControl = parent.getControl(AnimControl.class);
    if (animControl != null) {
        map.put(animControl.getSpatial().getName().replace("-ogremesh", ""), animControl);
    }

    if (parent instanceof Node) {
        for (final Spatial s : ((Node) parent).getChildren()) {
            this.findAnimControls(s, map);
        }
    }

    return map;
}

Spatial warrior = assetManager.loadModel("Models/warrior.scene");
rootNode.attachChild(warrior);

System.out.println("WARRIOR.SCENE");
Map<String, AnimControl> controls = this.findAnimControls(warrior, new HashMap<String, AnimControl>());
for (AnimControl animControl : controls.values()) {
    animControl.createChannel().setAnim("walk-01");
}

Spatial warrior2 = assetManager.loadModel("Models/warrior.j3o");
warrior2.setLocalTranslation(2.0f, 0.0f, 0.0f);
rootNode.attachChild(warrior2);

System.out.println("WARRIOR.J3O");
Map<String, AnimControl> controls2 = this.findAnimControls(warrior2, new HashMap<String, AnimControl>());
for (AnimControl animControl : controls2.values()) {
    animControl.createChannel().setAnim("walk-01");
} 

Any ideas?

Regards,
Patryk

Common thing: Did you apply the location/scale/rotation before exporting it?

No, I actually just placed the raw files into the assets directory, right-clicked on the *.scene file and clicked the ‘Convert to j3o Binary’ :wink:

I mean before it became an ogre file was it applied so that the location and scale were 0,0,0 and 1,1,1?

(I only say this because that broken one looks like what happens when this isn’t done properly, if this hasn’t been done I’m not sure if it would work even before conversion to j3o but I figured it was worth saying)

If you’re talking about the location/scale when the model was exported, then yes. As you can see in the GIF, the raw model looks fine.

Not a clue then

Hi friend
Can you upload your .blend model . so we can check it out ?
and try to convert .blend file to .j3o instead of Ogre3d . and see if the problem solves .

I don’t use Blender, only 3dsmax. Also, it’s an asset I bought from 3DRT and the license doesn’t really allow to share the contents with anyone, unless it’s used in a compiled executable. :-/

I quickly put together my own serializer and the problem is now gone. What I’m basically doing to fix the problem is:

  1. First I’m looking for all AnimControls in the spatial and all of its children (deep search)
  2. For every AnimControl I find, I write its skeleton and animations, and the name of the spatial it originally belongs to, so I can load the pieces back and assign them to proper spatials. I break down animations into parts, i.e. I serialize the name and length separately from the tracks
  3. I use the BinaryExporter class to export the rest of the model.

Then for importing it back:

  1. I load the model using the BinaryImporter class

  2. Then I deeply remove all AnimControls and SkeletonControls

  3. From another file (the one I exported using the above steps) I read back the skeletons and animations. and assign them to proper spatials. To reload the skeleton, I resorted to a nasty hack of using reflection to call the Skeleton.createSkinningMatrices() method, because the skinning matrices are transient and thus ignored during serialization. Here’s the code (don’t expect fireworks):

                final Method method = skelly.getClass().getDeclaredMethod("createSkinningMatrices");
                method.setAccessible(true);
                method.invoke(skelly);
    
  4. Last but not least, I create the prior removed AnimControls and SkeletonControls using the skeleton that I have just read from the other file.

The above works fine and fast, which clearly shows that either the BinaryExporter or BinaryImporter have some bug somewhere. I know I would probably help more if I posted the model here so you could experiment, but you know how it is with licensing…

1 Like

Found the real cause of the problem. In the Skeleton.read() change:

    for (Bone rootBone : rootBones) {
        rootBone.update();
        rootBone.setBindingPose();
    }

To:

    for (Bone rootBone : rootBones) {
        rootBone.reset(); // added line
        rootBone.update();
        rootBone.setBindingPose();
    }
2 Likes