Feature: added support for 'Use tail' option in Inverse Kinematics

constraint.
Bugfix: fixed a bug that could cause bad computations when bones were
not directly 'in touch' with their parents.
experimental
jmekaelthas 10 years ago
parent a5699e9d82
commit 6a642ae1be
  1. 41
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java

@ -22,6 +22,7 @@ import com.jme3.scene.plugins.blender.file.Structure;
*/ */
public class ConstraintDefinitionIK extends ConstraintDefinition { public class ConstraintDefinitionIK extends ConstraintDefinition {
private static final float MIN_DISTANCE = 0.0001f; private static final float MIN_DISTANCE = 0.0001f;
private static final int FLAG_USE_TAIL = 0x01;
private static final int FLAG_POSITION = 0x20; private static final int FLAG_POSITION = 0x20;
/** The number of affected bones. Zero means that all parent bones of the current bone should take part in baking. */ /** The number of affected bones. Zero means that all parent bones of the current bone should take part in baking. */
@ -30,6 +31,8 @@ public class ConstraintDefinitionIK extends ConstraintDefinition {
private float chainLength; private float chainLength;
/** Tells if there is anything to compute at all. */ /** Tells if there is anything to compute at all. */
private boolean needToCompute = true; private boolean needToCompute = true;
/** Indicates if the tail of the bone should be used or not. */
private boolean useTail;
/** The amount of iterations of the algorithm. */ /** The amount of iterations of the algorithm. */
private int iterations; private int iterations;
@ -37,6 +40,7 @@ public class ConstraintDefinitionIK extends ConstraintDefinition {
super(constraintData, ownerOMA, blenderContext); super(constraintData, ownerOMA, blenderContext);
bonesAffected = ((Number) constraintData.getFieldValue("rootbone")).intValue(); bonesAffected = ((Number) constraintData.getFieldValue("rootbone")).intValue();
iterations = ((Number) constraintData.getFieldValue("iterations")).intValue(); iterations = ((Number) constraintData.getFieldValue("iterations")).intValue();
useTail = (flag & FLAG_USE_TAIL) != 0;
if ((flag & FLAG_POSITION) == 0) { if ((flag & FLAG_POSITION) == 0) {
needToCompute = false; needToCompute = false;
@ -49,8 +53,8 @@ public class ConstraintDefinitionIK extends ConstraintDefinition {
@Override @Override
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
if(influence == 0 || !needToCompute) { if (influence == 0 || !needToCompute) {
return ;//no need to do anything return;// no need to do anything
} }
Quaternion q = new Quaternion(); Quaternion q = new Quaternion();
Vector3f t = targetTransform.getTranslation(); Vector3f t = targetTransform.getTranslation();
@ -81,13 +85,13 @@ public class ConstraintDefinitionIK extends ConstraintDefinition {
if (angle != 0) { if (angle != 0) {
Vector3f cross = currentDir.crossLocal(target).normalizeLocal(); Vector3f cross = currentDir.crossLocal(target).normalizeLocal();
q.fromAngleAxis(angle, cross); q.fromAngleAxis(angle, cross);
if(boneContext.isLockX()) { if (boneContext.isLockX()) {
q.set(0, q.getY(), q.getZ(), q.getW()); q.set(0, q.getY(), q.getZ(), q.getW());
} }
if(boneContext.isLockY()) { if (boneContext.isLockY()) {
q.set(q.getX(), 0, q.getZ(), q.getW()); q.set(q.getX(), 0, q.getZ(), q.getW());
} }
if(boneContext.isLockZ()) { if (boneContext.isLockZ()) {
q.set(q.getX(), q.getY(), 0, q.getW()); q.set(q.getX(), q.getY(), 0, q.getW());
} }
@ -106,7 +110,7 @@ public class ConstraintDefinitionIK extends ConstraintDefinition {
Bone bone = boneContext.getBone(); Bone bone = boneContext.getBone();
Transform topBoneTransform = constraintHelper.getTransform(topBone.getArmatureObjectOMA(), topBone.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD); Transform topBoneTransform = constraintHelper.getTransform(topBone.getArmatureObjectOMA(), topBone.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD);
Transform boneWorldTransform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD); Transform boneWorldTransform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD);
Vector3f e = topBoneTransform.getTranslation().addLocal(topBoneTransform.getRotation().mult(Vector3f.UNIT_Y).multLocal(topBone.getLength()));// effector Vector3f e = topBoneTransform.getTranslation().addLocal(topBoneTransform.getRotation().mult(Vector3f.UNIT_Y).multLocal(topBone.getLength()));// effector
Vector3f j = boneWorldTransform.getTranslation(); // current join position Vector3f j = boneWorldTransform.getTranslation(); // current join position
@ -117,16 +121,16 @@ public class ConstraintDefinitionIK extends ConstraintDefinition {
Vector3f cross = currentDir.crossLocal(target).normalizeLocal(); Vector3f cross = currentDir.crossLocal(target).normalizeLocal();
q.fromAngleAxis(angle, cross); q.fromAngleAxis(angle, cross);
if(boneContext.isLockX()) { if (boneContext.isLockX()) {
q.set(0, q.getY(), q.getZ(), q.getW()); q.set(0, q.getY(), q.getZ(), q.getW());
} }
if(boneContext.isLockY()) { if (boneContext.isLockY()) {
q.set(q.getX(), 0, q.getZ(), q.getW()); q.set(q.getX(), 0, q.getZ(), q.getW());
} }
if(boneContext.isLockZ()) { if (boneContext.isLockZ()) {
q.set(q.getX(), q.getY(), 0, q.getW()); q.set(q.getX(), q.getY(), 0, q.getW());
} }
boneWorldTransform.getRotation().set(q.multLocal(boneWorldTransform.getRotation())); boneWorldTransform.getRotation().set(q.multLocal(boneWorldTransform.getRotation()));
constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD, boneWorldTransform); constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD, boneWorldTransform);
} }
@ -149,6 +153,12 @@ public class ConstraintDefinitionIK extends ConstraintDefinition {
private List<BoneContext> loadBones() { private List<BoneContext> loadBones() {
List<BoneContext> bones = new ArrayList<BoneContext>(); List<BoneContext> bones = new ArrayList<BoneContext>();
Bone bone = (Bone) this.getOwner(); Bone bone = (Bone) this.getOwner();
if (bone == null) {
return bones;
}
if (!useTail) {
bone = bone.getParent();
}
chainLength = 0; chainLength = 0;
while (bone != null) { while (bone != null) {
BoneContext boneContext = blenderContext.getBoneContext(bone); BoneContext boneContext = blenderContext.getBoneContext(bone);
@ -158,7 +168,18 @@ public class ConstraintDefinitionIK extends ConstraintDefinition {
if (bonesAffected != 0 && bones.size() >= bonesAffected) { if (bonesAffected != 0 && bones.size() >= bonesAffected) {
break; break;
} }
// need to add spaces between bones to the chain length
Transform boneWorldTransform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD);
Vector3f boneWorldTranslation = boneWorldTransform.getTranslation();
bone = bone.getParent(); bone = bone.getParent();
if (bone != null) {
boneContext = blenderContext.getBoneContext(bone);
Transform parentWorldTransform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD);
Vector3f parentWorldTranslation = parentWorldTransform.getTranslation();
chainLength += boneWorldTranslation.distance(parentWorldTranslation);
}
} }
return bones; return bones;
} }

Loading…
Cancel
Save