159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapackage com.jme3.scene.plugins.blender.animations; 259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.animation.Bone; 459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.animation.BoneTrack; 559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Quaternion; 659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Vector3f; 759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.Node; 859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.Spatial; 959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.Arrays; 1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/** 1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * The purpose of this class is to imitate bone's movement when calculating inverse kinematics. 1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author Marcin Roguski (Kaelthas) 1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapublic class CalculationBone extends Node { 1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private Bone bone; 1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** The bone's tracks. Will be altered at the end of calculation process. */ 1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private BoneTrack track; 1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** The starting position of the bone. */ 2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private Vector3f startTranslation; 2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** The starting rotation of the bone. */ 2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private Quaternion startRotation; 2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** The starting scale of the bone. */ 2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private Vector3f startScale; 2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private Vector3f[] translations; 2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private Quaternion[] rotations; 2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private Vector3f[] scales; 2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public CalculationBone(Bone bone, int boneFramesCount) { 3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.bone = bone; 3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.startRotation = bone.getModelSpaceRotation().clone(); 3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.startTranslation = bone.getModelSpacePosition().clone(); 3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.startScale = bone.getModelSpaceScale().clone(); 3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.reset(); 3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if(boneFramesCount > 0) { 3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.translations = new Vector3f[boneFramesCount]; 3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.rotations = new Quaternion[boneFramesCount]; 3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.scales = new Vector3f[boneFramesCount]; 3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Arrays.fill(this.translations, 0, boneFramesCount, this.startTranslation); 4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Arrays.fill(this.rotations, 0, boneFramesCount, this.startRotation); 4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Arrays.fill(this.scales, 0, boneFramesCount, this.startScale); 4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Constructor. Stores the track, starting transformation and sets the transformation to the starting positions. 4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param bone 4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the bone this class will imitate 5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param track 5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the bone's tracks 5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public CalculationBone(Bone bone, BoneTrack track) { 5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this(bone, 0); 5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.track = track; 5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.translations = track.getTranslations(); 5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.rotations = track.getRotations(); 5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.scales = track.getScales(); 5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public int getBoneFramesCount() { 6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return this.translations==null ? 0 : this.translations.length; 6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * This method returns the end point of the bone. If the bone has parent it is calculated from the start point 6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * of parent to the start point of this bone. If the bone doesn't have a parent the end location is considered 6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * to be 1 point up along Y axis (scale is applied if set to != 1.0); 6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return the end point of this bone 7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //TODO: set to Z axis if user defined it this way 7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Vector3f getEndPoint() { 7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (this.getParent() == null) { 7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return new Vector3f(0, this.getLocalScale().y, 0); 7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Node parent = this.getParent(); 7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return parent.getWorldTranslation().subtract(this.getWorldTranslation()).multLocal(this.getWorldScale()); 7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * This method resets the calculation bone to the starting position. 8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void reset() { 8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.setLocalTranslation(startTranslation); 8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.setLocalRotation(startRotation); 8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.setLocalScale(startScale); 8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta @Override 9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public int attachChild(Spatial child) { 9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (this.getChildren() != null && this.getChildren().size() > 1) { 9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IllegalStateException(this.getClass().getName() + " class instance can only have one child!"); 9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return super.attachChild(child); 9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Spatial rotate(Quaternion rot, int frame) { 9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Spatial spatial = super.rotate(rot); 10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.updateWorldTransforms(); 10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (this.getChildren() != null && this.getChildren().size() > 0) { 10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta CalculationBone child = (CalculationBone) this.getChild(0); 10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta child.updateWorldTransforms(); 10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rotations[frame].set(this.getLocalRotation()); 10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta translations[frame].set(this.getLocalTranslation()); 10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (scales != null) { 10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta scales[frame].set(this.getLocalScale()); 10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return spatial; 11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void applyCalculatedTracks() { 11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if(track != null) { 11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta track.setKeyframes(track.getTimes(), translations, rotations, scales); 11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bone.setUserControl(true); 11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bone.setUserTransforms(translations[0], rotations[0], scales[0]); 11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bone.setUserControl(false); 12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bone.updateWorldVectors(); 12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta @Override 12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public String toString() { 12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return bone.getName() + ": " + this.getLocalRotation() + " " + this.getLocalTranslation(); 12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta}