Need help with JointMesh and JointController

I started learning the joint animation thing on jme, and I have a problem. I typed in the following code. The main function is a standard one, and createJointMesh generates a JointMesh that looks like a box with 12 vertices. Vertices 0-3 form a square of 2x2 on the x and z axes, with the center of (0,0,0), and vertices 4-7 and 8-11 form the same square with the centers of (0,4,0) and (0,6,0). You can get my useless Extrusion class from here.

import someboddy.jme.shape.Extrusion;
import com.jme.util.geom.BufferUtils;
import java.nio.*;

import com.jme.app.SimpleGame;
import com.jme.math.Vector3f;
import com.jme.math.Quaternion;
import com.jme.scene.*;
import com.jme.scene.shape.*;

import com.jmex.model.JointMesh;
import com.jmex.model.animation.JointController;

public class JointLearn extends SimpleGame
{
   public static void main(String[] args)
   {
      JointLearn app=new JointLearn();
      app.setDialogBehaviour(ALWAYS_SHOW_PROPS_DIALOG);
      app.start();
   }
   
   public JointMesh createJointMesh()
   {
      FloatBuffer crossSection=BufferUtils.createVector2Buffer(4);
      crossSection.rewind();
      crossSection.put(-1).put(-1);
      crossSection.put(1).put(-1);
      crossSection.put(1).put(1);
      crossSection.put(-1).put(1);
      
      FloatBuffer spine=BufferUtils.createVector3Buffer(3);
      spine.put(0).put(0).put(0);
      spine.put(0).put(4).put(0);
      spine.put(0).put(6).put(0);
      
      Extrusion e=new Extrusion("Extrusion",crossSection,spine);
      e.getLocalTranslation().set(-20,0,0);
      
      JointMesh jm=new JointMesh("JointMesh");
      jm.reconstruct(e.getVertexBuffer(),null,null,null,e.getIndexBuffer());
      return jm;
   }
   
   protected void simpleInitGame()
   {
      JointMesh jm=createJointMesh();
      rootNode.attachChild(jm);
      
      jm.jointIndex=new int[12];
      for(int i=0;i<3;++i)
         for(int j=0;j<4;++j)
            jm.jointIndex[4*i+j]=0;
      
      JointController jc=new JointController(3);
      jc.addJointMesh(jm);
      
      jc.parentIndex[0]=-1;
      jc.parentIndex[1]=0;
      jc.parentIndex[2]=1;
      
      jc.localRefMatrix[0].setTranslation(0,0,0);
      jc.localRefMatrix[1].setTranslation(0,4,0);
      jc.localRefMatrix[2].setTranslation(0,2,0);
      
      jc.setTranslation(1,0,0,0,0);
      jc.setTranslation(1,0.5f,1,0,0);
      jc.setTranslation(1,1,0,0,0);
      
      jc.processController();
      
      jm.addController(jc);
   }
}



When I run it, I get a null pointer exception. The stack trace looks something like this(I removed the package info):
at JointController.udpateData
at JointController.update
at Spatial.updateWorldData
and so on.

I think I forget a function I need to call, but I have no idea which.


Help?

O.K., solved that. The normalBuffer was null.





Now, I can't make the animation work.



Can anyone tell me how to do this?



Can anyone post a small program that demonstrates the use of JointMEsh and JointController? Just an old code you might have.

This interests me too, to see joint mesh in action take a look at TestMilkJmeWrite.

I think this uses JointMesh and JointController.

If You get around to understand this stuff then please drop an explanation here

Mmmmm…



"BinaryToXML.java" does not contain the word joint. I begin to think that the sole purpose of those classes is to import MilkShape files.

hm, but JmeBinaryReader does contain it ?

"XMLToBinary.java" does contain the word "joint", but as a part of a tag name rather than a part of a class name.



Do you happen to know who wrote this class? The JavaDoc comment says "Jack Lindamood". Do you know by what name is he known here?

I believe that's Cep21 in the forum.

O.K., I P.M.ed him about this thread.

Ok, so to document the flaw i mentioned, i link this thread:

http://www.jmonkeyengine.com/jmeforum/index.php?topic=2715.0 

Cep hasn't been around for ageshe might have left

According to the stats, he last logged in back in June…

I will try to reach him on ICQ.

O.K., I've sent him a message. Hope he read it soon.

Thanks Cep. You are the man.

any progress ???

I also have made some test to create a JointMesh-JointController system to animate JointMesh.



After I got the same errors someboddy got, I have been able to correct them strictly following order of foundamental instructions as written in the MilkToJme class.



Now application runs without errors but I still am not able to animate anything. I suppose to have made some errors with jointIndex or parentIndex setup. But not sure.



Do you have any idea?


/**
 *
 */
package org.marcofrisan.mmorpg.test.joints;

import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import org.marcofrisan.mmorpg.test.util.TestUtils;

import com.jme.app.SimpleGame;
import com.jme.math.FastMath;
import com.jme.math.TransformMatrix;
import com.jme.math.Vector3f;
import com.jme.scene.Controller;
import com.jme.scene.shape.Cylinder;
import com.jme.util.geom.BufferUtils;
import com.jmex.model.JointMesh;
import com.jmex.model.animation.JointController;

/**
 * @author Marco Frisan
 *
 */
public class SimpleJointTest extends SimpleGame {
   // public String dataDir = System.getProperty("user.dir") +
   // System.getProperty("file.separator") + "data";

   /*
    * (non-Javadoc)
    *
    * @see com.jme.app.BaseSimpleGame#simpleInitGame()
    */
   @Override
   protected void simpleInitGame() {
      TestUtils.createXYZShape(display, rootNode);

      createMultipleJointMesh(1);
   }

