Bugfix: (hopefully) final fixes to armature applying to models without applied transformations (+ removing unused pieces of code)

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10529 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
Kae..pl 12 years ago
parent e282db0f7f
commit 4f104e4200
  1. 8
      engine/src/blender/com/jme3/scene/plugins/blender/animations/ArmatureHelper.java
  2. 64
      engine/src/blender/com/jme3/scene/plugins/blender/animations/BoneContext.java
  3. 22
      engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java
  4. 25
      engine/src/blender/com/jme3/scene/plugins/blender/objects/ObjectHelper.java

@ -85,17 +85,15 @@ public class ArmatureHelper extends AbstractBlenderHelper {
* the parent bone * the parent bone
* @param result * @param result
* the list where the newly created bone will be added * the list where the newly created bone will be added
* @param bonesPoseChannels
* a map of bones poses channels
* @param blenderContext * @param blenderContext
* the blender context * the blender context
* @throws BlenderFileException * @throws BlenderFileException
* an exception is thrown when there is problem with the blender * an exception is thrown when there is problem with the blender
* file * file
*/ */
public void buildBones(Long armatureObjectOMA, Structure boneStructure, Bone parent, List<Bone> result, Matrix4f arbt, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException { public void buildBones(Long armatureObjectOMA, Structure boneStructure, Bone parent, List<Bone> result, Matrix4f objectToArmatureTransformation, BlenderContext blenderContext) throws BlenderFileException {
BoneContext bc = new BoneContext(armatureObjectOMA, boneStructure, arbt, bonesPoseChannels, blenderContext); BoneContext bc = new BoneContext(armatureObjectOMA, boneStructure, blenderContext);
bc.buildBone(result, bonesOMAs, blenderContext); bc.buildBone(result, bonesOMAs, objectToArmatureTransformation, blenderContext);
} }
/** /**

@ -37,8 +37,6 @@ public class BoneContext {
private Matrix4f restMatrix; private Matrix4f restMatrix;
/** Bone's total inverse transformation. */ /** Bone's total inverse transformation. */
private Matrix4f inverseTotalTransformation; private Matrix4f inverseTotalTransformation;
/** Bone's parent inverse matrix. */
private Matrix4f inverseParentMatrix;
/** The length of the bone. */ /** The length of the bone. */
private float length; private float length;
@ -49,18 +47,14 @@ public class BoneContext {
* the OMA of the bone's armature object * the OMA of the bone's armature object
* @param boneStructure * @param boneStructure
* the bone's structure * the bone's structure
* @param objectToArmatureMatrix
* object-to-armature transformation matrix
* @param bonesPoseChannels
* a map of pose channels for each bone OMA
* @param blenderContext * @param blenderContext
* the blender context * the blender context
* @throws BlenderFileException * @throws BlenderFileException
* an exception is thrown when problem with blender data reading * an exception is thrown when problem with blender data reading
* occurs * occurs
*/ */
public BoneContext(Long armatureObjectOMA, Structure boneStructure, Matrix4f objectToArmatureMatrix, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException { public BoneContext(Long armatureObjectOMA, Structure boneStructure, BlenderContext blenderContext) throws BlenderFileException {
this(boneStructure, armatureObjectOMA, null, objectToArmatureMatrix, bonesPoseChannels, blenderContext); this(boneStructure, armatureObjectOMA, null, blenderContext);
} }
/** /**
@ -72,17 +66,13 @@ public class BoneContext {
* the OMA of the bone's armature object * the OMA of the bone's armature object
* @param parent * @param parent
* bone's parent (null if the bone is the root bone) * bone's parent (null if the bone is the root bone)
* @param objectToArmatureMatrix
* object-to-armature transformation matrix
* @param bonesPoseChannels
* a map of pose channels for each bone OMA
* @param blenderContext * @param blenderContext
* the blender context * the blender context
* @throws BlenderFileException * @throws BlenderFileException
* an exception is thrown when problem with blender data reading * an exception is thrown when problem with blender data reading
* occurs * occurs
*/ */
private BoneContext(Structure boneStructure, Long armatureObjectOMA, BoneContext parent, Matrix4f objectToArmatureMatrix, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException { private BoneContext(Structure boneStructure, Long armatureObjectOMA, BoneContext parent, BlenderContext blenderContext) throws BlenderFileException {
this.parent = parent; this.parent = parent;
this.boneStructure = boneStructure; this.boneStructure = boneStructure;
this.armatureObjectOMA = armatureObjectOMA; this.armatureObjectOMA = armatureObjectOMA;
@ -91,33 +81,22 @@ public class BoneContext {
ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
armatureMatrix = objectHelper.getMatrix(boneStructure, "arm_mat", blenderContext.getBlenderKey().isFixUpAxis()); armatureMatrix = objectHelper.getMatrix(boneStructure, "arm_mat", blenderContext.getBlenderKey().isFixUpAxis());
this.computeRestMatrix(objectToArmatureMatrix); //compute the bone's rest matrix
restMatrix = armatureMatrix.clone();
inverseTotalTransformation = restMatrix.invert();
if(parent != null) {
restMatrix = parent.inverseTotalTransformation.mult(restMatrix);
}
//create the children
List<Structure> childbase = ((Structure) boneStructure.getFieldValue("childbase")).evaluateListBase(blenderContext); List<Structure> childbase = ((Structure) boneStructure.getFieldValue("childbase")).evaluateListBase(blenderContext);
for (Structure child : childbase) { for (Structure child : childbase) {
this.children.add(new BoneContext(child, armatureObjectOMA, this, objectToArmatureMatrix, bonesPoseChannels, blenderContext)); this.children.add(new BoneContext(child, armatureObjectOMA, this, blenderContext));
} }
blenderContext.setBoneContext(boneStructure.getOldMemoryAddress(), this); blenderContext.setBoneContext(boneStructure.getOldMemoryAddress(), this);
} }
/**
* This method computes the rest matrix for the bone.
*
* @param objectToArmatureMatrix
* object-to-armature transformation matrix
*/
private void computeRestMatrix(Matrix4f objectToArmatureMatrix) {
if (parent != null) {
inverseParentMatrix = parent.inverseTotalTransformation.clone();
} else {
inverseParentMatrix = objectToArmatureMatrix.clone();
}
restMatrix = armatureMatrix.clone();
inverseTotalTransformation = restMatrix.invert();
restMatrix = inverseParentMatrix.mult(restMatrix);
}
/** /**
* This method builds the bone. It recursively builds the bone's children. * This method builds the bone. It recursively builds the bone's children.
@ -126,27 +105,34 @@ public class BoneContext {
* a list of bones where the newly created bone will be added * a list of bones where the newly created bone will be added
* @param boneOMAs * @param boneOMAs
* the map between bone and its old memory address * the map between bone and its old memory address
* @param objectToArmatureMatrix
* object to armature transformation matrix
* @param blenderContext * @param blenderContext
* the blender context * the blender context
* @return newly created bone * @return newly created bone
*/ */
public Bone buildBone(List<Bone> bones, Map<Bone, Long> boneOMAs, BlenderContext blenderContext) { public Bone buildBone(List<Bone> bones, Map<Bone, Long> boneOMAs, Matrix4f objectToArmatureMatrix, BlenderContext blenderContext) {
Long boneOMA = boneStructure.getOldMemoryAddress(); Long boneOMA = boneStructure.getOldMemoryAddress();
bone = new Bone(boneName); bone = new Bone(boneName);
bones.add(bone); bones.add(bone);
boneOMAs.put(bone, boneOMA); boneOMAs.put(bone, boneOMA);
blenderContext.addLoadedFeatures(boneOMA, boneName, boneStructure, bone); blenderContext.addLoadedFeatures(boneOMA, boneName, boneStructure, bone);
Matrix4f pose = this.restMatrix.clone();
ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
Vector3f poseLocation = pose.toTranslationVector(); Vector3f poseLocation = restMatrix.toTranslationVector();
Quaternion rotation = pose.toRotationQuat(); Quaternion rotation = restMatrix.toRotationQuat().normalizeLocal();
Vector3f scale = objectHelper.getScale(pose); Vector3f scale = objectHelper.getScale(restMatrix);
if(parent == null) {
Quaternion rotationQuaternion = objectToArmatureMatrix.toRotationQuat().normalizeLocal();
scale.multLocal(objectHelper.getScale(objectToArmatureMatrix));
rotationQuaternion.multLocal(poseLocation.addLocal(objectToArmatureMatrix.toTranslationVector()));
rotation.multLocal(rotationQuaternion);
}
bone.setBindTransforms(poseLocation, rotation, scale); bone.setBindTransforms(poseLocation, rotation, scale);
for (BoneContext child : children) { for (BoneContext child : children) {
bone.addChild(child.buildBone(bones, boneOMAs, blenderContext)); bone.addChild(child.buildBone(bones, boneOMAs, objectToArmatureMatrix, blenderContext));
} }
return bone; return bone;

@ -17,9 +17,7 @@ import com.jme3.animation.Bone;
import com.jme3.animation.BoneTrack; import com.jme3.animation.BoneTrack;
import com.jme3.animation.Skeleton; import com.jme3.animation.Skeleton;
import com.jme3.animation.SkeletonControl; import com.jme3.animation.SkeletonControl;
import com.jme3.math.Matrix3f;
import com.jme3.math.Matrix4f; import com.jme3.math.Matrix4f;
import com.jme3.math.Quaternion;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh; import com.jme3.scene.Mesh;
import com.jme3.scene.Node; import com.jme3.scene.Node;
@ -87,32 +85,16 @@ import com.jme3.util.BufferUtils;
// load skeleton // load skeleton
Structure armatureStructure = ((Pointer) armatureObject.getFieldValue("data")).fetchData(blenderContext.getInputStream()).get(0); Structure armatureStructure = ((Pointer) armatureObject.getFieldValue("data")).fetchData(blenderContext.getInputStream()).get(0);
Structure pose = ((Pointer) armatureObject.getFieldValue("pose")).fetchData(blenderContext.getInputStream()).get(0);
List<Structure> chanbase = ((Structure) pose.getFieldValue("chanbase")).evaluateListBase(blenderContext);
Map<Long, Structure> bonesPoseChannels = new HashMap<Long, Structure>(chanbase.size());
for (Structure poseChannel : chanbase) {
Pointer pBone = (Pointer) poseChannel.getFieldValue("bone");
bonesPoseChannels.put(pBone.getOldMemoryAddress(), poseChannel);
}
Matrix4f objectToArmatureTransformation = Matrix4f.IDENTITY;
ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
if(objectHelper.isLineage(armatureObject, objectStructure, blenderContext)) {
boolean fixUpAxis = blenderContext.getBlenderKey().isFixUpAxis(); boolean fixUpAxis = blenderContext.getBlenderKey().isFixUpAxis();
Matrix4f armatureObjectMatrix = objectHelper.getMatrix(armatureObject, "obmat", fixUpAxis); Matrix4f armatureObjectMatrix = objectHelper.getMatrix(armatureObject, "obmat", fixUpAxis);
Matrix4f inverseMeshObjectMatrix = objectHelper.getMatrix(objectStructure, "imat", fixUpAxis); Matrix4f inverseMeshObjectMatrix = objectHelper.getMatrix(objectStructure, "imat", fixUpAxis);
objectToArmatureTransformation = armatureObjectMatrix.multLocal(inverseMeshObjectMatrix); Matrix4f objectToArmatureTransformation = armatureObjectMatrix.multLocal(inverseMeshObjectMatrix);
Matrix3f rot = objectToArmatureTransformation.toRotationMatrix();
objectToArmatureTransformation = new Matrix4f();
objectToArmatureTransformation.setRotationQuaternion(new Quaternion().fromRotationMatrix(rot));
}
List<Structure> bonebase = ((Structure) armatureStructure.getFieldValue("bonebase")).evaluateListBase(blenderContext); List<Structure> bonebase = ((Structure) armatureStructure.getFieldValue("bonebase")).evaluateListBase(blenderContext);
List<Bone> bonesList = new ArrayList<Bone>(); List<Bone> bonesList = new ArrayList<Bone>();
for (int i = 0; i < bonebase.size(); ++i) { for (int i = 0; i < bonebase.size(); ++i) {
armatureHelper.buildBones(armatureObject.getOldMemoryAddress(), bonebase.get(i), null, bonesList, objectToArmatureTransformation, bonesPoseChannels, blenderContext); armatureHelper.buildBones(armatureObject.getOldMemoryAddress(), bonebase.get(i), null, bonesList, objectToArmatureTransformation, blenderContext);
} }
bonesList.add(0, new Bone("")); bonesList.add(0, new Bone(""));
Bone[] bones = bonesList.toArray(new Bone[bonesList.size()]); Bone[] bones = bonesList.toArray(new Bone[bonesList.size()]);

@ -251,31 +251,6 @@ public class ObjectHelper extends AbstractBlenderHelper {
return result; return result;
} }
/**
* Method tells if the structure1 is a lineage of structure2.
*
* @param structure1
* the first structure
* @param structure2
* the second structure
* @return <b>true</b> if the first structure is a lineage of the second
* structure and <b>false</b> otherwise
* @throws BlenderFileException
* thrown when problems with reading the blend file occur
*/
public boolean isLineage(Structure structure1, Structure structure2, BlenderContext blenderContext) throws BlenderFileException {
Pointer pParent = (Pointer) structure2.getFieldValue("parent");
while (pParent.isNotNull()) {
long oma = pParent.getOldMemoryAddress();
if (structure1.getOldMemoryAddress().longValue() == oma) {
return true;
}
structure2 = blenderContext.getFileBlock(oma).getStructure(blenderContext);
pParent = (Pointer) structure2.getFieldValue("parent");
}
return false;
}
/** /**
* This method calculates local transformation for the object. Parentage is taken under consideration. * This method calculates local transformation for the object. Parentage is taken under consideration.
* @param objectStructure * @param objectStructure

Loading…
Cancel
Save