Exception playing Anim with an ArmatureMask

I just downloaded 2 models (from a new artist that I have never used used before), but
now I’m having trouble using both of them with an ArmatureMask in JME with the latest version of the engine (v3.6.1-stable)

As soon as I play an animation using an ArmatureMask, the app crashes with the following exception:

java.lang.ClassCastException: class com.jme3.scene.Node cannot be cast to class com.jme3.anim.Joint (com.jme3.scene.Node and com.jme3.anim.Joint are in unnamed module of loader 'app')
	at com.jme3.anim.ArmatureMask.contains(ArmatureMask.java:65)
	at com.jme3.anim.tween.action.ClipAction.doInterpolate(ClipAction.java:27)
	at com.jme3.anim.tween.action.BlendableAction.interpolate(BlendableAction.java:84)
	at com.jme3.anim.AnimLayer.update(AnimLayer.java:270)
	at com.jme3.anim.AnimComposer.controlUpdate(AnimComposer.java:402)
	at com.jme3.scene.control.AbstractControl.update(AbstractControl.java:118)
	at com.jme3.scene.Spatial.runControlUpdate(Spatial.java:743)
	at com.jme3.scene.Spatial.updateLogicalState(Spatial.java:922)
	at com.jme3.scene.Node.updateLogicalState(Node.java:228)
	at com.jme3.scene.Node.updateLogicalState(Node.java:239)
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:265)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:160)
	at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:225)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:242)
	at java.base/java.lang.Thread.run(Thread.java:833)

If I use this code to play any animation using an ArmatureMask (regardless of which Joints the mask contains), the app crashes with the exception above:

        ArmatureMask mask = new ArmatureMask(skinningControl.getArmature());
        
        animComposer.makeLayer("RootLayer", mask);
        
        animComposer.setCurrentAction("Walk_F_IP", "RootLayer");  //crashes

However, I do not have any issues when I play the animation in the SDK or in my game without armatureMasks. It runs fine if I directly play an animation on the whole AnimComposer with this code:

         animComposer.setCurrentAction(walkAnim);  //works

So something strange seems to be happening when the ArmatureMask is getting setup for certain models that is causing a Node to somehow get mixed into a list of Joints.


The models I’m having trouble with are unfortunately paid assets, so I can’t publicly post them for troubleshooting help.

Specifically I’m having trouble with a wolf and pig model from a guy on sketchfab who has some very nice animated animal models, but apparently he does something different in his modeling/animating workflow that JME does not like

So if anyone is willing to help and needs the model to do more investigation, then I can send you a google-drive download link for the model for troubleshooting purposes.

But hopefully the exception I posted can at least help get the troubleshooting process started.

1 Like

I guess it is because the model uses both spatial animation and bone animation.

A TransformTrack can target either a Joint or a Spatial. (they both implement HasLocalTransform interface).

We can deal with this in multiple ways inside ArmatureMask.

1- just ignore if target is not a joint and return false. (i.e. spatial animations won’t show up) and perhaps log a warning. Be aware of possible performance impacts for logging in this case.

2- throw an exception with a proper message indicating that “armature mask does not support non-joint targets and a different type of mask should be used” or something like that.

3- ?

2 Likes

I think the second option would be the better of the 2, since I think we should try to find a way to eventually support playing spatial animations on just one section of the model if that is possible. But I don’t have enough experience with the new animation system and morph animations to know if that’s something that’s simple or even possible to do. But if playing a morph animation on only part of a spatial is not possible, then your 1st would be the better option probably, and then in that case jme users would have to resort to playing animations on the whole animComposer and not use ArmatureMasks for that model if they want tp use its spatial animations (I will probably do this as a workaround in the meantime, since I probably don’t need multiple armatureMasks for a wolf model as much as I would for a human-based model).

Ideally, I would say that the ArmatureMask class should be changed (or a new alternative should be created as you suggested) so that it will automatically detect which vertices are associated with each joint when a joint gets are added to the armatureMask, and then the armatureMask will know which vertices to play the morph animation on for that mask. Or if the morphTargets can’t be automatically determined based on the Joint, then the developer would just have to initiate the armatureMask to include which vertices/morph targets to play the spatial animations on.

But again I have very little experience with spatial animation using the new animation system so I could be overlooking some limitations that would make this a lot more difficult (also I am assuming spatial animation is the same as morph animation and have been using the terms interchangeably, please correct me if I’m wrong on that or anything else though).

1 Like

Nope, they are different. Spatial animation is the animation applied on a Node or Geometry and can transform it (move, rotate, scale). Note, it does not modify the mesh.

For morph animation JME does not apply mask

2 Likes

Oh lol, my mistake. I never heard of spatial animations before this somehow, but that makes more sense in the context of this issue. I was needlessly overcomplicating things out of confusion, but I appreciate the clarification.

So in that case I don’t think it would break things that much if the spatial animations are ignored, since it is easy to adjust the whole spatial’s rotation / translation in-game where you have easy control of an npc model’s viewDir and location, plus for a game you usually want to use in-place animations so you can dynamically control the position and rotation of the NPC anyways.

So I would say that your first option, to ignore the spatial animations for animations played on armatureMasks with some type of warning, sounds like a good solution.

Maybe also check if the ArmatureMask contains every Joint or even just the Root joint (in case an ArmatureMask is being used as a root-mask of some type) and then only play the Spatial Animations in that case. Otherwise, its probably best to ignore the spatial animation when using armature masks.

1 Like

Thanks for the help on this issue, I was able to implement your first suggestion:

by extending ArmatureMask and overriding the contains() method:

public class TEMP_ArmatureMask extends ArmatureMask {    
    
    public TEMP_ArmatureMask() {
        super();
    }

    public TEMP_ArmatureMask(Armature armature) {
        super(armature);        
    }    
    
    @Override
    public boolean contains(Object target) {
        if(target instanceof Node){
            return false;
        }
        return super.contains(target);
    }
}

And now the exception is gone and things are working again.

It looks like most of the in-place animations are the same, although I expect the non-in-place animations would now be in-place if run on this armature mask that ignores the spatial animations.

So it could still be a good idea to make it so that Spatial Animations are still played if the ArmatureMask contains the rootBone, and ignore them otherwise. But for now ignoring them completely is is a sufficient fix.

1 Like