* Fix bug where animation loop mode "Cycle" would start at the end of the animation at each cycle causing discontinuities in the animation

* Fix bug where blending between the animations of a bone that did not have keyframes on the 2nd animation would fail and cause snapping / incorrect blending

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9400 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
Sha..rd 13 years ago
parent 4dd46f4c5b
commit a99d94c263
  1. 22
      engine/src/core/com/jme3/animation/AnimChannel.java
  2. 109
      engine/src/core/com/jme3/animation/Bone.java
  3. 8
      engine/src/core/com/jme3/animation/BoneTrack.java

@ -66,7 +66,7 @@ public final class AnimChannel {
private float blendAmount = 1f;
private float blendRate = 0;
private static float clampWrapTime(float t, float max, LoopMode loopMode){
if (t == 0) {
return 0; // prevent division by 0 errors
@ -76,11 +76,19 @@ public final class AnimChannel {
case Cycle:
boolean sign = ((int) (t / max) % 2) != 0;
float result;
if (t < 0){
result = sign ? t % max : -(max + (t % max));
} else {
// if (t < 0){
// result = sign ? t % max : -(max + (t % max));
// } else {
// NOTE: This algorithm seems stable for both high and low
// tpf so for now its a keeper.
result = sign ? -(max - (t % max)) : t % max;
}
// }
// if (result <= 0 || result >= max) {
// System.out.println("SIGN: " + sign + ", RESULT: " + result + ", T: " + t + ", M: " + max);
// }
return result;
case DontLoop:
return t > max ? max : (t < 0 ? 0 : t);
@ -362,8 +370,8 @@ public final class AnimChannel {
if (blendFrom != null && blendAmount != 1.0f){
// The blendFrom anim is set, the actual animation
// playing will be set
blendFrom.setTime(timeBlendFrom, 1f, control, this, vars);
// blendFrom.setTime(timeBlendFrom, 1f - blendAmount, control, this, vars);
// blendFrom.setTime(timeBlendFrom, 1f, control, this, vars);
blendFrom.setTime(timeBlendFrom, 1f - blendAmount, control, this, vars);
timeBlendFrom += tpf * speedBlendFrom;
timeBlendFrom = clampWrapTime(timeBlendFrom,

@ -85,8 +85,16 @@ public final class Bone implements Savable {
private Vector3f worldPos = new Vector3f();
private Quaternion worldRot = new Quaternion();
private Vector3f worldScale = new Vector3f();
//used for getCombinedTransform
// Used for getCombinedTransform
private Transform tmpTransform = new Transform();
/**
* Used to handle blending from one animation to another.
* See {@link #blendAnimTransforms(com.jme3.math.Vector3f, com.jme3.math.Quaternion, com.jme3.math.Vector3f, float)}
* on how this variable is used.
*/
private transient float currentWeightSum = -1;
/**
* Creates a new bone with the given name.
@ -323,6 +331,25 @@ public final class Bone implements Savable {
* world transform with this bones' local transform.
*/
public final void updateWorldVectors() {
if (currentWeightSum == 1f) {
currentWeightSum = -1;
} else if (currentWeightSum != -1f) {
// Apply the weight to the local transform
if (currentWeightSum == 0) {
localRot.set(initialRot);
localPos.set(initialPos);
localScale.set(initialScale);
} else {
float invWeightSum = 1f - currentWeightSum;
localRot.nlerp(initialRot, invWeightSum);
localPos.interpolate(initialPos, invWeightSum);
localScale.interpolate(initialScale, invWeightSum);
}
// Future invocations of transform blend will start over.
currentWeightSum = -1;
}
if (parent != null) {
//rotation
parent.worldRot.mult(localRot, worldRot);
@ -522,34 +549,70 @@ public final class Bone implements Savable {
}
}
/**
* Blends the given animation transform onto the bone's local transform.
* <p>
* Subsequent calls of this method stack up, with the final transformation
* of the bone computed at {@link #updateWorldVectors() } which resets
* the stack.
* <p>
* E.g. a single transform blend with weight = 0.5 followed by an
* updateWorldVectors() call will result in final transform = transform * 0.5.
* Two transform blends with weight = 0.5 each will result in the two
* transforms blended together (nlerp) with blend = 0.5.
*
* @param translation The translation to blend in
* @param rotation The rotation to blend in
* @param scale The scale to blend in
* @param weight The weight of the transform to apply. Set to 1.0 to prevent
* any other transform from being applied until updateWorldVectors().
*/
void blendAnimTransforms(Vector3f translation, Quaternion rotation, Vector3f scale, float weight) {
if (userControl) {
return;
}
TempVars vars = TempVars.get();
// assert vars.lock();
Vector3f tmpV = vars.vect1;
Vector3f tmpV2 = vars.vect2;
Quaternion tmpQ = vars.quat1;
//location
tmpV.set(initialPos).addLocal(translation);
localPos.interpolate(tmpV, weight);
//rotation
tmpQ.set(initialRot).multLocal(rotation);
localRot.nlerp(tmpQ, weight);
//scale
if (scale != null) {
tmpV2.set(initialScale).multLocal(scale);
localScale.interpolate(tmpV2, weight);
if (weight == 0) {
// Do not apply this transform at all.
return;
}
vars.release();
if (currentWeightSum == 1){
return; // More than 2 transforms are being blended
} else if (currentWeightSum == -1 || currentWeightSum == 0) {
// Set the transform fully
localPos.set(initialPos).addLocal(translation);
localRot.set(initialRot).multLocal(rotation);
if (scale != null) {
localScale.set(initialScale).multLocal(scale);
}
// Set the weight. It will be applied in updateWorldVectors().
currentWeightSum = weight;
} else {
// The weight is already set.
// Blend in the new transform.
TempVars vars = TempVars.get();
Vector3f tmpV = vars.vect1;
Vector3f tmpV2 = vars.vect2;
Quaternion tmpQ = vars.quat1;
tmpV.set(initialPos).addLocal(translation);
localPos.interpolate(tmpV, weight);
tmpQ.set(initialRot).multLocal(rotation);
localRot.nlerp(tmpQ, weight);
if (scale != null) {
tmpV2.set(initialScale).multLocal(scale);
localScale.interpolate(tmpV2, weight);
}
// Ensures no new weights will be blended in the future.
currentWeightSum = 1;
vars.release();
}
}
/**

@ -243,11 +243,11 @@ public final class BoneTrack implements Track {
tempS.interpolate(tempS2, blend);
}
if (weight != 1f) {
// if (weight != 1f) {
target.blendAnimTransforms(tempV, tempQ, scales != null ? tempS : null, weight);
} else {
target.setAnimTransforms(tempV, tempQ, scales != null ? tempS : null);
}
// } else {
// target.setAnimTransforms(tempV, tempQ, scales != null ? tempS : null);
// }
}
/**

Loading…
Cancel
Save