diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/animations/BoneContext.java b/engine/src/blender/com/jme3/scene/plugins/blender/animations/BoneContext.java index 48caa5f40..c398f7730 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/animations/BoneContext.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/animations/BoneContext.java @@ -209,6 +209,13 @@ public class BoneContext { public Skeleton getSkeleton() { return blenderContext.getSkeleton(armatureObjectOMA); } + + /** + * @return the initial bone's matrix in model space + */ + public Matrix4f getBoneMatrixInModelSpace() { + return boneMatrixInModelSpace; + } /** * Tells if the bone is of specified property defined by its flag. diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java index 68f723183..2e8505d12 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java @@ -8,7 +8,6 @@ import java.util.logging.Logger; import com.jme3.animation.Bone; import com.jme3.animation.Skeleton; -import com.jme3.math.FastMath; import com.jme3.math.Matrix4f; import com.jme3.math.Quaternion; import com.jme3.math.Transform; @@ -34,9 +33,6 @@ import com.jme3.util.TempVars; public class ConstraintHelper extends AbstractBlenderHelper { private static final Logger LOGGER = Logger.getLogger(ConstraintHelper.class.getName()); - private static final Quaternion POS_PARLOC_SPACE_QUATERNION = new Quaternion(new float[] { FastMath.HALF_PI, 0, 0 }); - private static final Quaternion NEG_PARLOC_SPACE_QUATERNION = new Quaternion(new float[] { -FastMath.HALF_PI, 0, 0 }); - /** * Helper constructor. * @@ -242,28 +238,28 @@ public class ConstraintHelper extends AbstractBlenderHelper { assert bone.getParent() != null : "CONSTRAINT_SPACE_LOCAL should be evaluated as CONSTRAINT_SPACE_POSE if the bone has no parent!"; result = new Transform(bone.getLocalPosition(), bone.getLocalRotation(), bone.getLocalScale()); break; - case CONSTRAINT_SPACE_POSE: + case CONSTRAINT_SPACE_POSE: { Matrix4f boneWorldMatrix = this.toMatrix(this.getTransform(oma, subtargetName, Space.CONSTRAINT_SPACE_WORLD), tempVars.tempMat4); Matrix4f armatureInvertedWorldMatrix = this.toMatrix(feature.getWorldTransform(), tempVars.tempMat42).invertLocal(); Matrix4f bonePoseMatrix = armatureInvertedWorldMatrix.multLocal(boneWorldMatrix); result = new Transform(bonePoseMatrix.toTranslationVector(), bonePoseMatrix.toRotationQuat(), bonePoseMatrix.toScaleVector()); break; - case CONSTRAINT_SPACE_PARLOCAL: - Matrix4f parentLocalMatrix = tempVars.tempMat4; - if (bone.getParent() != null) { - Bone parent = bone.getParent(); - this.toMatrix(parent.getLocalPosition(), parent.getLocalRotation(), parent.getLocalScale(), parentLocalMatrix); - } else { - parentLocalMatrix.loadIdentity(); + } + case CONSTRAINT_SPACE_PARLOCAL: { + Matrix4f boneWorldMatrix = this.toMatrix(this.getTransform(oma, subtargetName, Space.CONSTRAINT_SPACE_WORLD), tempVars.tempMat4); + Matrix4f armatureInvertedWorldMatrix = this.toMatrix(feature.getWorldTransform(), tempVars.tempMat42).invertLocal(); + Matrix4f bonePoseMatrix = armatureInvertedWorldMatrix.multLocal(boneWorldMatrix); + result = new Transform(bonePoseMatrix.toTranslationVector(), bonePoseMatrix.toRotationQuat(), bonePoseMatrix.toScaleVector()); + Bone parent = bone.getParent(); + if(parent != null) { + BoneContext parentContext = blenderContext.getBoneContext(parent); + Vector3f head = parent.getModelSpacePosition(); + Vector3f tail = head.add(bone.getModelSpaceRotation().mult(Vector3f.UNIT_Y.mult(parentContext.getLength()))); + result.getTranslation().subtractLocal(tail); + } - Matrix4f boneLocalMatrix = this.toMatrix(bone.getLocalPosition(), bone.getLocalRotation(), bone.getLocalScale(), tempVars.tempMat42); - Matrix4f resultMatrix = parentLocalMatrix.multLocal(boneLocalMatrix); - - Vector3f loc = resultMatrix.toTranslationVector(); - Quaternion rot = resultMatrix.toRotationQuat().normalizeLocal().multLocal(NEG_PARLOC_SPACE_QUATERNION); - Vector3f scl = resultMatrix.toScaleVector(); - result = new Transform(loc, rot, scl); break; + } default: throw new IllegalStateException("Unknown space type: " + space); } @@ -342,19 +338,27 @@ public class ConstraintHelper extends AbstractBlenderHelper { break; } case CONSTRAINT_SPACE_PARLOCAL: - Matrix4f parentLocalInverseMatrix = tempVars.tempMat4; - if (bone.getParent() != null) { - this.toMatrix(bone.getParent().getLocalPosition(), bone.getParent().getLocalRotation(), bone.getParent().getLocalScale(), parentLocalInverseMatrix); - parentLocalInverseMatrix.invertLocal(); - } else { - parentLocalInverseMatrix.loadIdentity(); + Matrix4f armatureWorldMatrix = this.toMatrix(feature.getWorldTransform(), tempVars.tempMat4); + Matrix4f boneMatrixInWorldSpace = armatureWorldMatrix.multLocal(this.toMatrix(transform, tempVars.tempMat42)); + Matrix4f invertedModelMatrix = this.toMatrix(this.getTransform(targetBoneContext.getSkeletonOwnerOma(), null, Space.CONSTRAINT_SPACE_WORLD), tempVars.tempMat42).invertLocal(); + Matrix4f boneMatrixInModelSpace = invertedModelMatrix.multLocal(boneMatrixInWorldSpace); + Bone parent = bone.getParent(); + if (parent != null) { + //first add the initial parent matrix to the bone's model matrix + BoneContext parentContext = blenderContext.getBoneContext(parent); + + Matrix4f initialParentMatrixInModelSpace = parentContext.getBoneMatrixInModelSpace(); + Matrix4f currentParentMatrixInModelSpace = this.toMatrix(parent.getModelSpacePosition(), parent.getModelSpaceRotation(), parent.getModelSpaceScale(), tempVars.tempMat4); + //the bone will now move with its parent in model space + + //now we need to subtract the difference between current parent's model matrix and its initial model matrix + boneMatrixInModelSpace = initialParentMatrixInModelSpace.mult(boneMatrixInModelSpace); + + Matrix4f diffMatrix = initialParentMatrixInModelSpace.mult(currentParentMatrixInModelSpace.invert()); + boneMatrixInModelSpace.multLocal(diffMatrix); + //now the bone will have its position in model space with initial parent's model matrix added } - Matrix4f m = this.toMatrix(transform.getTranslation(), transform.getRotation(), transform.getScale(), tempVars.tempMat42); - Matrix4f result = parentLocalInverseMatrix.multLocal(m); - Vector3f loc = result.toTranslationVector(); - Quaternion rot = result.toRotationQuat().normalizeLocal().multLocal(POS_PARLOC_SPACE_QUATERNION); - Vector3f scl = result.toScaleVector(); - bone.setBindTransforms(loc, rot, scl); + bone.setBindTransforms(boneMatrixInModelSpace.toTranslationVector(), boneMatrixInModelSpace.toRotationQuat(), boneMatrixInModelSpace.toScaleVector()); break; default: tempVars.release();