   /**
    * Creates joNum JointMesh objects. It names them joint_0, joint_1 ...
    * joint_n. And attach them to rootNode.
    *
    * @param jmNum
    *            number of JointMesh objects to be created.
    */
   private void createMultipleJointMesh(int jmNum) {
      JointMesh jm[] = new JointMesh[jmNum];
      for (int i = 0; i < jmNum; i++) {
         jm[i] = createJointMesh();
         
         jm[i].setName("joint_" + i);
         
         jm[i].jointIndex = new int[jm[i].getVertexBuffer(0).capacity() / 3];
         for (int j = 0; j < 2; ++j)
            for (int k = 0; k < 6; ++k)
               jm[i].jointIndex[6 * j + k] = j - 1;
         
         //jm[i].setModelBound(new BoundingBox());
         //jm[i].updateModelBound();

         rootNode.attachChild(jm[i]);

         createJointController(2, jm[i]);
      }

   }

   /**
    * The method createJointMesh returns a JointMesh using buffers extracted
    * from a Cylinder.
    *
    * @return JointMesh
    */
   private JointMesh createJointMesh() {
      Cylinder cy = new Cylinder("Cylinder", 2, 6, 0.5f, 10f);

      // Rotate Cylinder vertices mesh to lie along Y axis, and
      // translate them by 5f along Y to get base cap lieing on XZ plane.
      FloatBuffer vertex = cy.getVertexBuffer(0);
      int capacity = vertex.capacity();
      //Quaternion rot = new Quaternion();
      //rot.fromAngleAxis(FastMath.PI * 0.5f, new Vector3f(1f, 0f, 0f));
      TransformMatrix tmRot = new TransformMatrix();
      tmRot.setEulerRot(FastMath.PI * 0.5f, 0f, 0f);
      // System.out.println("FloatBuffer vertex is large " + capacity);
      for (int i = 0; i < capacity; i += 3) {
         Vector3f tempVec = new Vector3f(vertex.get(i), vertex.get(i + 1), vertex
               .get(i + 2));
         tempVec = tmRot.multPoint(tempVec);//rot.mult(v);
         tempVec.y += 5f;
         vertex.put(i, tempVec.x);
         vertex.put(i + 1, tempVec.y);
         vertex.put(i + 2, tempVec.z);
      }
      // End "modeling" Cylinder mesh.

      FloatBuffer vertBuf = cy.getVertexBuffer(0);
      FloatBuffer normBuf = cy.getNormalBuffer(0);
      int cap = vertBuf.capacity();
      FloatBuffer colorBuf = BufferUtils.createColorBuffer(cap / 3);
      FloatBuffer texBuf = cy.getTextureBuffer(0, 0);
      IntBuffer indexBuf = cy.getIndexBuffer(0);
      
      JointMesh jm = new JointMesh("JointMesh");
      jm.reconstruct(vertBuf, normBuf, colorBuf, texBuf, indexBuf);
      jm.originalNormal = BufferUtils.getVector3Array(normBuf);
      jm.originalVertex = BufferUtils.getVector3Array(vertBuf);
      
      return jm;
   }

   private void createJointController(int joNum, JointMesh jm) {
      JointController jc = new JointController(joNum);
      jc.FPS = 1;
      
      for (int i = 0; i < joNum; i++) {
         jc.localRefMatrix[i].setEulerRot(0f, 0f, 0f);
         jc.localRefMatrix[i].setTranslation(0f, 0f, 0f);
         // Set keyframes for rotation and translation.
         for (int j = 0; j < 25; j++) {
            jc.setRotation(i, j*400, FastMath.PI / 6, 0f, 0f);
            jc.setTranslation(i, j*400, 0f, 0f, 0f);
         }
         jc.parentIndex[i] = i - 1;
      }
      
      jc.setRepeatType(Controller.RT_WRAP);
      jc.setTimes(1, 5);
      rootNode.addController(jc);
      
       for (int k=0;k<rootNode.getQuantity();k++){
            if (rootNode.getChild(k) instanceof JointMesh)
                jc.addJointMesh((JointMesh) rootNode.getChild(k));
        }
      
      //jm.addController(jc); // Before corrections I got this Exception.
/*      java.lang.NullPointerException
      at com.jmex.model.animation.JointController.updateData(Unknown Source)
      at com.jmex.model.animation.JointController.update(Unknown Source)
      at com.jme.scene.Spatial.updateWorldData(Unknown Source)
      at com.jme.scene.Geometry.updateWorldData(Unknown Source)
      at com.jme.scene.Spatial.updateGeometricState(Unknown Source)
      at com.jme.scene.Node.updateWorldData(Unknown Source)
      at com.jme.scene.Spatial.updateGeometricState(Unknown Source)
      at com.jme.app.SimpleGame.update(Unknown Source)
      at com.jme.app.BaseGame.start(Unknown Source)
      at org.marcofrisan.mmorpg.test.joints.SimpleJointTest.main(SimpleJointTest.java:162)
*/
   }

   /**
    * @param args
    */
   public static void main(String[] args) {
      // Initializes new Application and set Config Dialog behaviour.
      SimpleJointTest app = new SimpleJointTest();
      app
            .setDialogBehaviour(SimpleGame.FIRSTRUN_OR_NOCONFIGFILE_SHOW_PROPS_DIALOG);

      // Starts the Application launcing simpleInitGame() and than Game Loop
      // with update() and render().
      app.start();
   }

}