Cant get a spatial's AnimControl

First off, G’day! I’m new to JME, with all of about 3 days experience. That experience isn’t without problems however, hence why I’m here.



I’ve been playing around with the concepts in the first couple of tutorials. I’ve sucessfully created a cube, created a textured cube, imported a model from blender, imported a textured model from blender… so on and so forth. Then I thought I’d try my hand at getting some animation, but have had no luck.



I created a quick test model in blender, gave it an armature, and a single animation. I put the .blend in my Project Assets folder, and have been working straight off the .blend (no conversion to .j3o).



I can load and view the model with no problems. But for some reason, I can not get the AnimControl from the spatial (using Spatial.getControl(AnimControl.class)). The method returns null, and obviously any subsequent method called on the non-existent control results in a NullPointerException. Furthermore, calling getNumControls() on the Spatial returns 0. The strange thing is, I have no problems viewing the animation in the SceneExplorer. The AnimControl exists, and it does what its supposed to (making me think there is nothing wrong with the model or animation itself???).



I thought it might be a problem with working out of the .blend, so tried to convert it to .j3o, but trying to load the .j3o results in an exception too…



I’ve really got no idea whats going on, and feel like a complete nuffty. As such, are you guys able to please shed some light on the situation? It would be greatly appreciated. I’ll attach the code and errors to this post.



Im running jMP Alpha-4, with the latest nightlies (as @ a couple of hours ago). Its probably obvious in the following code, but “zzz” is the Spatial and “doStuff” is the animation.



Here’s the main class:



[java] public class Main extends SimpleApplication {



AnimControl control;

AnimChannel channel;

Spatial zzz;



public static void main(String[] args) {

Main app = new Main();

app.start();

}



@Override

public void simpleInitApp() {



Material mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

mat.setColor(“Color”, ColorRGBA.Blue);



zzz = assetManager.loadModel(“Blends/zzz.blend”);

zzz.setMaterial(mat);

rootNode.attachChild(zzz);



control = zzz.getControl(AnimControl.class);

//Chucks a wobbly here, as getControl has returned null.

channel = control.createChannel();

channel.setAnim(“doStuff”);

channel.setLoopMode(LoopMode.Loop);



DirectionalLight light = new DirectionalLight();

light.setDirection(new Vector3f(-0.1f, -0.7f, -1f));

rootNode.addLight(light);





}



@Override

public void simpleUpdate(float tpf) {

//TODO: add update code

}



@Override

public void simpleRender(RenderManager rm) {

//TODO: add render code

}

}

[/java]



The associated exception is:


05/10/2011 11:33:03 PM com.jme3.app.Application handleError
SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.lang.NullPointerException
at mygame.Main.simpleInitApp(Main.java:39)
at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:230)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:129)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:205)
at java.lang.Thread.run(Thread.java:662)
05/10/2011 11:33:03 PM com.jme3.renderer.lwjgl.LwjglRenderer cleanup
INFO: Deleting objects and invalidating state
05/10/2011 11:33:03 PM com.jme3.input.lwjgl.LwjglMouseInput destroy
INFO: Mouse destroyed.
05/10/2011 11:33:03 PM com.jme3.input.lwjgl.LwjglKeyInput destroy
INFO: Keyboard destroyed.
05/10/2011 11:33:03 PM com.jme3.system.lwjgl.LwjglAbstractDisplay deinitInThread
INFO: Display destroyed.
Java Result: -1073741819


The exception thrown from trying to use the .j3o in place of the .blend is:


