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.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();
   public JointMesh createJointMesh()
      FloatBuffer crossSection=BufferUtils.createVector2Buffer(4);
      FloatBuffer spine=BufferUtils.createVector3Buffer(3);
      Extrusion e=new Extrusion("Extrusion",crossSection,spine);
      JointMesh jm=new JointMesh("JointMesh");
      return jm;
   protected void simpleInitGame()
      JointMesh jm=createJointMesh();
      jm.jointIndex=new int[12];
      for(int i=0;i<3;++i)
         for(int j=0;j<4;++j)
      JointController jc=new JointController(3);

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.


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


"" 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 ?

"" 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: 

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.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
   protected void simpleInitGame() {
      TestUtils.createXYZShape(display, rootNode);


    * 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());


         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.setTimes(1, 5);
       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 Source)
      at Source)
      at org.marcofrisan.mmorpg.test.joints.SimpleJointTest.main(

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

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