浏览代码

Adds support for different joint model transform accumulation strategy

Nehon 7 年之前
父节点
当前提交
e5057ad7fa

+ 31 - 4
jme3-core/src/main/java/com/jme3/anim/Armature.java

@@ -1,5 +1,6 @@
 package com.jme3.anim;
 package com.jme3.anim;
 
 
+import com.jme3.anim.util.JointModelTransform;
 import com.jme3.export.*;
 import com.jme3.export.*;
 import com.jme3.math.Matrix4f;
 import com.jme3.math.Matrix4f;
 import com.jme3.util.clone.Cloner;
 import com.jme3.util.clone.Cloner;
@@ -22,7 +23,7 @@ public class Armature implements JmeCloneable, Savable {
      * will cause it to go to the animated position.
      * will cause it to go to the animated position.
      */
      */
     private transient Matrix4f[] skinningMatrixes;
     private transient Matrix4f[] skinningMatrixes;
-
+    private Class<? extends JointModelTransform> modelTransformClass = MatrixJointModelTransform.class;
 
 
     /**
     /**
      * Serialization only
      * Serialization only
@@ -44,9 +45,14 @@ public class Armature implements JmeCloneable, Savable {
 
 
         List<Joint> rootJointList = new ArrayList<>();
         List<Joint> rootJointList = new ArrayList<>();
         for (int i = jointList.length - 1; i >= 0; i--) {
         for (int i = jointList.length - 1; i >= 0; i--) {
-            Joint b = jointList[i];
-            if (b.getParent() == null) {
-                rootJointList.add(b);
+            Joint joint = jointList[i];
+            try {
+                joint.setJointModelTransform(modelTransformClass.newInstance());
+            } catch (InstantiationException | IllegalAccessException e) {
+                throw new IllegalArgumentException(e);
+            }
+            if (joint.getParent() == null) {
+                rootJointList.add(joint);
             }
             }
         }
         }
         rootJoints = rootJointList.toArray(new Joint[rootJointList.size()]);
         rootJoints = rootJointList.toArray(new Joint[rootJointList.size()]);
@@ -75,6 +81,27 @@ public class Armature implements JmeCloneable, Savable {
         }
         }
     }
     }
 
 
+    /**
+     * Sets the JointModelTransform implementation
+     * Default is {@link MatrixJointModelTransform}
+     *
+     * @param modelTransformClass
+     * @see {@link JointModelTransform},{@link MatrixJointModelTransform},{@link SeparateJointModelTransform},
+     */
+    public void setModelTransformClass(Class<? extends JointModelTransform> modelTransformClass) {
+        this.modelTransformClass = modelTransformClass;
+        if (jointList == null) {
+            return;
+        }
+        for (Joint joint : jointList) {
+            try {
+                joint.setJointModelTransform(modelTransformClass.newInstance());
+            } catch (InstantiationException | IllegalAccessException e) {
+                throw new IllegalArgumentException(e);
+            }
+        }
+    }
+
     /**
     /**
      * returns the array of all root joints of this Armatire
      * returns the array of all root joints of this Armatire
      *
      *

+ 22 - 21
jme3-core/src/main/java/com/jme3/anim/Joint.java

@@ -1,5 +1,6 @@
 package com.jme3.anim;
 package com.jme3.anim;
 
 
+import com.jme3.anim.util.JointModelTransform;
 import com.jme3.export.*;
 import com.jme3.export.*;
 import com.jme3.material.MatParamOverride;
 import com.jme3.material.MatParamOverride;
 import com.jme3.math.*;
 import com.jme3.math.*;
@@ -41,9 +42,9 @@ public class Joint implements Savable, JmeCloneable {
 
 
     /**
     /**
      * The transform of the joint in model space. Relative to the origin of the model.
      * The transform of the joint in model space. Relative to the origin of the model.
+     * this is either a MatrixJointModelTransform or a SeparateJointModelTransform
      */
      */
-    private Transform modelTransform = new Transform();
-    private Matrix4f modelTransformMatrix = new Matrix4f();
+    private JointModelTransform jointModelTransform;
 
 
     /**
     /**
      * The matrix used to transform affected vertices position into the joint model space.
      * The matrix used to transform affected vertices position into the joint model space.
@@ -78,12 +79,7 @@ public class Joint implements Savable, JmeCloneable {
      * model transform with this bones' local transform.
      * model transform with this bones' local transform.
      */
      */
     public final void updateModelTransforms() {
     public final void updateModelTransforms() {
-        localTransform.toTransformMatrix(modelTransformMatrix);
-        if (parent != null) {
-            parent.modelTransformMatrix.mult(modelTransformMatrix, modelTransformMatrix);
-        }
-        modelTransform.fromTransformMatrix(modelTransformMatrix);
-
+        jointModelTransform.updateModelTransform(localTransform, parent);
         updateAttachNode();
         updateAttachNode();
     }
     }
 
 
@@ -102,11 +98,11 @@ public class Joint implements Savable, JmeCloneable {
              * The animated meshes are in the same coordinate system as the
              * The animated meshes are in the same coordinate system as the
              * attachments node: no further transforms are needed.
              * attachments node: no further transforms are needed.
              */
              */
-            attachedNode.setLocalTransform(modelTransform);
+            attachedNode.setLocalTransform(getModelTransform());
 
 
         } else {
         } else {
             Spatial loopSpatial = targetGeometry;
             Spatial loopSpatial = targetGeometry;
-            Transform combined = modelTransform.clone();
+            Transform combined = getModelTransform().clone();
             /*
             /*
              * Climb the scene graph applying local transforms until the
              * Climb the scene graph applying local transforms until the
              * attachments node's parent is reached.
              * attachments node's parent is reached.
@@ -131,23 +127,18 @@ public class Joint implements Savable, JmeCloneable {
      * @param outTransform
      * @param outTransform
      */
      */
     void getOffsetTransform(Matrix4f outTransform) {
     void getOffsetTransform(Matrix4f outTransform) {
-        outTransform.set(modelTransformMatrix).mult(inverseModelBindMatrix, outTransform);
+        jointModelTransform.getOffsetTransform(outTransform, inverseModelBindMatrix);
     }
     }
 
 
     protected void setBindPose() {
     protected void setBindPose() {
         //Note that the whole Armature must be updated before calling this method.
         //Note that the whole Armature must be updated before calling this method.
-        inverseModelBindMatrix.set(modelTransformMatrix);
+        getModelTransform().toTransformMatrix(inverseModelBindMatrix);
         inverseModelBindMatrix.invertLocal();
         inverseModelBindMatrix.invertLocal();
         baseLocalTransform.set(localTransform);
         baseLocalTransform.set(localTransform);
     }
     }
 
 
     protected void resetToBindPose() {
     protected void resetToBindPose() {
-        //just using modelTransformMatrix as a temp matrix here
-        modelTransformMatrix.set(inverseModelBindMatrix).invertLocal(); // model transform = model bind
-        if (parent != null) {
-            parent.modelTransformMatrix.invert().mult(modelTransformMatrix, modelTransformMatrix);
-        }
-        localTransform.fromTransformMatrix(modelTransformMatrix);
+        jointModelTransform.applyBindPose(localTransform, inverseModelBindMatrix, parent);
         updateModelTransforms();
         updateModelTransforms();
 
 
         for (Joint child : children) {
         for (Joint child : children) {
@@ -155,6 +146,14 @@ public class Joint implements Savable, JmeCloneable {
         }
         }
     }
     }
 
 
+    protected JointModelTransform getJointModelTransform() {
+        return jointModelTransform;
+    }
+
+    protected void setJointModelTransform(JointModelTransform jointModelTransform) {
+        this.jointModelTransform = jointModelTransform;
+    }
+
     public Vector3f getLocalTranslation() {
     public Vector3f getLocalTranslation() {
         return localTransform.getTranslation();
         return localTransform.getTranslation();
     }
     }
@@ -246,7 +245,7 @@ public class Joint implements Savable, JmeCloneable {
     }
     }
 
 
     public Transform getModelTransform() {
     public Transform getModelTransform() {
-        return modelTransform;
+        return jointModelTransform.getModelTransform();
     }
     }
 
 
     public Matrix4f getInverseModelBindMatrix() {
     public Matrix4f getInverseModelBindMatrix() {
@@ -270,8 +269,8 @@ public class Joint implements Savable, JmeCloneable {
         this.targetGeometry = cloner.clone(targetGeometry);
         this.targetGeometry = cloner.clone(targetGeometry);
 
 
         this.baseLocalTransform = cloner.clone(baseLocalTransform);
         this.baseLocalTransform = cloner.clone(baseLocalTransform);
-        this.localTransform = cloner.clone(baseLocalTransform);
-        this.modelTransform = cloner.clone(baseLocalTransform);
+        this.localTransform = cloner.clone(localTransform);
+        this.jointModelTransform = cloner.clone(jointModelTransform);
         this.inverseModelBindMatrix = cloner.clone(inverseModelBindMatrix);
         this.inverseModelBindMatrix = cloner.clone(inverseModelBindMatrix);
     }
     }
 
 
@@ -287,6 +286,7 @@ public class Joint implements Savable, JmeCloneable {
         baseLocalTransform = (Transform) input.readSavable("baseLocalTransforms", baseLocalTransform);
         baseLocalTransform = (Transform) input.readSavable("baseLocalTransforms", baseLocalTransform);
         localTransform.set(baseLocalTransform);
         localTransform.set(baseLocalTransform);
         inverseModelBindMatrix = (Matrix4f) input.readSavable("inverseModelBindMatrix", inverseModelBindMatrix);
         inverseModelBindMatrix = (Matrix4f) input.readSavable("inverseModelBindMatrix", inverseModelBindMatrix);
+        jointModelTransform = (JointModelTransform) input.readSavable("jointModelTransform", null);
 
 
         ArrayList<Joint> childList = input.readSavableArrayList("children", null);
         ArrayList<Joint> childList = input.readSavableArrayList("children", null);
         for (int i = childList.size() - 1; i >= 0; i--) {
         for (int i = childList.size() - 1; i >= 0; i--) {
@@ -304,6 +304,7 @@ public class Joint implements Savable, JmeCloneable {
         output.write(baseLocalTransform, "baseLocalTransform", new Transform());
         output.write(baseLocalTransform, "baseLocalTransform", new Transform());
         output.write(inverseModelBindMatrix, "inverseModelBindMatrix", new Matrix4f());
         output.write(inverseModelBindMatrix, "inverseModelBindMatrix", new Matrix4f());
         output.writeSavableArrayList(children, "children", null);
         output.writeSavableArrayList(children, "children", null);
+        output.write(jointModelTransform, "jointModelTransform", null);
     }
     }
 
 
 }
 }

+ 78 - 0
jme3-core/src/main/java/com/jme3/anim/MatrixJointModelTransform.java

@@ -0,0 +1,78 @@
+package com.jme3.anim;
+
+import com.jme3.anim.util.JointModelTransform;
+import com.jme3.export.*;
+import com.jme3.math.Matrix4f;
+import com.jme3.math.Transform;
+import com.jme3.util.clone.Cloner;
+
+import java.io.IOException;
+
+/**
+ * This JointModelTransform implementation accumulate joints transforms in a Matrix4f to properly
+ * support non uniform scaling in an armature hierarchy
+ */
+public class MatrixJointModelTransform implements JointModelTransform {
+
+    private Matrix4f modelTransformMatrix = new Matrix4f();
+    private Transform modelTransform = new Transform();
+
+    @Override
+    public void updateModelTransform(Transform localTransform, Joint parent) {
+        localTransform.toTransformMatrix(modelTransformMatrix);
+        if (parent != null) {
+            ((MatrixJointModelTransform) parent.getJointModelTransform()).getModelTransformMatrix().mult(modelTransformMatrix, modelTransformMatrix);
+        }
+        modelTransform.fromTransformMatrix(modelTransformMatrix);
+    }
+
+    public void getOffsetTransform(Matrix4f outTransform, Matrix4f inverseModelBindMatrix) {
+        outTransform.set(modelTransformMatrix).mult(inverseModelBindMatrix, outTransform);
+    }
+
+    @Override
+    public void applyBindPose(Transform localTransform, Matrix4f inverseModelBindMatrix, Joint parent) {
+        modelTransformMatrix.set(inverseModelBindMatrix).invertLocal(); // model transform = model bind
+        if (parent != null) {
+            ((MatrixJointModelTransform) parent.getJointModelTransform()).getModelTransformMatrix().invert().mult(modelTransformMatrix, modelTransformMatrix);
+        }
+        localTransform.fromTransformMatrix(modelTransformMatrix);
+    }
+
+    public Matrix4f getModelTransformMatrix() {
+        return modelTransformMatrix;
+    }
+
+    @Override
+    public Transform getModelTransform() {
+        return modelTransform;
+    }
+
+    @Override
+    public void write(JmeExporter ex) throws IOException {
+        OutputCapsule oc = ex.getCapsule(this);
+        oc.write(modelTransformMatrix, "modelTransformMatrix", new Matrix4f());
+    }
+
+    @Override
+    public void read(JmeImporter im) throws IOException {
+        InputCapsule ic = im.getCapsule(this);
+        modelTransformMatrix = (Matrix4f) ic.readSavable("modelTransformMatrix", new Matrix4f());
+        modelTransform.fromTransformMatrix(modelTransformMatrix);
+    }
+
+    @Override
+    public Object jmeClone() {
+        try {
+            MatrixJointModelTransform clone = (MatrixJointModelTransform) super.clone();
+            return clone;
+        } catch (CloneNotSupportedException ex) {
+            throw new AssertionError();
+        }
+    }
+
+    @Override
+    public void cloneFields(Cloner cloner, Object original) {
+        modelTransformMatrix = modelTransformMatrix.clone();
+    }
+}

+ 74 - 0
jme3-core/src/main/java/com/jme3/anim/SeparateJointModelTransform.java

@@ -0,0 +1,74 @@
+package com.jme3.anim;
+
+import com.jme3.anim.util.JointModelTransform;
+import com.jme3.export.*;
+import com.jme3.math.Matrix4f;
+import com.jme3.math.Transform;
+import com.jme3.util.clone.Cloner;
+
+import java.io.IOException;
+
+/**
+ * This JointModelTransform implementation accumulates model transform in a Transform class
+ * This does NOT support proper non uniform scale in the armature hierarchy.
+ * But the effect might be useful in some circumstances.
+ * Note that this is how the old animation system was working, so you might want to use this
+ * if your model has non uniform scale and was migrated from old j3o model.
+ */
+public class SeparateJointModelTransform implements JointModelTransform {
+
+    private Transform modelTransform = new Transform();
+
+    @Override
+    public void updateModelTransform(Transform localTransform, Joint parent) {
+        modelTransform.set(localTransform);
+        if (parent != null) {
+            modelTransform.combineWithParent(parent.getModelTransform());
+        }
+    }
+
+    public void getOffsetTransform(Matrix4f outTransform, Matrix4f inverseModelBindMatrix) {
+        modelTransform.toTransformMatrix(outTransform).mult(inverseModelBindMatrix, outTransform);
+    }
+
+    @Override
+    public void applyBindPose(Transform localTransform, Matrix4f inverseModelBindMatrix, Joint parent) {
+        localTransform.fromTransformMatrix(inverseModelBindMatrix);
+        localTransform.invert(); //model transform
+        if (parent != null) {
+            localTransform.combineWithParent(parent.getModelTransform().invert());
+        }
+    }
+
+    @Override
+    public Transform getModelTransform() {
+        return modelTransform;
+    }
+
+    @Override
+    public void write(JmeExporter ex) throws IOException {
+        OutputCapsule oc = ex.getCapsule(this);
+        oc.write(modelTransform, "modelTransform", new Transform());
+    }
+
+    @Override
+    public void read(JmeImporter im) throws IOException {
+        InputCapsule ic = im.getCapsule(this);
+        modelTransform = (Transform) ic.readSavable("modelTransform", new Transform());
+    }
+
+    @Override
+    public Object jmeClone() {
+        try {
+            SeparateJointModelTransform clone = (SeparateJointModelTransform) super.clone();
+            return clone;
+        } catch (CloneNotSupportedException ex) {
+            throw new AssertionError();
+        }
+    }
+
+    @Override
+    public void cloneFields(Cloner cloner, Object original) {
+        modelTransform = modelTransform.clone();
+    }
+}

+ 22 - 0
jme3-core/src/main/java/com/jme3/anim/util/JointModelTransform.java

@@ -0,0 +1,22 @@
+package com.jme3.anim.util;
+
+import com.jme3.anim.Joint;
+import com.jme3.export.Savable;
+import com.jme3.math.Matrix4f;
+import com.jme3.math.Transform;
+import com.jme3.util.clone.JmeCloneable;
+
+/**
+ * Implementations of this interface holds accumulated model transform of a Joint.
+ * Implementation might choose different accumulation strategy.
+ */
+public interface JointModelTransform extends JmeCloneable, Savable {
+
+    void updateModelTransform(Transform localTransform, Joint parent);
+
+    void getOffsetTransform(Matrix4f outTransform, Matrix4f inverseModelBindMatrix);
+
+    void applyBindPose(Transform localTransform, Matrix4f inverseModelBindMatrix, Joint parent);
+
+    Transform getModelTransform();
+}

+ 2 - 0
jme3-examples/src/main/java/jme3test/model/anim/TestArmature.java

@@ -51,6 +51,8 @@ public class TestArmature extends SimpleApplication {
         Joint[] joints = new Joint[]{root, j1, j2, j3};
         Joint[] joints = new Joint[]{root, j1, j2, j3};
 
 
         final Armature armature = new Armature(joints);
         final Armature armature = new Armature(joints);
+//        armature.setModelTransformClass(SeparateJointModelTransform.class);
+
         armature.setBindPose();
         armature.setBindPose();
 
 
         AnimClip clip = new AnimClip("anim");
         AnimClip clip = new AnimClip("anim");