05/10/2011 11:34:21 PM com.jme3.app.Application handleError
SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.lang.ClassCastException: [Lcom.jme3.export.Savable; cannot be cast to [Lcom.jme3.animation.Track;
at com.jme3.animation.Animation.read(Animation.java:202)
at com.jme3.export.binary.BinaryImporter.readObject(BinaryImporter.java:357)
at com.jme3.export.binary.BinaryInputCapsule.resolveIDs(BinaryInputCapsule.java:484)
at com.jme3.export.binary.BinaryInputCapsule.readStringSavableMap(BinaryInputCapsule.java:668)
at com.jme3.animation.AnimControl.read(AnimControl.java:359)
at com.jme3.export.binary.BinaryImporter.readObject(BinaryImporter.java:357)
at com.jme3.export.binary.BinaryInputCapsule.resolveIDs(BinaryInputCapsule.java:484)
at com.jme3.export.binary.BinaryInputCapsule.readSavableArray(BinaryInputCapsule.java:472)
at com.jme3.export.binary.BinaryInputCapsule.readSavableArrayList(BinaryInputCapsule.java:588)
at com.jme3.scene.Spatial.read(Spatial.java:1283)
at com.jme3.scene.Node.read(Node.java:609)
at com.jme3.export.binary.BinaryImporter.readObject(BinaryImporter.java:357)
at com.jme3.export.binary.BinaryInputCapsule.resolveIDs(BinaryInputCapsule.java:484)
at com.jme3.export.binary.BinaryInputCapsule.readSavableArray(BinaryInputCapsule.java:472)
at com.jme3.export.binary.BinaryInputCapsule.readSavableArrayList(BinaryInputCapsule.java:588)
at com.jme3.scene.Node.read(Node.java:599)
at com.jme3.export.binary.BinaryImporter.readObject(BinaryImporter.java:357)
at com.jme3.export.binary.BinaryImporter.load(BinaryImporter.java:264)
at com.jme3.export.binary.BinaryImporter.load(BinaryImporter.java:147)
at com.jme3.export.binary.BinaryImporter.load(BinaryImporter.java:131)
at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:243)
at com.jme3.asset.DesktopAssetManager.loadModel(DesktopAssetManager.java:376)
at com.jme3.asset.DesktopAssetManager.loadModel(DesktopAssetManager.java:386)
at mygame.Main.simpleInitApp(Main.java:33)
at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:230)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:129)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:205)
at java.lang.Thread.run(Thread.java:662)
05/10/2011 11:34:21 PM com.jme3.renderer.lwjgl.LwjglRenderer cleanup
INFO: Deleting objects and invalidating state
05/10/2011 11:34:21 PM com.jme3.input.lwjgl.LwjglMouseInput destroy
INFO: Mouse destroyed.
05/10/2011 11:34:21 PM com.jme3.input.lwjgl.LwjglKeyInput destroy
INFO: Keyboard destroyed.
05/10/2011 11:34:21 PM com.jme3.system.lwjgl.LwjglAbstractDisplay deinitInThread
INFO: Display destroyed.


Let me know if you need any more info, or if I have commited any major social faux pas with this post.
Thank you all very much.

Sorry!!! References to Main.Java:39 in the first exception is line 24 in the posted code (method called on channel).

Main.Java:33 in the second exception is line 18 (loading the Spatial, albeit as the j3o).

The blender loader does not attach the AnimControl to the loaded model yet. hence you obviously get NPE’s when trying to use the non-existing control :wink: @Kaelthas will change this some time soon I guess, for now use OgreXML as explained.

Ahh, no worries; I dont feel like such a nuffty now ;). Thanks for the speedy reply Normen.

Could you post here the blend file you are using ?:slight_smile:

I can take a look at it and figure out what is wrong.



The blender loader is attaching AnimControl and SkeletonControl to the model.

I was able to load the model with defined actions and animate it the way you did.

:slight_smile:

G’day Kaelthas,



I’ve uploaded the .blend to:



http://www.fileden.com/files/2011/10/6/3205271/zzz.blend



It was created in Blender 2.59. Be prepared to be astounded by my wonderful Blender skills :wink:



Thankyou!

Also, the female model from that other thread has a skeleton but no animations and loads without a SkeletonControl. Maybe that problem is related but I’m sad I can’t use the model with hair. :slight_smile: (reference: http://hub.jmonkeyengine.org/groups/import-assets/forum/topic/blender-loader-npe-in-armaturemodifier/ )



It’s so nice that blender import is getting so easy.

OK the problem with zzz.blend and female is simple :slight_smile:

By default jme uses BlenderModelLoader to load the objects.

But the returned Spatial is not the object you have in the scene but the root node that

all objects and lights from the scene are attached to.



So what you need to do is to iterate the children, find the object you want (if there is only a single object then getting the first child will do fine)

and then get the control and run the animation.



I successfully run the animation in zzz.





Maybe we should reconsider this kind of model loading because as I see it is quite confusing.

@normen what do you think ?

Shall I load only the first model I find in the scene with BlenderModelLoader ?

1 Like

Kaelthas, you’ve truly made my day! Its working fine. Much appreciated! :slight_smile:



I know you didn’t ask me; but for what its worth, and from a newbie’s perspective, this method of loading seems quite logical. Providing however that it is explained somewhere. Perhaps an ammendum to the ‘Hello Assets’ tutorial would be sufficient?

I agree… I’d rather have all of the data and then sort if out myself if I need to. Better than bald women running around. :stuck_out_tongue:



If it’s an issue, perhaps JME could some day provide some convenience utilities for grabbing the first found control of a node’s children or something.

I think the AnimControl should be attached to the root node when theres only one for the model (e.g. proper model with one armature and animation set) and if theres multiple animations / armatures then attach them to the corresponding object.