[dead] JME3 COLLADA loader

omg, you really put out a version already? …daring… but cool! :wink:

I added the following to the PhysicsCar example code removing the floor (Box b) and replacing it with a model of a car. I realize this isn't the best test here, but regardless of what I do, I can't "find" the file. I've put the file in with all the other files I'm using for this project, as well as in every directory between the my project and the one I'm pointing to but I'm still getting the error below:



     

 //        //box stand in

//        Box b = new Box(new Vector3f(0, 0, 0), 0.5f, 0.5f, 2f);

//        Geometry g = new Geometry("Box", b);

//        g.setMaterial(matBox);

//        player = new PhysicsVehicleNode(g, new BoxCollisionShape(new Vector3f(0.5f, 0.5f, 2f)), 1);

        assetManager.registerLocator("…/", FileLocator.class.getName());

        assetManager.registerLoader(ColladaLoader.class.getName(), "dae");

        Spatial car = assetManager.loadModel("dependencies/models/car.dae");

        rootNode.attachChild(car);







INFO LwjglAbstractDisplay 9:42:07 PM Display created.

INFO LwjglAbstractDisplay 9:42:07 PM Adapter: null

INFO LwjglAbstractDisplay 9:42:07 PM Driver Version: null

INFO LwjglAbstractDisplay 9:42:07 PM Vendor: NVIDIA Corporation

INFO LwjglAbstractDisplay 9:42:07 PM OpenGL Version: 2.1.2 NVIDIA 173.14.22

INFO LwjglAbstractDisplay 9:42:07 PM Renderer: GeForce 8600 GT/PCI/SSE2

INFO LwjglAbstractDisplay 9:42:07 PM GLSL Ver: 1.20 NVIDIA via Cg compiler

INFO LwjglTimer 9:42:07 PM Timer resolution: 1000 ticks per second

INFO Camera 9:42:07 PM Camera created (W: 640, H: 480)

INFO LwjglMouseInput 9:42:07 PM Mouse created.

INFO LwjglKeyInput 9:42:07 PM Keyboard created.

INFO Node 9:42:08 PM Child (BitmapFont) attached to this node (Gui Node)

INFO Node 9:42:08 PM Child (BitmapFont) attached to this node (Statistics View)

INFO Node 9:42:08 PM Child (BitmapFont) attached to this node (Statistics View)

INFO Node 9:42:08 PM Child (BitmapFont) attached to this node (Statistics View)

INFO Node 9:42:08 PM Child (BitmapFont) attached to this node (Statistics View)

INFO Node 9:42:08 PM Child (BitmapFont) attached to this node (Statistics View)

INFO Node 9:42:08 PM Child (BitmapFont) attached to this node (Statistics View)

INFO Node 9:42:08 PM Child (BitmapFont) attached to this node (Statistics View)

INFO Node 9:42:08 PM Child (BitmapFont) attached to this node (Statistics View)

INFO Node 9:42:08 PM Child (BitmapFont) attached to this node (Statistics View)

INFO Node 9:42:08 PM Child (BitmapFont) attached to this node (Statistics View)

INFO Node 9:42:08 PM Child (BitmapFont) attached to this node (Statistics View)

INFO Node 9:42:08 PM Child (BitmapFont) attached to this node (Statistics View)

INFO Node 9:42:08 PM Child (BitmapFont) attached to this node (Statistics View)

INFO Node 9:42:08 PM Child (Statistics View) attached to this node (Gui Node)

INFO Node 9:42:08 PM Child (Floor) attached to this node (null)

INFO Node 9:42:08 PM Child (null) attached to this node (Root Node)

SEVERE ColladaLoader 9:42:08 PM null

