Ogre3D Mesh.XML Importer

You can't really directly control poses unless they are in an animation… Direct control is not supported by the importer.

The link to loader doesn't work…

I fixed it now :slight_smile: It's still best if you get it from the Radakan source which might have some fixes

:

http://code.google.com/p/radakan/source/browse/trunk#trunk/ogreloader

Hi,



I tried to export model from blender with skeletal animation. Ogre Importer works fine example files like ninja. But with my file only mesh loaded successfully and if I try to start animation following exception is thrown:



INFO: Child (OgreMesh) attached to this node (rootNode)
Mar 21, 2009 11:17:41 AM class test.OgreTest start()
SEVERE: Exception in game loop
java.nio.BufferUnderflowException
   at java.nio.Buffer.nextGetIndex(Buffer.java:474)
   at java.nio.DirectFloatBufferU.get(DirectFloatBufferU.java:205)
   at com.radakan.jme.mxml.anim.MeshAnimationController.softwareSkinUpdate(MeshAnimationController.java:312)
   at com.radakan.jme.mxml.anim.MeshAnimationController.update(MeshAnimationController.java:417)
   at com.jme.scene.Spatial.updateWorldData(Spatial.java:541)
   at com.jme.scene.Node.updateWorldData(Node.java:383)
   at com.jme.scene.Spatial.updateGeometricState(Spatial.java:517)
   at com.jme.scene.Node.updateWorldData(Node.java:395)
   at com.jme.scene.Spatial.updateGeometricState(Spatial.java:517)
   at test.OgreTest.simpleInitGame(OgreTest.java:149)
   at com.jme.app.BaseSimpleGame.initGame(BaseSimpleGame.java:544)
   at com.jme.app.BaseGame.start(BaseGame.java:74)
   at test.OgreTest.main(OgreTest.java:43)
Mar 21, 2009 11:17:41 AM com.jme.app.BaseSimpleGame cleanup
INFO: Cleaning up resources.
Mar 21, 2009 11:17:41 AM com.jme.app.BaseGame start
INFO: Application ending.



What did I do wrong? Which options should be used when exporting from blender with Ogre Meshes exporter?

I have also problems with textures. In which file format textures should be? tga without compression? Gimp also asks for origin when saving tga. Options are bottom/right and top/left. Which one should be used?

I am using OgreImporter form Radakan project

URL: http://radakan.googlecode.com/svn/trunk
Repository Root: http://radakan.googlecode.com/svn
Repository UUID: 06f53981-2c4c-0410-8a1d-d54e5c4dde6c
Revision: 622

Check my files from:
http://194.100.84.38/~pekka/jme/

-jpm

Hello, I've had much fun working with this so far. One question, can a single skeleton drive multiple meshes? For equipment and such instead of attaching I have the all the different parts set to use the same skeleton. Thanks for this great piece of software!



Oh, and jpm, the line where your error occurs seems to deal with vertex weights, perhaps your exporter isn't exporting them, or if you don't use weights maybe try setting all the weights to 1 or commenting out the weight calculations in MeshAnimationController.

Thanks ravenhearte, setting all vertex weights to 1 solved animation problem.



-jpm

I have also problems with textures. In which file format textures should be? tga without compression? Gimp also asks for origin when saving tga. Options are bottom/right and top/left. Which one should be used?

With the latest patch, jME should support both compressed and uncompressed TGAs. About the origin thing, I am not sure, but I think both work.

One question, can a single skeleton drive multiple meshes? For equipment and such instead of attaching I have the all the different parts set to use the same skeleton.

The MeshAnimationController has a method getBone(), from it you can get the world transform of the bone, you then apply that transform to your equipment. Ideally there should be a more streamlined way of doing this.. Feel free to change the importer to support this feature.

ravenhearte said:

Oh, and jpm, the line where your error occurs seems to deal with vertex weights, perhaps your exporter isn't exporting them, or if you don't use weights maybe try setting all the weights to 1 or commenting out the weight calculations in MeshAnimationController.

jpm said:

Thanks ravenhearte, setting all vertex weights to 1 solved animation problem.

-jpm

I actually checked the files and it seems that there is only 71 vertex-to-bone weights specified where as there are 72 verticies, that could be the issue.

There's a NullPointerException thrown when attempting to load a model with pose animations and with no skeleton animations.



Just have to add a check for the skeleton being null in one place in MeshAnimationController as far as I can tell (works for me, at least); heres the dif:





