Adds support for different joint model transform accumulation strategy
This commit is contained in:
parent
c630ac2e59
commit
74f9a648d1
jme3-core/src/main/java/com/jme3/anim
jme3-examples/src/main/java/jme3test/model/anim
@ -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…
x
Reference in New Issue
Block a user