java.lang.IndexOutOfBoundsException: Index: 0, Size: 0

        at java.util.LinkedList.entry(LinkedList.java:365)

        at java.util.LinkedList.get(LinkedList.java:315)

        at jme3dae.collada14.transformers.TransformationElementTransformer.transform(TransformationElementTransformer.java:44)

        at jme3dae.collada14.transformers.SceneTransformer.parseNode(SceneTransformer.java:158)

        at jme3dae.collada14.transformers.SceneTransformer.parseVisualScene(SceneTransformer.java:128)

        at jme3dae.collada14.transformers.SceneTransformer.parseInstanceVisualScene(SceneTransformer.java:81)

        at jme3dae.collada14.transformers.SceneTransformer.transform(SceneTransformer.java:58)

        at jme3dae.collada14.ColladaDocumentV14.transform(ColladaDocumentV14.java:79)

        at jme3dae.collada14.ColladaDocumentV14.transform(ColladaDocumentV14.java:28)

        at jme3dae.ColladaLoader.load(ColladaLoader.java:41)

        at jme3dae.ColladaLoader.load(ColladaLoader.java:18)

        at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:162)

        at com.jme3.asset.DesktopAssetManager.loadModel(DesktopAssetManager.java:282)

        at com.jme3.asset.DesktopAssetManager.loadModel(DesktopAssetManager.java:292)

        at RayTest.PhysicsCar.buildPlayer(PhysicsCar.java:289)

        at RayTest.PhysicsCar.simpleInitApp(PhysicsCar.java:118)

        at com.jme3.app.SimpleBulletApplication.initialize(SimpleBulletApplication.java:253)

        at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:102)

        at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:147)

        at java.lang.Thread.run(Thread.java:619)

WARNING DesktopAssetManager 9:42:08 PM Error occured while loading resource dependencies/models/car.dae using ColladaLoader

SEVERE Application 9:42:08 PM Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]

java.lang.NullPointerException

        at com.jme3.asset.ModelKey.createClonedInstance(ModelKey.java:18)

        at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:186)

        at com.jme3.asset.DesktopAssetManager.loadModel(DesktopAssetManager.java:282)

        at com.jme3.asset.DesktopAssetManager.loadModel(DesktopAssetManager.java:292)

        at RayTest.PhysicsCar.buildPlayer(PhysicsCar.java:289)

        at RayTest.PhysicsCar.simpleInitApp(PhysicsCar.java:118)

        at com.jme3.app.SimpleBulletApplication.initialize(SimpleBulletApplication.java:253)

        at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:102)

        at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:147)

        at java.lang.Thread.run(Thread.java:619)

It's ok, in the sense that the asset loader finds the file and the collada loader tries to load it. It's just the loader that screws things up. Can you post the collada file "car.dae"?

I attempted to use two different files. Both of these worked in jme2.  They are attached below:

The stack trace of the reported exception seems to refer to an older version of the plug-in. Try downloading the jar file again from the link in the first post. I have updated it to print a version string, check if a line like this



INFO ColladaDocumentV14 18.58.12 ColladaParser v. 0.1



appears while starting your app.



I did a test using the same jar and it can load the scenes in the posted files.



The materials i use right now are shadeless so the look won't be the best possible but this can be improved later with not changes to user code.

I downloaded the latest version and tested it out. it still won't load. here is the output:



INFO: Child (Floor) attached to this node (null)

Jul 22, 2010 2:58:01 PM com.jme3.scene.Node attachChild

INFO: Child (null) attached to this node (Root Node)

===============HERE===================

Jul 22, 2010 2:58:01 PM jme3dae.collada14.ColladaDocumentV14 transform

INFO: ColladaParser v. 0.1

Jul 22, 2010 2:58:01 PM com.jme3.scene.Node attachChild

INFO: Child (SketchUp) attached to this node (COLLADA SCENE)

APPLYING MATERIAL Material2

MATERIAL 22896671 APP TO 22130853

Jul 22, 2010 2:58:01 PM com.jme3.scene.Node attachChild

INFO: Child (model) attached to this node (null)

Jul 22, 2010 2:58:01 PM com.jme3.scene.Node attachChild

INFO: Child () attached to this node (SketchUp)

Jul 22, 2010 2:58:01 PM com.jme3.scene.Node attachChild

INFO: Child (COLLADA SCENE) attached to this node (Root Node)

Jul 22, 2010 2:58:01 PM com.jme3.app.Application handleError

SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]

java.lang.NullPointerException

        at RayTest.PhysicsCar.buildPlayer(PhysicsCar.java:357)

        at RayTest.PhysicsCar.simpleInitApp(PhysicsCar.java:119)

        at com.jme3.app.SimpleBulletApplication.initialize(SimpleBulletApplication.java:259)

        at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:102)

        at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:147)

        at java.lang.Thread.run(Thread.java:619)

BUILD SUCCESSFUL (total time: 4 seconds)

The model is loaded (or at least the log says that it has been attached to the scene).



The npe says that something is missing while trying to use that model with PhysicsCar. Maybe it has to do with the mesh, maybe not. I'll give it a check.

