1package com.jme3.scene.plugins.blender.constraints; 2 3import com.jme3.animation.Animation; 4import com.jme3.animation.Skeleton; 5import com.jme3.scene.plugins.blender.BlenderContext; 6import com.jme3.scene.plugins.blender.animations.CalculationBone; 7import com.jme3.scene.plugins.blender.animations.Ipo; 8import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; 9import com.jme3.scene.plugins.blender.file.Structure; 10import java.util.logging.Logger; 11 12/** 13 * This class represents 'Inverse kinematics' constraint type in blender. 14 * @author Marcin Roguski (Kaelthas) 15 */ 16/*package*/ class ConstraintInverseKinematics extends Constraint { 17 private static final Logger LOGGER = Logger.getLogger(ConstraintInverseKinematics.class.getName()); 18 private static final float IK_SOLVER_ERROR = 0.5f; 19 20 /** 21 * This constructor creates the constraint instance. 22 * 23 * @param constraintStructure 24 * the constraint's structure (bConstraint clss in blender 2.49). 25 * @param ownerOMA 26 * the old memory address of the constraint owner 27 * @param influenceIpo 28 * the ipo curve of the influence factor 29 * @param blenderContext 30 * the blender context 31 * @throws BlenderFileException 32 * this exception is thrown when the blender file is somehow 33 * corrupted 34 */ 35 public ConstraintInverseKinematics(Structure constraintStructure, 36 Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException { 37 super(constraintStructure, ownerOMA, influenceIpo, blenderContext); 38 } 39 40 @Override 41 protected void bakeConstraint() { 42// try { 43 // IK solver is only attached to bones 44// Bone ownerBone = (Bone) blenderContext.getLoadedFeature(ownerOMA, LoadedFeatureDataType.LOADED_FEATURE); 45// AnimData animData = blenderContext.getAnimData(ownerOMA); 46// if(animData == null) { 47 //TODO: to nie moxe byx null, utworzyx dane bez ruchu, w zalexnoxci czy target six rusza 48// } 49 50 //prepare a list of all parents of this bone 51// CalculationBone[] bones = this.getBonesToCalculate(skeleton, boneAnimation); 52 53 // get the target point 54// Object targetObject = this.getTarget(LoadedFeatureDataType.LOADED_FEATURE); 55// Vector3f pt = null;// Point Target 56// if (targetObject instanceof Bone) { 57// pt = ((Bone) targetObject).getModelSpacePosition(); 58// } else if (targetObject instanceof Spatial) { 59// pt = ((Spatial) targetObject).getWorldTranslation(); 60// } else if (targetObject instanceof Skeleton) { 61// Structure armatureNodeStructure = (Structure) this.getTarget(LoadedFeatureDataType.LOADED_STRUCTURE); 62// ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); 63// Transform transform = objectHelper.getTransformation(armatureNodeStructure, blenderContext); 64// pt = transform.getTranslation(); 65// } else { 66// throw new IllegalStateException( 67// "Unknown target object type! Should be Node, Bone or Skeleton and there is: " 68// + targetObject.getClass().getName()); 69// } 70 71 //fetching the owner's bone track 72// BoneTrack ownerBoneTrack = null; 73// int boneIndex = skeleton.getBoneIndex(ownerBone); 74// for (int i = 0; i < boneAnimation.getTracks().length; ++i) { 75// if (boneAnimation.getTracks()[i].getTargetBoneIndex() == boneIndex) { 76// ownerBoneTrack = boneAnimation.getTracks()[i]; 77// break; 78// } 79// } 80// int ownerBoneFramesCount = ownerBoneTrack==null ? 0 : ownerBoneTrack.getTimes().length; 81// 82// // preparing data 83// int maxIterations = ((Number) data.getFieldValue("iterations")).intValue(); 84// CalculationBone[] bones = this.getBonesToCalculate(ownerBone, skeleton, boneAnimation); 85// for (int i = 0; i < bones.length; ++i) { 86// System.out.println(Arrays.toString(bones[i].track.getTranslations())); 87// System.out.println(Arrays.toString(bones[i].track.getRotations())); 88// System.out.println("==============================="); 89// } 90// Quaternion rotation = new Quaternion(); 91// //all tracks should have the same amount of frames 92// int framesCount = bones[0].getBoneFramesCount(); 93// assert framesCount >=1; 94// for (int frame = 0; frame < framesCount; ++frame) { 95// float error = IK_SOLVER_ERROR; 96// int iteration = 0; 97// while (error >= IK_SOLVER_ERROR && iteration <= maxIterations) { 98// // rotating the bones 99// for (int i = 0; i < bones.length - 1; ++i) { 100// Vector3f pe = bones[i].getEndPoint(); 101// Vector3f pc = bones[i + 1].getWorldTranslation().clone(); 102// 103// Vector3f peSUBpc = pe.subtract(pc).normalizeLocal(); 104// Vector3f ptSUBpc = pt.subtract(pc).normalizeLocal(); 105// 106// float theta = FastMath.acos(peSUBpc.dot(ptSUBpc)); 107// Vector3f direction = peSUBpc.cross(ptSUBpc).normalizeLocal(); 108// bones[i].rotate(rotation.fromAngleAxis(theta, direction), frame); 109// } 110// error = pt.subtract(bones[0].getEndPoint()).length(); 111// ++iteration; 112// } 113// } 114// 115// for (CalculationBone bone : bones) { 116// bone.applyCalculatedTracks(); 117// } 118// 119// System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"); 120// for (int i = 0; i < bones.length; ++i) { 121// System.out.println(Arrays.toString(bones[i].track.getTranslations())); 122// System.out.println(Arrays.toString(bones[i].track.getRotations())); 123// System.out.println("==============================="); 124// } 125// } catch(BlenderFileException e) { 126// LOGGER.severe(e.getLocalizedMessage()); 127// } 128 } 129 130 /** 131 * This method returns bones used for rotation calculations. 132 * @param bone 133 * the bone to which the constraint is applied 134 * @param skeleton 135 * the skeleton owning the bone and its ancestors 136 * @param boneAnimation 137 * the bone animation data that stores the traces for the skeleton's bones 138 * @return a list of bones to imitate the bone's movement during IK solving 139 */ 140 private CalculationBone[] getBonesToCalculate(Skeleton skeleton, Animation boneAnimation) { 141// Bone ownerBone = (Bone) blenderContext.getLoadedFeature(ownerOMA, LoadedFeatureDataType.LOADED_FEATURE); 142// List<CalculationBone> bonesList = new ArrayList<CalculationBone>(); 143// do { 144// bonesList.add(new CalculationBone(ownerBone, 1)); 145// int boneIndex = skeleton.getBoneIndex(ownerBone); 146// for (int i = 0; i < boneAnimation.getTracks().length; ++i) { 147// if (((BoneTrack[])boneAnimation.getTracks())[i].getTargetBoneIndex() == boneIndex) { 148// bonesList.add(new CalculationBone(ownerBone, (BoneTrack)boneAnimation.getTracks()[i])); 149// break; 150// } 151// } 152// ownerBone = ownerBone.getParent(); 153// } while (ownerBone != null); 154// //attaching children 155// CalculationBone[] result = bonesList.toArray(new CalculationBone[bonesList.size()]); 156// for (int i = result.length - 1; i > 0; --i) { 157// result[i].attachChild(result[i - 1]); 158// } 159// return result; 160 return null; 161 } 162} 163