Adds support for different joint model transform accumulation strategy
This commit is contained in:
parent
c630ac2e59
commit
74f9a648d1
@ -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];
|
Joint joint = jointList[i];
|
||||||
if (b.getParent() == null) {
|
try {
|
||||||
rootJointList.add(b);
|
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
|
||||||
*
|
*
|
||||||
|
@ -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 JointModelTransform jointModelTransform;
|
||||||
private Matrix4f modelTransformMatrix = new Matrix4f();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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);
|
jointModelTransform.updateModelTransform(localTransform, parent);
|
||||||
if (parent != null) {
|
|
||||||
parent.modelTransformMatrix.mult(modelTransformMatrix, modelTransformMatrix);
|
|
||||||
}
|
|
||||||
modelTransform.fromTransformMatrix(modelTransformMatrix);
|
|
||||||
|
|
||||||
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
|
jointModelTransform.applyBindPose(localTransform, inverseModelBindMatrix, parent);
|
||||||
modelTransformMatrix.set(inverseModelBindMatrix).invertLocal(); // model transform = model bind
|
|
||||||
if (parent != null) {
|
|
||||||
parent.modelTransformMatrix.invert().mult(modelTransformMatrix, modelTransformMatrix);
|
|
||||||
}
|
|
||||||
localTransform.fromTransformMatrix(modelTransformMatrix);
|
|
||||||
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.localTransform = cloner.clone(localTransform);
|
||||||
this.modelTransform = cloner.clone(baseLocalTransform);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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};
|
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");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user