I have a similar exception if i try to use the model as it is in the TestFancyCar test.



Notice that the TestFancyCar use the names of the elements in the model file to grab the wheels: your model has a different kind of name-mapping (the wheels are "Wheel1", "Wheel1_1", "Wheel1_2", "Wheel1_3" and they are not geometries but Nodes). Your model doesn't have a chassis built with one geometry, instead it has a chassis built with a set of sub-nodes). If i'm right, you can still use the TestFancyCar as a guideline but you can't just apply your model to it.

Well, I pasted my loading code into the TestOGRELoading" file and the COLLADA model loaded just fine.  Looks great actually. I guess I'm just having problems with the PhysicsCar demo.  I also could not get OGRE models to load in it either.



Sorry about the confusion there. It seems to be working as it should. thanks for the help though.

Thanks to you for the time spent testing the loader.

Back to animation… help needed.



I have a list of per-bone animation: at time T rotate/move/scale the bone K.



Let's say that I have built the skeleton and I can get the meshes that are bound to that skeleton.



What I had in mind was:


  1. for each animation create a set of BoneTrack elements
  2. with each set of BoneTrack, create a BoneAnimation
  3. With the Skeleton and the Meshes create an AnimControl instance
  4. add to the AnimControl the bone animation instances
  5. associate the AnimControl to the spatial representing the animated model, via setControl.



    If that is right, the problems i have are:



    BoneAnimation requires a length float: is that the total length of the animation (ie Max(frameTime of each BoneTrack))?

    AnimControl requires a Node: can i use the node that groups the geometries that wrap the animated meshes or any node is fine?

    Do i have to do something with AnimChannel?



    Thanks.
BoneAnimation requires a length float: is that the total length of the animation (ie Max(frameTime of each BoneTrack))?

Yes.

AnimControl requires a Node: can i use the node that groups the geometries that wrap the animated meshes or any node is fine?
Do i have to do something with AnimChannel?

The node that contains all geometries animated by the AnimControl is fine.

Well, i have found a new very very complicated way to make objects disappear from screen…



Ps.: in AnimControl one has to call setAnimations(new HashMap<String, BoneAnimation>()) before to call addAnim because the "animationMap" field defaults to null. An NPE is throw pretty everywhere.

No luck with proper animation yet but while working on it i had a freaky idea.



ExplicitAnimationNode, aka “the poor man’s animation utility”.



Using a naming convention (animation_name+frame_index), ExplicitAnimationNode extracts from a scene (a jme3 node, it really works with any kind of node) sequences of explicit animation frames.



Like:



Node scene = any jme3 node with a scene containing some explicit animation frame

ExplicitAnimationNode ex = ExplicitAnimationNode.createFrom(scene);

rootNode.attachChild(ex);



end of the job. This is a sample blender scene containing the animation data:







That scene has some object. One is named “stand001”, two are named “walk001” “walk002”, the other is named “player”. So the createFrom method generates an ExplicitAnimationNode with 2 animations, one called “stand” composed of one frame, one called “walk” composed of two frame, walk001 followed by walk002.



Transformations are discarded so the “workspace” can be organized at will.



There’s no need to say how problematic explicit animation is but this experiment makes me think to another crazy idea: what if instead of relyng on the representation of a bone-animation by some format, we could be able to extract a bone animation from the analysys of a “3d workspace”, built in any format (let’s say in obj format)?



I had this idea because the cheapness of ExplicitAnimationNode has one strenght: it doesn’t depend on the source format neither it depends on the editor capability to actually generate explicit animation. It just need to be able to create meshes and name them.



Would it be possible to generate a reasonabley easy “convention” to create skeltal animations? I got to try (sooner or later).

This is a good idea if you're making a game for Android, which won't run skeletal animations at acceptable speeds (jPCT tests indicate 10-20 fps with a single skeletal-animated model).

In that case, you'll be forced to use vertex animation, which is essentially a different vertex buffer for every frame in the animation.

Still I don't see any excuse not to support COLLADA skeletal animations, I did have a few looks at the format and generated files and found its very similar to how its structured for Ogre3D models.

The excuse is that, as you might have noticed, i tend to loose focus quite easily.