Index: C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/MeshAnimationController.java
===================================================================
--- C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/MeshAnimationController.java   (revision 622)
+++ C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/MeshAnimationController.java   (working copy)
@@ -238,8 +238,11 @@
     
     void reset(){
         resetToBind();
-        skeleton.getRoot().reset();
-        skeleton.getRoot().update();
+        if(skeleton != null)     
+        {
+           skeleton.getRoot().reset();
+           skeleton.getRoot().update();
+        }
         resetToBindEveryFrame = false;
         animation = null;
         time = 0;

Thanks for the report. I fixed this in my local copy.

Hi,


Momoko_Fan said:

I actually checked the files and it seems that there is only 71 vertex-to-bone weights specified where as there are 72 verticies, that could be the issue.


Actually I got it working after making sure that every single vertex is included by only one vertex group. Is it feature or bug, I don't know...

Next question:

I have tested Ninja scene and textures are loaded correctly. I my own scene textures are not found and got following error message:


Apr 4, 2009 10:27:55 AM com.jme.util.resource.ResourceLocatorTool locateResource
WARNING: Unable to locate: box.jpg



box.jpg is in same folder with material file. I modified material file by adding ./ before box.jpg so it looks like:


material Material2
{
        receive_shadows on
        technique
        {
                pass
                {
                        ambient 0.500000 0.500000 0.500000 1.000000
                        diffuse 0.704000 0.712000 0.584000 1.000000
                        specular 0.500000 0.500000 0.500000 1.000000 12.500000
                        emissive 0.000000 0.000000 0.000000 1.000000
                        texture_unit
                        {
                                texture ./box.jpg
                                tex_address_mode wrap
                                filtering trilinear
                                colour_op alpha_blend
                        }
                }
        }
}



Now textures are loaded correctly but adding ./ may cause problems on other OSes. I am using Linux. And I don't understand why ./ is not needed in ninja's Example.material.

Thanks for help...

Another question:



Is there a way to find out material and texture of triangle which have been selected for example by ray picking??



-jpm

Now textures are loaded correctly but adding ./ may cause problems on other OSes. I am using Linux. And I don't understand why ./ is not needed in ninja's Example.material.

Look at the test example. You will see that texture paths are specified using the ResourceLocatorTool for ResourceLocatorType.TYPE_TEXTURE. Make sure that the paths your locators specify point to where the textures are.


Is there a way to find out material and texture of triangle which have been selected for example by ray picking??

Unless you explicitly specified mesh names in your modeling tool or exporter, the names are assigned the same as their materials. Since each mesh must have one material, you can find the material of a triangle simply by getting the name of its mesh.

Im having issues getting materials to work in 3ds, im getting the following stack trace :

java.io.IOException: Unknown scene_blend mode: zero

at com.radakan.jme.mxml.MaterialLoader.readPassStatement(MaterialLoader.java:280)

at com.radakan.jme.mxml.MaterialLoader.readPass(MaterialLoader.java:351)

at com.radakan.jme.mxml.MaterialLoader.readTechnique(MaterialLoader.java:376)

at com.radakan.jme.mxml.MaterialLoader.readMaterial(MaterialLoader.java:440)

at com.radakan.jme.mxml.MaterialLoader.load(MaterialLoader.java:477)

at game.GameBase.loadMeshModel(GameBase.java:269)

at game.GameBase.buildPlayer(GameBase.java:216)

at game.GameBase.initGame(GameBase.java:144)

at com.jme.app.BaseGame.start(BaseGame.java:74)

at game.GameBase.main(GameBase.java:68)



i cant figure out how to get 3ds to export the texture without a scene_blend mode, and none of the modes in the dropdown box will allow my game to run. Any ideas?

Can you please attach/send the problematic .material file?

material 01-Default
{
   receive_shadows off
   transparency_casts_shadows off
   technique Map#1
   {
      pass Map#2
      {
         ambient 0.698039 0.698039 0.698039 1
         diffuse 0.556863 0.972549 0.47451 1
         specular 0.898039 0.898039 0.898039 1 20
         emissive 0 0 0 1
         scene_blend one zero
         depth_check on
         depth_write on
         depth_func less_equal
         depth_bias 0 0
         alpha_rejection always_pass 0
         cull_hardware clockwise
         cull_software back
         lighting on
         shading gouraud
         polygon_mode solid
         colour_write on
         max_lights 8
         start_light 0
         iteration once
      }

   }

}



I apologize in advance if im doing something really stupid here
this is my first try at 3D stuff 

hey! are you working with googlecode svn? would be nice since your last edit (first post of this topic) was a month ago and i don't know if this is actually the most recent/working version!


I was trying to save/load the models loaded with the OgreLoader into a binary format, and I ended up using com.jme.util.export.binary.BinaryExporter/Importer, and that required me to implement the Savable interface for MeshAnimationController.



I implemented Serializable with some of the other classes (as this seemed simpler, and even if it is less effective, it's not much of an issue in my case), and saved them as a byte array from MeshAnimationController.



Also, the the BinaryExporter/Importer require default constructors, so OgreMesh and MeshAnimationController had to have them; and the variables being saved in read/write for Savable had to be non-final, so I also removed those modifiers.



So if this is useful to anyone else, here are the diffs:



MeshAnimationController:


Index: C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/MeshAnimationController.java
===================================================================
--- C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/MeshAnimationController.java   (revision 622)
+++ C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/MeshAnimationController.java   (working copy)
@@ -28,19 +28,28 @@
 
 package com.radakan.jme.mxml.anim;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.util.Collection;
+import java.util.Map;
+
 import com.jme.math.Matrix4f;
 import com.jme.math.Vector3f;
-import com.jme.renderer.Camera.FrustumIntersect;
-import java.util.Map;
-
 import com.jme.scene.Controller;
 import com.jme.scene.state.GLSLShaderObjectsState;
 import com.jme.scene.state.RenderState;
-import java.nio.ByteBuffer;
-import java.nio.FloatBuffer;
-import java.util.Collection;
+import com.jme.util.export.InputCapsule;
+import com.jme.util.export.JMEExporter;
+import com.jme.util.export.JMEImporter;
+import com.jme.util.export.OutputCapsule;
+import com.jme.util.export.Savable;
 
-public class MeshAnimationController extends Controller {
+public class MeshAnimationController extends Controller implements Savable {
 
     private static final long serialVersionUID = -2412532346418342259L;
 
@@ -52,17 +61,17 @@
     /**
      * List of targets which this controller effects.
      */
-    private final OgreMesh[] targets;
+    private OgreMesh[] targets;
     
     /**
      * Skeleton object must contain corresponding data for the targets' weight buffers.
      */
-    private final Skeleton skeleton;
+    private Skeleton skeleton;
     
     /**
      * List of animations, bone or vertex based.
      */
-    private final Map<String, Animation> animationMap;
+    private Map<String, Animation> animationMap;
     
     /**
      * The currently playing animation.
@@ -81,6 +90,11 @@
      */
     private int framesToSkip = 0;
     private int curFrame = 0;
+   
+    public MeshAnimationController()
+    {
+   
+    }
 
     public MeshAnimationController(OgreMesh[] meshes,
                                    Skeleton skeleton,
@@ -238,8 +252,11 @@
     
     void reset(){
         resetToBind();
-        skeleton.getRoot().reset();
-        skeleton.getRoot().update();
+        if(skeleton != null)     
+        {
+           skeleton.getRoot().reset();
+           skeleton.getRoot().update();
+        }
         resetToBindEveryFrame = false;
         animation = null;
         time = 0;
@@ -282,8 +299,8 @@
         Matrix4f offsetMatrices[] = skeleton.computeSkinningMatrices();
         
         // NOTE: This code assumes the vertex buffer is in bind pose
-        // resetToBind() has been called this frame
-        FloatBuffer vb = mesh.getVertexBuffer();
+        // resetToBind() has been called this frame       
+        FloatBuffer vb = mesh.getVertexBuffer();       
         vb.rewind();
         
         FloatBuffer nb = mesh.getNormalBuffer();
@@ -422,5 +439,43 @@
         time += tpf * getSpeed();
     }
     
+    public void write(JMEExporter e) throws IOException {
+        super.write(e);
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(bos);       
+        oos.writeObject(animationMap);
+        oos.flush();
+        oos.close();
+        bos.close();
+        byte [] data = bos.toByteArray();
+       
+        OutputCapsule output = e.getCapsule(this);
+        output.write(data, "MeshAnimationControllerData", null);
+        output.write(targets, "targets[]", null);
+        output.write(skeleton, "skeleton", null);
+    }
     
+    @SuppressWarnings("unchecked")
+   public void read(JMEImporter e) throws IOException {
+        super.read(e);       
+        InputCapsule input = e.getCapsule(this);
+       
+        byte [] data = input.readByteArray("MeshAnimationControllerData", null);
+      Savable[] targetsSavable = input.readSavableArray("targets[]", null);
+      skeleton = (Skeleton) input.readSavable("skeleton", null);
+      
+      targets = new OgreMesh[targetsSavable.length];   
+      int i = 0;
+      for(Savable s : targetsSavable)  targets[i++] = (OgreMesh)s;
+      
+      
+      
+      ByteArrayInputStream bis = new ByteArrayInputStream(data);
+       ObjectInputStream ois = new ObjectInputStream(bis);
+       try {     
+          animationMap = (Map<String, Animation>) ois.readObject();
+       } catch (ClassNotFoundException e1) {      
+          throw new RuntimeException(e1);
+       }
+    }
 }




MeshAnimation:


Index: C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/MeshAnimation.java
===================================================================
--- C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/MeshAnimation.java   (revision 622)
+++ C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/MeshAnimation.java   (working copy)
@@ -28,8 +28,11 @@
 
 package com.radakan.jme.mxml.anim;
 
-public class MeshAnimation {
+import java.io.Serializable;
 
+public class MeshAnimation implements Serializable{
+
+    private static final long serialVersionUID = 1L;
     private String name;
     private float length;
     private Track[] tracks;



BoneTrack:


Index: C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/BoneTrack.java
===================================================================
--- C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/BoneTrack.java   (revision 622)
+++ C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/BoneTrack.java   (working copy)
@@ -28,14 +28,19 @@
 
 package com.radakan.jme.mxml.anim;
 
+import java.io.Serializable;
+
 import com.jme.math.Quaternion;
 import com.jme.math.Vector3f;
 
+
 /**
  * Contains a list of transforms and times for each keyframe.
  */
-public final class BoneTrack {
+public final class BoneTrack implements Serializable{
 
+    private static final long serialVersionUID = 1L;
+
     /**
      * Bone index in the skeleton which this track effects.
      */
@@ -153,5 +158,4 @@
             target.setAnimTransforms(tempV, tempQ);
         }
     }
-    
 }



BoneAnimation:


Index: C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/BoneAnimation.java
===================================================================
--- C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/BoneAnimation.java   (revision 622)
+++ C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/BoneAnimation.java   (working copy)
@@ -28,12 +28,15 @@
 
 package com.radakan.jme.mxml.anim;
 
+import java.io.Serializable;
+
+
 /**
  * Bone animation updates each of it's tracks with the skeleton and time
  * to apply the animation.
  */
-public final class BoneAnimation {
-
+public final class BoneAnimation implements Serializable{
+    private static final long serialVersionUID = 1L;
     private final String name;
     private final float length;
    
@@ -62,5 +65,4 @@
             tracks[i].setTime(time, skeleton);
         }
     }
-    
 }




Bone:


Index: C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/Bone.java
===================================================================
--- C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/Bone.java   (revision 622)
+++ C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/Bone.java   (working copy)
@@ -32,11 +32,19 @@
 import com.jme.math.Quaternion;
 import com.jme.math.Vector3f;
 import com.jme.scene.Node;
+import com.jme.util.export.InputCapsule;
+import com.jme.util.export.JMEExporter;
+import com.jme.util.export.JMEImporter;
+import com.jme.util.export.OutputCapsule;
+import com.jme.util.export.Savable;
+
+import java.io.IOException;
+import java.io.Serializable;
 import java.util.ArrayList;
 
-public final class Bone {
+public final class Bone implements Savable, Serializable {
    
-    final String name;
+    String name;
    
     Bone parent;
     final ArrayList<Bone> children = new ArrayList<Bone>();
@@ -260,6 +268,59 @@
     void setBindTransforms(Vector3f translation, Quaternion rotation){
         setBindTransforms(translation, rotation, Vector3f.UNIT_XYZ);
     }
+
+    @Override
+    public Class getClassTag() {
+   // TODO Auto-generated method stub
+   return null;
+    }
+
    
+    private final static String defName = "Unnamed Bone";
+    private final static String childBoneWrite = "ChildBone";
+    private final static String childBoneCount = "Child Bone Count";
+    private final static String parentBoneWrite = "Parent Bone";
+    @Override
+    public void read(JMEImporter im) throws IOException {
+   InputCapsule input = im.getCapsule(this);
+   name = input.readString("name", defName);
+   initialPos = (Vector3f) input.readSavable("initialPos", null);
+   initialRot = (Quaternion) input.readSavable("initialRot", null);
+   worldBindInversePos = (Vector3f) input.readSavable("worldBindInversePos", null);
+   worldBindInverseRot = (Quaternion) input.readSavable("worldBindInverseRot", null);
+   localPos = (Vector3f) input.readSavable("localPos", null);
+   localRot = (Quaternion) input.readSavable("localRot", null);
+   worldPos = (Vector3f) input.readSavable("worldPos", new Vector3f());
+   worldRot = (Quaternion) input.readSavable("worldRot", new Vector3f());
+   
+   parent = (Bone) input.readSavable(parentBoneWrite, null);
+   int childCount = input.readInt(childBoneCount, 0);
+   for(int i = 0; i < childCount; i++)
+   {       
+       Bone child = (Bone) input.readSavable(childBoneWrite + i, null);
+       if(child != null) children.add(child);
+   }
+   
+    }
+
+    @Override
+    public void write(JMEExporter ex) throws IOException {
+   OutputCapsule output = ex.getCapsule(this);
+   output.write(name, "name", defName);   
+   output.write(initialPos, "initialPos", null);
+   output.write(initialRot, "initialRot", null);
+   output.write(worldBindInversePos, "worldBindInversePos", null);
+   output.write(worldBindInverseRot, "worldBindInverseRot", null);
+   output.write(localPos, "localPos", null);
+   output.write(localRot, "localRot", null);
+   output.write(worldPos, "worldPos", worldPos);
+   output.write(worldRot, "worldRot", worldRot);
+   
+   output.write(parent, parentBoneWrite, null);
+   output.write(children.size(), childBoneCount, 0);
+   int i = 0;
+   for(Bone childBone : children) output.write(childBone, childBoneWrite + i++, null);   
+    }
+    
      
 }




(Continued further)

The rest of the diffs:





Animation:


Index: C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/Animation.java
===================================================================
--- C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/Animation.java   (revision 622)
+++ C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/Animation.java   (working copy)
@@ -28,11 +28,15 @@
 
 package com.radakan.jme.mxml.anim;
 
+
+import java.io.Serializable;
+
+
 /**
  * Combines mesh and bone animations into one class for easier access
  */
-public class Animation {
-
+public class Animation implements Serializable{
+    private static final long serialVersionUID = 1L;
     private final String name;
     private float length;
     
@@ -102,7 +106,4 @@
     BoneAnimation getBoneAnimation(){
         return boneAnim;
     }
-   
-   
-   
 }



OgreMesh:



import com.jme.scene.TriMesh;
import com.jme.util.export.InputCapsule;
import com.jme.util.export.JMEExporter;
import com.jme.util.export.JMEImporter;
import com.jme.util.export.OutputCapsule;
import com.jme.util.geom.BufferUtils;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

/**
 * Holds the bind pose, lod levels and a weightbuffer that defines vertex->bone/weight associations.
 */
public class OgreMesh extends TriMesh {

    private static final long serialVersionUID = 8831653270716808462L;
   
    private transient FloatBuffer vertexBufferOriginal;
    private transient FloatBuffer normalBufferOriginal;
   
    private WeightBuffer weightBuffer;
   
    private IntBuffer levelZero;
    private IntBuffer[] lodLevels;
   
    public OgreMesh(String name){
        super(name);
    }
   
    public void cloneFromMesh(OgreMesh source){
        vertexBufferOriginal = source.vertexBufferOriginal;
        normalBufferOriginal = source.normalBufferOriginal;
       
        if (hasBindPose()){
            setVertexBuffer(BufferUtils.createFloatBuffer(source.getVertexBuffer().capacity()));
            setNormalBuffer(BufferUtils.createFloatBuffer(source.getNormalBuffer().capacity()));
            restoreBindPose();
        }
       
        setWeightBuffer(source.weightBuffer);
        setLodLevels(source.lodLevels);
    }
   
    public void setWeightBuffer(WeightBuffer weightBuf){
        if (weightBuf == null)
            return;
       
        if (weightBuf.indexes.limit() / 4 != this.getVertexCount())
            throw new IllegalArgumentException();
       
        weightBuffer = weightBuf;
    }
   
    public WeightBuffer getWeightBuffer(){
        return weightBuffer;
    }
   
    public FloatBuffer getVertexBufferOriginal(){
        return vertexBufferOriginal;
    }
   
    public FloatBuffer getNormalBufferOriginal(){
        return normalBufferOriginal;
    }
   
    public void setLodLevels(IntBuffer[] lodLevels){
        this.levelZero = getIndexBuffer();
        this.lodLevels = lodLevels;
    }
   
    /**
     * Set the current LOD level.
     * LOD level zero is the model in max quality,
     * levels 1 and below reduce the quality/vertex count of the model
     * by a certain amount to increase rendering speed.
     * @param level
     */
    public void setLodLevel(int level){
        IntBuffer target;
       
        if (level == 0)
            target = levelZero;
        else
            target = lodLevels[level-1];
       
        if (target != indexBuffer){
            setIndexBuffer(target);
//            DisplaySystem.getDisplaySystem().getRenderer().deleteVBO(vboInfo.getVBOVertexID());
//            vboInfo.setVBOIndexID(-1);
        }
    }
   
    @Override
    public void setHasDirtyVertices(boolean flag){
        super.setHasDirtyVertices(flag);
       
        if (flag && (vboInfo != null && vboInfo.isVBOVertexEnabled() && vboInfo.isVBONormalEnabled())){
            // update VBO data here
            // not supported by jME yet..
        }
    }
   
    /**
     * @return Total number of lod levels
     */
    public int getLodLevelCount(){
        if (lodLevels == null)
            return 1;
           
        return lodLevels.length + 1;
    }
   
    /**
     * Clears all bind pose data
     */
    public void clearBindPose(){
        vertexBufferOriginal = null;
        normalBufferOriginal = null;
    }
   
    /**
     * Saves the current mesh state to it's bind pose.
     */
    public void saveCurrentToBindPose(){
        if (vertexBufferOriginal == null){
            vertexBufferOriginal = BufferUtils.createFloatBuffer(vertBuf.capacity());
        }
        if (normalBufferOriginal == null){
            normalBufferOriginal = BufferUtils.createFloatBuffer(normBuf.capacity());
        }
             
        vertBuf.rewind();
        vertexBufferOriginal.rewind();
        vertexBufferOriginal.put(vertBuf);
       
        normBuf.rewind();
        normalBufferOriginal.rewind();
        normalBufferOriginal.put(normBuf);
    }
   
    /**
     * Restores bind pose
     */
    public void restoreBindPose(){
        vertBuf.rewind();
        vertexBufferOriginal.rewind();
        vertBuf.put(vertexBufferOriginal);
       
        normBuf.rewind();
        normalBufferOriginal.rewind();
        normBuf.put(normalBufferOriginal);
    }
   
    /**
     * True if bind pose data is available
     * @return
     */
    public boolean hasBindPose(){
        return vertexBufferOriginal != null &&
               (normBuf == null || normalBufferOriginal != null);
    }
   
    @Override
    public void write(JMEExporter e) throws IOException{
        // dont want to write a vertex buffer in an animation here..
        // make sure to restore bind pose
        if (hasBindPose())
            restoreBindPose();
       
        super.write(e);
       
        OutputCapsule out = e.getCapsule(this);
        out.write(hasBindPose(), "HadBindPose", false);
        if (weightBuffer != null){
            out.write(weightBuffer.indexes, "BoneIndexes", null);
            out.write(weightBuffer.weights, "BoneWeights", null);
            out.write(weightBuffer.maxWeightsPerVert, "maxWeightsPerVert", 0);           
        }
    }
   
    @Override
    public void read(JMEImporter i) throws IOException{
        super.read(i);
       
        InputCapsule in = i.getCapsule(this);
        if (in.readBoolean("HadBindPose", false)){
            saveCurrentToBindPose();
        }
       
        ByteBuffer indexes = in.readByteBuffer("BoneIndexes", null);
        if (indexes != null){
            FloatBuffer weights = in.readFloatBuffer("BoneWeights", null);
            weightBuffer = new WeightBuffer(indexes, weights);
            weightBuffer.maxWeightsPerVert = in.readInt("maxWeightsPerVert", 0);
           
        }
    }
   
    /** Used for binary loading */
    public OgreMesh() {

    }
   
}




Pose:


Index: C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/Pose.java
===================================================================
--- C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/Pose.java   (revision 622)
+++ C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/Pose.java   (working copy)
@@ -30,12 +30,14 @@
 
 import com.jme.math.Vector3f;
 import com.jme.util.geom.BufferUtils;
+
+import java.io.Serializable;
 import java.nio.FloatBuffer;
 
 /**
  * A pose is a list of offsets that say where a mesh verticles should be for this pose.
  */
-public final class Pose {
+public final class Pose implements Serializable{
 
     private final String name;
     private final int targetMeshIndex;




PoseTrack:


Index: C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/PoseTrack.java
===================================================================
--- C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/PoseTrack.java   (revision 622)
+++ C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/PoseTrack.java   (working copy)
@@ -28,15 +28,17 @@
 
 package com.radakan.jme.mxml.anim;
 
+import java.io.Serializable;
+
 /**
  * A single track of pose animation associated with a certain mesh.
  */
-public final class PoseTrack extends Track {
+public final class PoseTrack extends Track implements Serializable {
 
     private PoseFrame[] frames;
     private float[]     times;
     
-    public static class PoseFrame {
+    public static class PoseFrame implements Serializable{
         
         public PoseFrame(Pose[] poses, float[] weights){
             this.poses = poses;




Skeleton:


Index: C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/Skeleton.java
===================================================================
--- C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/Skeleton.java   (revision 622)
+++ C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/Skeleton.java   (working copy)
@@ -28,15 +28,23 @@
 
 package com.radakan.jme.mxml.anim;
 
+import java.io.IOException;
+import java.io.Serializable;
+
 import com.jme.math.Matrix4f;
 import com.jme.scene.state.GLSLShaderObjectsState;
+import com.jme.util.export.InputCapsule;
+import com.jme.util.export.JMEExporter;
+import com.jme.util.export.JMEImporter;
+import com.jme.util.export.OutputCapsule;
+import com.jme.util.export.Savable;
 
 /**
  * A skeleton is a hierarchy of bones.
  * Skeleton updates the world transforms to reflect the current local
  * animated matrixes.
  */
-public final class Skeleton {
+public final class Skeleton implements Savable, Serializable {
 
     private Bone rootBone;
     private Bone[] boneList;
@@ -149,5 +157,27 @@
         //shader.setUniform("boneMatrices", skinningMats, true);
         throw new UnsupportedOperationException("Hardware skinning cannot be used without a jME2 patch");
     }
+
+    @Override
+    public Class getClassTag() {
+   // TODO Auto-generated method stub
+   return this.getClass();
+    }
+
+    @Override
+    public void read(JMEImporter im) throws IOException {
+   InputCapsule input = im.getCapsule(this);
+   rootBone = (Bone) input.readSavable("rootBone", null);
+   boneList = (Bone[]) input.readSavableArray("boneList", null);
+   skinningMatrixes = (Matrix4f[]) input.readSavableArray("skinningMatrixes", null);
+    }
+
+    @Override
+    public void write(JMEExporter ex) throws IOException {
+   OutputCapsule output = ex.getCapsule(this);
+   output.write(rootBone, "rootBone", null);
+   output.write(boneList, "boneList", null);
+   output.write(skinningMatrixes, "skinningMatrixes", null);
+    }
 
 }



Track:


Index: C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/Track.java
===================================================================
--- C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/Track.java   (revision 622)
+++ C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/Track.java   (working copy)
@@ -28,12 +28,15 @@
 
 package com.radakan.jme.mxml.anim;
 
+import java.io.Serializable;
+
 /**
  * A single track of mesh animation (either morph or pose based).
  * Currently morph animations are not supported (only pose).
  */
-public abstract class Track {
+public abstract class Track implements Serializable {
 
+    private static final long serialVersionUID = 1L;
     protected final int targetMeshIndex;
     
     public Track(int targetMeshIndex){




WeightBuffer:


Index: C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/WeightBuffer.java
===================================================================
--- C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/WeightBuffer.java   (revision 622)
+++ C:/Documents and Settings/Wizem/workspace/OgreLoader/src/com/radakan/jme/mxml/anim/WeightBuffer.java   (working copy)
@@ -30,87 +30,124 @@
 
 import com.jme.scene.state.GLSLShaderObjectsState;
 import com.jme.util.geom.BufferUtils;
+
+import java.io.IOException;
+import java.io.Serializable;
 import java.nio.ByteBuffer;
 import java.nio.FloatBuffer;
 
 /**
  * WeightBuffer contains associations of vertexes to bones and their weights.
- * The WeightBuffer can be sent to a shader or processed on the CPU
- * to do skinning.
+ * The WeightBuffer can be sent to a shader or processed on the CPU to do
+ * skinning.
  */
-public final class WeightBuffer {
+public final class WeightBuffer implements Serializable {
 
+    private static final long serialVersionUID = 1L;
+
     /**
      * Each 4 bytes in the boneIndex buffer are assigned to a vertex.
      *
      */
-    final ByteBuffer indexes;
-   
+    ByteBuffer indexes;
+
     /**
      * The weight of each bone specified in the index buffer
      */
-    final FloatBuffer weights;
-   
+    FloatBuffer weights;
+
     /**
-     * The maximum number of weighted bones used by the vertices
-     * Can be 1-4. The indexes and weights still have 4 components per vertex,
-     * regardless of this value.
+     * The maximum number of weighted bones used by the vertices Can be 1-4. The
+     * indexes and weights still have 4 components per vertex, regardless of
+     * this value.
      */
     int maxWeightsPerVert = 0;
-   
-    public WeightBuffer(int vertexCount){
-        indexes = BufferUtils.createByteBuffer(vertexCount * 4);
-        weights = BufferUtils.createFloatBuffer(vertexCount * 4);
+
+    public WeightBuffer(int vertexCount) {
+   indexes = BufferUtils.createByteBuffer(vertexCount * 4);
+   weights = BufferUtils.createFloatBuffer(vertexCount * 4);
     }
-   
-    public WeightBuffer(ByteBuffer indexes, FloatBuffer weights){
-        this.indexes = indexes;
-        this.weights = weights;
+
+    public WeightBuffer(ByteBuffer indexes, FloatBuffer weights) {
+   this.indexes = indexes;
+   this.weights = weights;
     }
-     
-    public void sendToShader(GLSLShaderObjectsState shader){
-        indexes.rewind();
-        shader.setAttributePointer("indexes", 4, false, true, 0, indexes);
-       
-        if (maxWeightsPerVert > 1){
-            weights.rewind();
-            shader.setAttributePointer("weights", 4, true, 0, weights);
-        }
+
+    public void sendToShader(GLSLShaderObjectsState shader) {
+   indexes.rewind();
+   shader.setAttributePointer("indexes", 4, false, true, 0, indexes);
+
+   if (maxWeightsPerVert > 1) {
+       weights.rewind();
+       shader.setAttributePointer("weights", 4, true, 0, weights);
+   }
     }
-   
+
     /**
-     * Normalizes weights if needed and finds largest amount of weights used
-     * for all vertices in the buffer.
+     * Normalizes weights if needed and finds largest amount of weights used for
+     * all vertices in the buffer.
      */
-    public void initializeWeights(){
-        int nVerts = weights.capacity() / 4;
-        weights.rewind();
-        for (int v = 0; v < nVerts; v++){
-            float w0 = weights.get(),
-                  w1 = weights.get(),
-                  w2 = weights.get(),
-                  w3 = weights.get();
-           
-            if (w3 > 0.01f){
-                maxWeightsPerVert = Math.max(maxWeightsPerVert, 4);
-            }else if (w2 > 0.01f){
-                maxWeightsPerVert = Math.max(maxWeightsPerVert, 3);
-            }else if (w1 > 0.01f){
-                maxWeightsPerVert = Math.max(maxWeightsPerVert, 2);
-            }else if (w0 > 0.01f){
-                maxWeightsPerVert = Math.max(maxWeightsPerVert, 1);
-            }
-           
-            float sum = w0 + w1 + w2 + w3;
-            if (sum != 1f){
-                weights.position(weights.position()-4);
-                weights.put(w0 / sum);
-                weights.put(w1 / sum);
-                weights.put(w2 / sum);
-                weights.put(w3 / sum);
-            }
-        }
-        weights.rewind();
+    public void initializeWeights() {
+   int nVerts = weights.capacity() / 4;
+   weights.rewind();
+   for (int v = 0; v < nVerts; v++) {
+       float w0 = weights.get(), w1 = weights.get(), w2 = weights.get(), w3 = weights
+          .get();
+
+       if (w3 > 0.01f) {
+      maxWeightsPerVert = Math.max(maxWeightsPerVert, 4);
+       } else if (w2 > 0.01f) {
+      maxWeightsPerVert = Math.max(maxWeightsPerVert, 3);
+       } else if (w1 > 0.01f) {
+      maxWeightsPerVert = Math.max(maxWeightsPerVert, 2);
+       } else if (w0 > 0.01f) {
+      maxWeightsPerVert = Math.max(maxWeightsPerVert, 1);
+       }
+
+       float sum = w0 + w1 + w2 + w3;
+       if (sum != 1f) {
+      weights.position(weights.position() - 4);
+      weights.put(w0 / sum);
+      weights.put(w1 / sum);
+      weights.put(w2 / sum);
+      weights.put(w3 / sum);
+       }
+   }
+   weights.rewind();
     }
-   
+
+    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+   out.write(maxWeightsPerVert);
+   
+   byte[] indexesArray = new byte[indexes.capacity()];
+   for(int i = 0; i < indexesArray.length; i++) indexesArray[i] = indexes.get();
+   out.write(indexesArray.length);
+   out.write(indexesArray);
+   
+   
+   float[] weightsArray = new float[weights.capacity()];
+   for(int i = 0; i < weightsArray.length; i++) weightsArray[i] = weights.get();
+   out.write(weightsArray.length);
+   for(float weight : weightsArray) out.writeFloat(weight);
+    }
+
+    private void readObject(java.io.ObjectInputStream in) throws IOException,
+       ClassNotFoundException {
+   maxWeightsPerVert = in.readInt();
+   
+   int indexesArrayLength = in.readInt();
+   byte[] indexesArray = new byte[indexesArrayLength];
+   in.read(indexesArray, 0, indexesArrayLength);   
+   indexes = BufferUtils.createByteBuffer(indexesArray.length);
+   for(byte b : indexesArray) indexes.put(b);
+   
+   
+   int weightsArrayLength = in.readInt();
+   float[] weightsArray = new float[weightsArrayLength];
+   for(int i = 0; i < weightsArrayLength; i++) weightsArray[i] = in.readFloat();
+   weights = BufferUtils.createFloatBuffer(weightsArray.length);
+   for(float f : weightsArray) weights.put(f);
+
+    }
+
 }



Edit: Fixed all the bugs in the initial code; Sorry the OgreMesh is not a diff, I kind of commited the changes to my own repository, and in short I don't know how to better set things up to get a diff. The main difference is a default constructor and an extra line in read and write. If anyone wants to use this and has problems (though there shouldn't be any, as it works for me...), let me know... (I think I got all the changes here that I have on my local copy, though I could have made a mistake)

Hola Community,



I wrote a tutorial how to use OgreImporter’s SceneLoader. 



Starting with building the scene in blender, exporting it and then importing it.

Maybe someone will help that. Until today I didn’t know there was a SceneLoader also

in OgreImporter :D. But I am really really happy with it. Ok,…until now I only used very simple

Scenes…but that work (even with animation)  :roll:



Have a look here:



http://thomas.trocha.com/wp/?page_id=235

my exporter (maya) is able to export shared geometry. your importer doesn't reckognize that [so it seems to me]. if i turn on sharedgeometry within the xmlfile, my app crashes.

That's really odd because the importer does support shared geometry. Are you sure you're using the latest SVN version?

ttrocha said:

I wrote a tutorial how to use OgreImporter's SceneLoader. 

Starting with building the scene in blender, exporting it and then importing it.
Maybe someone will help that. Until today I didn't know there was a SceneLoader also
in OgreImporter :D. But I am really really happy with it. Ok,...until now I only used very simple
Scenes....but that work (even with animation)  :roll:

Have a look here:

http://thomas.trocha.com/wp/?page_id=235


Thanks! I put the tutorial on the first post of this thread.