• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.jme3.scene.plugins.blender.animations;
2 
3 import com.jme3.animation.Bone;
4 import com.jme3.animation.BoneTrack;
5 import com.jme3.math.Quaternion;
6 import com.jme3.math.Vector3f;
7 import com.jme3.scene.Node;
8 import com.jme3.scene.Spatial;
9 import java.util.Arrays;
10 
11 /**
12  * The purpose of this class is to imitate bone's movement when calculating inverse kinematics.
13  * @author Marcin Roguski (Kaelthas)
14  */
15 public class CalculationBone extends Node {
16 	private Bone bone;
17 	/** The bone's tracks. Will be altered at the end of calculation process. */
18 	private BoneTrack track;
19 	/** The starting position of the bone. */
20 	private Vector3f startTranslation;
21 	/** The starting rotation of the bone. */
22 	private Quaternion startRotation;
23 	/** The starting scale of the bone. */
24 	private Vector3f startScale;
25 	private Vector3f[] translations;
26 	private Quaternion[] rotations;
27 	private Vector3f[] scales;
28 
CalculationBone(Bone bone, int boneFramesCount)29 	public CalculationBone(Bone bone, int boneFramesCount) {
30 		this.bone = bone;
31 		this.startRotation = bone.getModelSpaceRotation().clone();
32 		this.startTranslation = bone.getModelSpacePosition().clone();
33 		this.startScale = bone.getModelSpaceScale().clone();
34 		this.reset();
35 		if(boneFramesCount > 0) {
36 			this.translations = new Vector3f[boneFramesCount];
37 			this.rotations = new Quaternion[boneFramesCount];
38 			this.scales = new Vector3f[boneFramesCount];
39 
40 			Arrays.fill(this.translations, 0, boneFramesCount, this.startTranslation);
41 			Arrays.fill(this.rotations, 0, boneFramesCount, this.startRotation);
42 			Arrays.fill(this.scales, 0, boneFramesCount, this.startScale);
43 		}
44 	}
45 
46 	/**
47 	 * Constructor. Stores the track, starting transformation and sets the transformation to the starting positions.
48 	 * @param bone
49 	 *        the bone this class will imitate
50 	 * @param track
51 	 *        the bone's tracks
52 	 */
CalculationBone(Bone bone, BoneTrack track)53 	public CalculationBone(Bone bone, BoneTrack track) {
54 		this(bone, 0);
55 		this.track = track;
56 		this.translations = track.getTranslations();
57 		this.rotations = track.getRotations();
58 		this.scales = track.getScales();
59 	}
60 
getBoneFramesCount()61 	public int getBoneFramesCount() {
62 		return this.translations==null ? 0 : this.translations.length;
63 	}
64 
65 	/**
66 	 * This method returns the end point of the bone. If the bone has parent it is calculated from the start point
67 	 * of parent to the start point of this bone. If the bone doesn't have a parent the end location is considered
68 	 * to be 1 point up along Y axis (scale is applied if set to != 1.0);
69 	 * @return the end point of this bone
70 	 */
71 	//TODO: set to Z axis if user defined it this way
getEndPoint()72 	public Vector3f getEndPoint() {
73 		if (this.getParent() == null) {
74 			return new Vector3f(0, this.getLocalScale().y, 0);
75 		} else {
76 			Node parent = this.getParent();
77 			return parent.getWorldTranslation().subtract(this.getWorldTranslation()).multLocal(this.getWorldScale());
78 		}
79 	}
80 
81 	/**
82 	 * This method resets the calculation bone to the starting position.
83 	 */
reset()84 	public void reset() {
85 		this.setLocalTranslation(startTranslation);
86 		this.setLocalRotation(startRotation);
87 		this.setLocalScale(startScale);
88 	}
89 
90 	@Override
attachChild(Spatial child)91 	public int attachChild(Spatial child) {
92 		if (this.getChildren() != null && this.getChildren().size() > 1) {
93 			throw new IllegalStateException(this.getClass().getName() + " class instance can only have one child!");
94 		}
95 		return super.attachChild(child);
96 	}
97 
rotate(Quaternion rot, int frame)98 	public Spatial rotate(Quaternion rot, int frame) {
99 		Spatial spatial = super.rotate(rot);
100 		this.updateWorldTransforms();
101 		if (this.getChildren() != null && this.getChildren().size() > 0) {
102 			CalculationBone child = (CalculationBone) this.getChild(0);
103 			child.updateWorldTransforms();
104 		}
105 		rotations[frame].set(this.getLocalRotation());
106 		translations[frame].set(this.getLocalTranslation());
107 		if (scales != null) {
108 			scales[frame].set(this.getLocalScale());
109 		}
110 		return spatial;
111 	}
112 
applyCalculatedTracks()113 	public void applyCalculatedTracks() {
114 		if(track != null) {
115 			track.setKeyframes(track.getTimes(), translations, rotations, scales);
116 		} else {
117 			bone.setUserControl(true);
118 			bone.setUserTransforms(translations[0], rotations[0], scales[0]);
119 			bone.setUserControl(false);
120 			bone.updateWorldVectors();
121 		}
122 	}
123 
124 	@Override
toString()125 	public String toString() {
126 		return bone.getName() + ": " + this.getLocalRotation() + " " + this.getLocalTranslation();
127 	}
128 }