* 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
This commit is contained in:
parent
4dd46f4c5b
commit
a99d94c263
@ -76,11 +76,19 @@ public final class AnimChannel {
|
|||||||
case Cycle:
|
case Cycle:
|
||||||
boolean sign = ((int) (t / max) % 2) != 0;
|
boolean sign = ((int) (t / max) % 2) != 0;
|
||||||
float result;
|
float result;
|
||||||
if (t < 0){
|
|
||||||
result = sign ? t % max : -(max + (t % max));
|
// if (t < 0){
|
||||||
} else {
|
// 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;
|
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;
|
return result;
|
||||||
case DontLoop:
|
case DontLoop:
|
||||||
return t > max ? max : (t < 0 ? 0 : t);
|
return t > max ? max : (t < 0 ? 0 : t);
|
||||||
@ -362,8 +370,8 @@ public final class AnimChannel {
|
|||||||
if (blendFrom != null && blendAmount != 1.0f){
|
if (blendFrom != null && blendAmount != 1.0f){
|
||||||
// The blendFrom anim is set, the actual animation
|
// The blendFrom anim is set, the actual animation
|
||||||
// playing will be set
|
// playing will be set
|
||||||
blendFrom.setTime(timeBlendFrom, 1f, control, this, vars);
|
// blendFrom.setTime(timeBlendFrom, 1f, control, this, vars);
|
||||||
// blendFrom.setTime(timeBlendFrom, 1f - blendAmount, control, this, vars);
|
blendFrom.setTime(timeBlendFrom, 1f - blendAmount, control, this, vars);
|
||||||
|
|
||||||
timeBlendFrom += tpf * speedBlendFrom;
|
timeBlendFrom += tpf * speedBlendFrom;
|
||||||
timeBlendFrom = clampWrapTime(timeBlendFrom,
|
timeBlendFrom = clampWrapTime(timeBlendFrom,
|
||||||
|
@ -85,9 +85,17 @@ public final class Bone implements Savable {
|
|||||||
private Vector3f worldPos = new Vector3f();
|
private Vector3f worldPos = new Vector3f();
|
||||||
private Quaternion worldRot = new Quaternion();
|
private Quaternion worldRot = new Quaternion();
|
||||||
private Vector3f worldScale = new Vector3f();
|
private Vector3f worldScale = new Vector3f();
|
||||||
//used for getCombinedTransform
|
|
||||||
|
// Used for getCombinedTransform
|
||||||
private Transform tmpTransform = new Transform();
|
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.
|
* 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.
|
* world transform with this bones' local transform.
|
||||||
*/
|
*/
|
||||||
public final void updateWorldVectors() {
|
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) {
|
if (parent != null) {
|
||||||
//rotation
|
//rotation
|
||||||
parent.worldRot.mult(localRot, worldRot);
|
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) {
|
void blendAnimTransforms(Vector3f translation, Quaternion rotation, Vector3f scale, float weight) {
|
||||||
if (userControl) {
|
if (userControl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TempVars vars = TempVars.get();
|
if (weight == 0) {
|
||||||
// assert vars.lock();
|
// Do not apply this transform at all.
|
||||||
|
return;
|
||||||
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 (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();
|
||||||
|
|
||||||
vars.release();
|
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);
|
tempS.interpolate(tempS2, blend);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (weight != 1f) {
|
// if (weight != 1f) {
|
||||||
target.blendAnimTransforms(tempV, tempQ, scales != null ? tempS : null, weight);
|
target.blendAnimTransforms(tempV, tempQ, scales != null ? tempS : null, weight);
|
||||||
} else {
|
// } else {
|
||||||
target.setAnimTransforms(tempV, tempQ, scales != null ? tempS : null);
|
// target.setAnimTransforms(tempV, tempQ, scales != null ? tempS : null);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user