Adds support for different joint model transform accumulation strategy

shader-nodes-enhancement
Nehon 7 years ago committed by Rémy Bouquet
parent ce170b8b53
commit e5057ad7fa
  1. 35
      jme3-core/src/main/java/com/jme3/anim/Armature.java
  2. 43
      jme3-core/src/main/java/com/jme3/anim/Joint.java
  3. 78
      jme3-core/src/main/java/com/jme3/anim/MatrixJointModelTransform.java
  4. 74
      jme3-core/src/main/java/com/jme3/anim/SeparateJointModelTransform.java
  5. 22
      jme3-core/src/main/java/com/jme3/anim/util/JointModelTransform.java
  6. 2
      jme3-examples/src/main/java/jme3test/model/anim/TestArmature.java

@ -1,5 +1,6 @@
package com.jme3.anim;
import com.jme3.anim.util.JointModelTransform;
import com.jme3.export.*;
import com.jme3.math.Matrix4f;
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.
*/
private transient Matrix4f[] skinningMatrixes;
private Class<? extends JointModelTransform> modelTransformClass = MatrixJointModelTransform.class;
/**
* Serialization only
@ -44,9 +45,14 @@ public class Armature implements JmeCloneable, Savable {
List<Joint> rootJointList = new ArrayList<>();
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()]);
@ -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
*

@ -1,5 +1,6 @@
package com.jme3.anim;
import com.jme3.anim.util.JointModelTransform;
import com.jme3.export.*;
import com.jme3.material.MatParamOverride;
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.
* 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.
@ -78,12 +79,7 @@ public class Joint implements Savable, JmeCloneable {
* model transform with this bones' local transform.
*/
public final void updateModelTransforms() {
localTransform.toTransformMatrix(modelTransformMatrix);
if (parent != null) {
parent.modelTransformMatrix.mult(modelTransformMatrix, modelTransformMatrix);
}
modelTransform.fromTransformMatrix(modelTransformMatrix);
jointModelTransform.updateModelTransform(localTransform, parent);
updateAttachNode();
}
@ -102,11 +98,11 @@ public class Joint implements Savable, JmeCloneable {
* The animated meshes are in the same coordinate system as the
* attachments node: no further transforms are needed.
*/
attachedNode.setLocalTransform(modelTransform);
attachedNode.setLocalTransform(getModelTransform());
} else {
Spatial loopSpatial = targetGeometry;
Transform combined = modelTransform.clone();
Transform combined = getModelTransform().clone();
/*
* Climb the scene graph applying local transforms until the
* attachments node's parent is reached.
@ -131,23 +127,18 @@ public class Joint implements Savable, JmeCloneable {
* @param outTransform
*/
void getOffsetTransform(Matrix4f outTransform) {
outTransform.set(modelTransformMatrix).mult(inverseModelBindMatrix, outTransform);
jointModelTransform.getOffsetTransform(outTransform, inverseModelBindMatrix);
}
protected void setBindPose() {
//Note that the whole Armature must be updated before calling this method.
inverseModelBindMatrix.set(modelTransformMatrix);
getModelTransform().toTransformMatrix(inverseModelBindMatrix);
inverseModelBindMatrix.invertLocal();
baseLocalTransform.set(localTransform);
}
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();
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() {
return localTransform.getTranslation();
}
@ -246,7 +245,7 @@ public class Joint implements Savable, JmeCloneable {
}
public Transform getModelTransform() {
return modelTransform;
return jointModelTransform.getModelTransform();
}
public Matrix4f getInverseModelBindMatrix() {
@ -270,8 +269,8 @@ public class Joint implements Savable, JmeCloneable {
this.targetGeometry = cloner.clone(targetGeometry);
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);
}
@ -287,6 +286,7 @@ public class Joint implements Savable, JmeCloneable {
baseLocalTransform = (Transform) input.readSavable("baseLocalTransforms", baseLocalTransform);
localTransform.set(baseLocalTransform);
inverseModelBindMatrix = (Matrix4f) input.readSavable("inverseModelBindMatrix", inverseModelBindMatrix);
jointModelTransform = (JointModelTransform) input.readSavable("jointModelTransform", null);
ArrayList<Joint> childList = input.readSavableArrayList("children", null);
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(inverseModelBindMatrix, "inverseModelBindMatrix", new Matrix4f());
output.writeSavableArrayList(children, "children", null);
output.write(jointModelTransform, "jointModelTransform", null);
}
}

@ -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();
}
}

@ -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();
}
}

@ -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();
}

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

Loading…
Cancel
Save