I had to check a couple of things to solve the phantom-mesh problem (namely that the data received by the mesh and the AnimControl is right and the other thing that the ogre loader does with the vertex buffer of the mesh and i don't) but then i get lost doing other things.

I think i'm missing a step in jme3 animation. I've built a test case that does what the plugin does. This is the content of the simpleInitApp of a SimpleApplication that has not other methods.


   float[] normals = { 0, 0, 1, 0, 0, 1, 0, 0, 1 };
   float[] positions = { -1, 0, 0, 1, 0, 0, 0, 2, 0 };
   int[] indices = { 0, 1, 2 };
   float[] weights = { 0,0,0,0, 0,0,0,0, 1,0,0,0 }; //just v2 affected by bone 0
   byte[] bones = { 0,0,0,0, 0,0,0,0, 0,0,0,0 }; //all v bound to bone 0
   
   Mesh mesh = new Mesh();
   mesh.setBuffer(Type.Position, 3, positions.clone());
   mesh.setBuffer(Type.Normal, 3, normals.clone());
   mesh.setBuffer(Type.Index, 1, indices.clone());
   mesh.setBuffer(Type.BindPosePosition, 3, positions.clone());
   mesh.setBuffer(Type.BindPoseNormal, 3, normals.clone());

   VertexBuffer vertexWeightBuffer = new VertexBuffer(Type.BoneWeight);
   VertexBuffer boneIndexBuffer = new VertexBuffer(Type.BoneIndex);
   vertexWeightBuffer.setupData(Usage.CpuOnly, 4, Format.Float, FloatBuffer.wrap(weights));
   boneIndexBuffer.setupData(Usage.CpuOnly, 4, Format.UnsignedByte, ByteBuffer.wrap(bones));
   mesh.setBuffer(vertexWeightBuffer);
   mesh.setBuffer(boneIndexBuffer);

   Geometry geom = new Geometry("triangle", mesh);
   geom.setMaterial(assetManager.loadMaterial("/Common/Materials/RedColor.j3m"));

   Node node = new Node("geom owner");
   node.attachChild(geom);

   Bone bone = new Bone("bone 0");
   bone.setBindTransforms(new Vector3f(), new Quaternion(0, 0, 0, 1));

   Skeleton skeleton = new Skeleton(new Bone[] { bone });
   skeleton.setBindingPose();

   float[] times = { 0, 10 };
   Vector3f[] translations = { new Vector3f(0, 0, 0), new Vector3f(0, 2, 0) };
   Quaternion[] rotations = { new Quaternion(0, 0, 0, 1), new Quaternion(0, 0, 0, 1) };
   BoneTrack boneTrack = new BoneTrack(0, times, translations, rotations);

   BoneAnimation boneAnim = new BoneAnimation("test animation", 10);
   boneAnim.setTracks(new BoneTrack[] { boneTrack });

   final AnimControl anim = new AnimControl(node, new Mesh[] { mesh }, skeleton );
   anim.setAnimations(new HashMap<String, BoneAnimation>());
   anim.addAnim(boneAnim);
   AnimChannel channel = anim.createChannel();
   channel.setAnim("test animation");
   channel.setSpeed(0.001f);

   node.addControl(anim);

   rootNode.attachChild(node);



The mesh is correctly displayed if i set "anim.setEnabled(false)". I'll try to make little changes to catch the problem but, in the meantime, maybe someone can catch the problem at first glance.

Debug update 1: the mesh position gets annihilated when animated (all zero)

Just as a side-note, there are some interesting links coming up in this conversation that might come in handy:

Well, I do not agree very much with the "collada is complex, bloated and huge" statement. It is a properly specified format and this alone makes it a rare jewel. Parsing it is by no means a difficult task, the only reason why i cannot support animations yet is because i don't want to create a parallel animation library in JME3 and I haven't found yet the proper slots where to put the data extracted from the collada document but this is a fault in my understanding of jme, not something that makes collada particularily complex. I have to say that the support that blender offers to collada is a bit raw, being an open source project I was expecting better support for an open format, but I can't say how much time and resources they had to put in that plugin: in the end, all depends on that.

Btw, I have created a jMP plugin from this Collada importer, enabling a “convert to jme3 binary”  command for dae files in jMP. If you download the pre-version of alpha2 here and enable the “Contributions” update center in tools->plugins->settings you should be able to select it on the “available plugins” page. Its a compile of the most current svn version of the loader and also a good example of how other importers can be added w/o bloating the jME3 core too much…