parent
539c2e65fc
commit
3b187e9342
@ -1,243 +1,260 @@ |
|||||||
package com.jme3.scene.plugins.blender.animations; |
package com.jme3.scene.plugins.blender.animations; |
||||||
|
|
||||||
import java.util.logging.Level; |
import java.util.logging.Level; |
||||||
import java.util.logging.Logger; |
import java.util.logging.Logger; |
||||||
|
|
||||||
import com.jme3.animation.BoneTrack; |
import com.jme3.animation.BoneTrack; |
||||||
import com.jme3.animation.SpatialTrack; |
import com.jme3.animation.SpatialTrack; |
||||||
import com.jme3.animation.Track; |
import com.jme3.animation.Track; |
||||||
import com.jme3.math.FastMath; |
import com.jme3.math.FastMath; |
||||||
import com.jme3.math.Quaternion; |
import com.jme3.math.Quaternion; |
||||||
import com.jme3.math.Vector3f; |
import com.jme3.math.Vector3f; |
||||||
import com.jme3.scene.plugins.blender.curves.BezierCurve; |
import com.jme3.scene.plugins.blender.curves.BezierCurve; |
||||||
|
|
||||||
/** |
/** |
||||||
* This class is used to calculate bezier curves value for the given frames. The |
* This class is used to calculate bezier curves value for the given frames. The |
||||||
* Ipo (interpolation object) consists of several b-spline curves (connected 3rd |
* Ipo (interpolation object) consists of several b-spline curves (connected 3rd |
||||||
* degree bezier curves) of a different type. |
* degree bezier curves) of a different type. |
||||||
* |
* |
||||||
* @author Marcin Roguski |
* @author Marcin Roguski |
||||||
*/ |
*/ |
||||||
public class Ipo { |
public class Ipo { |
||||||
private static final Logger LOGGER = Logger.getLogger(Ipo.class.getName()); |
private static final Logger LOGGER = Logger.getLogger(Ipo.class.getName()); |
||||||
|
|
||||||
public static final int AC_LOC_X = 1; |
public static final int AC_LOC_X = 1; |
||||||
public static final int AC_LOC_Y = 2; |
public static final int AC_LOC_Y = 2; |
||||||
public static final int AC_LOC_Z = 3; |
public static final int AC_LOC_Z = 3; |
||||||
public static final int OB_ROT_X = 7; |
public static final int OB_ROT_X = 7; |
||||||
public static final int OB_ROT_Y = 8; |
public static final int OB_ROT_Y = 8; |
||||||
public static final int OB_ROT_Z = 9; |
public static final int OB_ROT_Z = 9; |
||||||
public static final int AC_SIZE_X = 13; |
public static final int AC_SIZE_X = 13; |
||||||
public static final int AC_SIZE_Y = 14; |
public static final int AC_SIZE_Y = 14; |
||||||
public static final int AC_SIZE_Z = 15; |
public static final int AC_SIZE_Z = 15; |
||||||
public static final int AC_QUAT_W = 25; |
public static final int AC_QUAT_W = 25; |
||||||
public static final int AC_QUAT_X = 26; |
public static final int AC_QUAT_X = 26; |
||||||
public static final int AC_QUAT_Y = 27; |
public static final int AC_QUAT_Y = 27; |
||||||
public static final int AC_QUAT_Z = 28; |
public static final int AC_QUAT_Z = 28; |
||||||
|
|
||||||
/** A list of bezier curves for this interpolation object. */ |
/** A list of bezier curves for this interpolation object. */ |
||||||
private BezierCurve[] bezierCurves; |
private BezierCurve[] bezierCurves; |
||||||
/** Each ipo contains one bone track. */ |
/** Each ipo contains one bone track. */ |
||||||
private Track calculatedTrack; |
private Track calculatedTrack; |
||||||
/** This variable indicates if the Y asxis is the UP axis or not. */ |
/** This variable indicates if the Y asxis is the UP axis or not. */ |
||||||
protected boolean fixUpAxis; |
protected boolean fixUpAxis; |
||||||
/** |
/** |
||||||
* Depending on the blender version rotations are stored in degrees or |
* Depending on the blender version rotations are stored in degrees or |
||||||
* radians so we need to know the version that is used. |
* radians so we need to know the version that is used. |
||||||
*/ |
*/ |
||||||
protected final int blenderVersion; |
protected final int blenderVersion; |
||||||
|
|
||||||
/** |
/** |
||||||
* Constructor. Stores the bezier curves. |
* Constructor. Stores the bezier curves. |
||||||
* |
* |
||||||
* @param bezierCurves |
* @param bezierCurves |
||||||
* a table of bezier curves |
* a table of bezier curves |
||||||
* @param fixUpAxis |
* @param fixUpAxis |
||||||
* indicates if the Y is the up axis or not |
* indicates if the Y is the up axis or not |
||||||
* @param blenderVersion |
* @param blenderVersion |
||||||
* the blender version that is currently used |
* the blender version that is currently used |
||||||
*/ |
*/ |
||||||
public Ipo(BezierCurve[] bezierCurves, boolean fixUpAxis, int blenderVersion) { |
public Ipo(BezierCurve[] bezierCurves, boolean fixUpAxis, int blenderVersion) { |
||||||
this.bezierCurves = bezierCurves; |
this.bezierCurves = bezierCurves; |
||||||
this.fixUpAxis = fixUpAxis; |
this.fixUpAxis = fixUpAxis; |
||||||
this.blenderVersion = blenderVersion; |
this.blenderVersion = blenderVersion; |
||||||
} |
} |
||||||
|
|
||||||
/** |
/** |
||||||
* This method calculates the ipo value for the first curve. |
* This method calculates the ipo value for the first curve. |
||||||
* |
* |
||||||
* @param frame |
* @param frame |
||||||
* the frame for which the value is calculated |
* the frame for which the value is calculated |
||||||
* @return calculated ipo value |
* @return calculated ipo value |
||||||
*/ |
*/ |
||||||
public float calculateValue(int frame) { |
public float calculateValue(int frame) { |
||||||
return this.calculateValue(frame, 0); |
return this.calculateValue(frame, 0); |
||||||
} |
} |
||||||
|
|
||||||
/** |
/** |
||||||
* This method calculates the ipo value for the curve of the specified |
* This method calculates the ipo value for the curve of the specified |
||||||
* index. Make sure you do not exceed the curves amount. Alway chech the |
* index. Make sure you do not exceed the curves amount. Alway chech the |
||||||
* amount of curves before calling this method. |
* amount of curves before calling this method. |
||||||
* |
* |
||||||
* @param frame |
* @param frame |
||||||
* the frame for which the value is calculated |
* the frame for which the value is calculated |
||||||
* @param curveIndex |
* @param curveIndex |
||||||
* the index of the curve |
* the index of the curve |
||||||
* @return calculated ipo value |
* @return calculated ipo value |
||||||
*/ |
*/ |
||||||
public float calculateValue(int frame, int curveIndex) { |
public float calculateValue(int frame, int curveIndex) { |
||||||
return bezierCurves[curveIndex].evaluate(frame, BezierCurve.Y_VALUE); |
return bezierCurves[curveIndex].evaluate(frame, BezierCurve.Y_VALUE); |
||||||
} |
} |
||||||
|
|
||||||
/** |
/** |
||||||
* This method returns the frame where last bezier triple center point of |
* This method returns the frame where last bezier triple center point of |
||||||
* the specified bezier curve is located. |
* the specified bezier curve is located. |
||||||
* |
* |
||||||
* @return the frame number of the last defined bezier triple point for the |
* @return the frame number of the last defined bezier triple point for the |
||||||
* specified ipo |
* specified ipo |
||||||
*/ |
*/ |
||||||
public int getLastFrame() { |
public int getLastFrame() { |
||||||
int result = 1; |
int result = 1; |
||||||
for (int i = 0; i < bezierCurves.length; ++i) { |
for (int i = 0; i < bezierCurves.length; ++i) { |
||||||
int tempResult = bezierCurves[i].getLastFrame(); |
int tempResult = bezierCurves[i].getLastFrame(); |
||||||
if (tempResult > result) { |
if (tempResult > result) { |
||||||
result = tempResult; |
result = tempResult; |
||||||
} |
} |
||||||
} |
} |
||||||
return result; |
return result; |
||||||
} |
} |
||||||
|
|
||||||
/** |
/** |
||||||
* This method calculates the value of the curves as a bone track between |
* This method calculates the value of the curves as a bone track between |
||||||
* the specified frames. |
* the specified frames. |
||||||
* |
* |
||||||
* @param targetIndex |
* @param targetIndex |
||||||
* the index of the target for which the method calculates the |
* the index of the target for which the method calculates the |
||||||
* tracks IMPORTANT! Aet to -1 (or any negative number) if you |
* tracks IMPORTANT! Aet to -1 (or any negative number) if you |
||||||
* want to load spatial animation. |
* want to load spatial animation. |
||||||
* @param localTranslation |
* @param localTranslation |
||||||
* the local translation of the object/bone that will be animated by |
* the local translation of the object/bone that will be animated by |
||||||
* the track |
* the track |
||||||
* @param localRotation |
* @param localRotation |
||||||
* the local rotation of the object/bone that will be animated by |
* the local rotation of the object/bone that will be animated by |
||||||
* the track |
* the track |
||||||
* @param localScale |
* @param localScale |
||||||
* the local scale of the object/bone that will be animated by |
* the local scale of the object/bone that will be animated by |
||||||
* the track |
* the track |
||||||
* @param startFrame |
* @param startFrame |
||||||
* the first frame of tracks (inclusive) |
* the first frame of tracks (inclusive) |
||||||
* @param stopFrame |
* @param stopFrame |
||||||
* the last frame of the tracks (inclusive) |
* the last frame of the tracks (inclusive) |
||||||
* @param fps |
* @param fps |
||||||
* frame rate (frames per second) |
* frame rate (frames per second) |
||||||
* @param spatialTrack |
* @param spatialTrack |
||||||
* this flag indicates if the track belongs to a spatial or to a |
* this flag indicates if the track belongs to a spatial or to a |
||||||
* bone; the difference is important because it appears that bones |
* bone; the difference is important because it appears that bones |
||||||
* in blender have the same type of coordinate system (Y as UP) |
* in blender have the same type of coordinate system (Y as UP) |
||||||
* as jme while other features have different one (Z is UP) |
* as jme while other features have different one (Z is UP) |
||||||
* @return bone track for the specified bone |
* @return bone track for the specified bone |
||||||
*/ |
*/ |
||||||
public Track calculateTrack(int targetIndex, Vector3f localTranslation, Quaternion localRotation, Vector3f localScale, int startFrame, int stopFrame, int fps, boolean spatialTrack) { |
public Track calculateTrack(int targetIndex, Vector3f localTranslation, Quaternion localRotation, Vector3f localScale, int startFrame, int stopFrame, int fps, boolean spatialTrack) { |
||||||
if (calculatedTrack == null) { |
if (calculatedTrack == null) { |
||||||
// preparing data for track
|
// preparing data for track
|
||||||
int framesAmount = stopFrame - startFrame; |
int framesAmount = stopFrame - startFrame; |
||||||
float timeBetweenFrames = 1.0f / fps; |
float timeBetweenFrames = 1.0f / fps; |
||||||
|
|
||||||
float[] times = new float[framesAmount + 1]; |
float[] times = new float[framesAmount + 1]; |
||||||
Vector3f[] translations = new Vector3f[framesAmount + 1]; |
Vector3f[] translations = new Vector3f[framesAmount + 1]; |
||||||
float[] translation = new float[] { localTranslation.x, localTranslation.y, localTranslation.z }; |
float[] translation = new float[] { localTranslation.x, localTranslation.y, localTranslation.z }; |
||||||
Quaternion[] rotations = new Quaternion[framesAmount + 1]; |
Quaternion[] rotations = new Quaternion[framesAmount + 1]; |
||||||
float[] quaternionRotation = new float[] { localRotation.getX(), localRotation.getY(), localRotation.getZ(), localRotation.getW(), }; |
float[] quaternionRotation = new float[] { localRotation.getX(), localRotation.getY(), localRotation.getZ(), localRotation.getW(), }; |
||||||
float[] objectRotation = localRotation.toAngles(null); |
float[] eulerRotation = localRotation.toAngles(null); |
||||||
Vector3f[] scales = new Vector3f[framesAmount + 1]; |
Vector3f[] scales = new Vector3f[framesAmount + 1]; |
||||||
float[] scale = new float[] { localScale.x, localScale.y, localScale.z }; |
float[] scale = new float[] { localScale.x, localScale.y, localScale.z }; |
||||||
float degreeToRadiansFactor = 1; |
float degreeToRadiansFactor = 1; |
||||||
if (blenderVersion < 250) {// in blender earlier than 2.50 the values are stored in degrees
|
if (blenderVersion < 250) {// in blender earlier than 2.50 the values are stored in degrees
|
||||||
degreeToRadiansFactor *= FastMath.DEG_TO_RAD * 10;// the values in blender are divided by 10, so we need to mult it here
|
degreeToRadiansFactor *= FastMath.DEG_TO_RAD * 10;// the values in blender are divided by 10, so we need to mult it here
|
||||||
} |
} |
||||||
int yIndex = 1, zIndex = 2; |
int yIndex = 1, zIndex = 2; |
||||||
boolean swapAxes = spatialTrack && fixUpAxis; |
boolean swapAxes = spatialTrack && fixUpAxis; |
||||||
if (swapAxes) { |
if (swapAxes) { |
||||||
yIndex = 2; |
yIndex = 2; |
||||||
zIndex = 1; |
zIndex = 1; |
||||||
} |
} |
||||||
|
boolean eulerRotationUsed = false, queternionRotationUsed = false; |
||||||
// calculating track data
|
|
||||||
for (int frame = startFrame; frame <= stopFrame; ++frame) { |
// calculating track data
|
||||||
int index = frame - startFrame; |
for (int frame = startFrame; frame <= stopFrame; ++frame) { |
||||||
times[index] = index * timeBetweenFrames;// start + (frame - 1) * timeBetweenFrames;
|
int index = frame - startFrame; |
||||||
for (int j = 0; j < bezierCurves.length; ++j) { |
times[index] = index * timeBetweenFrames;// start + (frame - 1) * timeBetweenFrames;
|
||||||
double value = bezierCurves[j].evaluate(frame, BezierCurve.Y_VALUE); |
for (int j = 0; j < bezierCurves.length; ++j) { |
||||||
switch (bezierCurves[j].getType()) { |
double value = bezierCurves[j].evaluate(frame, BezierCurve.Y_VALUE); |
||||||
// LOCATION
|
switch (bezierCurves[j].getType()) { |
||||||
case AC_LOC_X: |
// LOCATION
|
||||||
translation[0] = (float) value; |
case AC_LOC_X: |
||||||
break; |
translation[0] = (float) value; |
||||||
case AC_LOC_Y: |
break; |
||||||
if (swapAxes && value != 0) { |
case AC_LOC_Y: |
||||||
value = -value; |
if (swapAxes && value != 0) { |
||||||
} |
value = -value; |
||||||
translation[yIndex] = (float) value; |
} |
||||||
break; |
translation[yIndex] = (float) value; |
||||||
case AC_LOC_Z: |
break; |
||||||
translation[zIndex] = (float) value; |
case AC_LOC_Z: |
||||||
break; |
translation[zIndex] = (float) value; |
||||||
|
break; |
||||||
// ROTATION (used with object animation)
|
|
||||||
case OB_ROT_X: |
// EULER ROTATION
|
||||||
objectRotation[0] = (float) value * degreeToRadiansFactor; |
case OB_ROT_X: |
||||||
break; |
eulerRotationUsed = true; |
||||||
case OB_ROT_Y: |
eulerRotation[0] = (float) value * degreeToRadiansFactor; |
||||||
if (swapAxes && value != 0) { |
break; |
||||||
value = -value; |
case OB_ROT_Y: |
||||||
} |
eulerRotationUsed = true; |
||||||
objectRotation[yIndex] = (float) value * degreeToRadiansFactor; |
if (swapAxes && value != 0) { |
||||||
break; |
value = -value; |
||||||
case OB_ROT_Z: |
} |
||||||
objectRotation[zIndex] = (float) value * degreeToRadiansFactor; |
eulerRotation[yIndex] = (float) value * degreeToRadiansFactor; |
||||||
break; |
break; |
||||||
|
case OB_ROT_Z: |
||||||
// SIZE
|
eulerRotationUsed = true; |
||||||
case AC_SIZE_X: |
eulerRotation[zIndex] = (float) value * degreeToRadiansFactor; |
||||||
scale[0] = (float) value; |
break; |
||||||
break; |
|
||||||
case AC_SIZE_Y: |
// SIZE
|
||||||
scale[yIndex] = (float) value; |
case AC_SIZE_X: |
||||||
break; |
scale[0] = (float) value; |
||||||
case AC_SIZE_Z: |
break; |
||||||
scale[zIndex] = (float) value; |
case AC_SIZE_Y: |
||||||
break; |
scale[yIndex] = (float) value; |
||||||
|
break; |
||||||
// QUATERNION ROTATION (used with bone animation)
|
case AC_SIZE_Z: |
||||||
case AC_QUAT_W: |
scale[zIndex] = (float) value; |
||||||
quaternionRotation[3] = (float) value; |
break; |
||||||
break; |
|
||||||
case AC_QUAT_X: |
// QUATERNION ROTATION (used with bone animation)
|
||||||
quaternionRotation[0] = (float) value; |
case AC_QUAT_W: |
||||||
break; |
queternionRotationUsed = true; |
||||||
case AC_QUAT_Y: |
quaternionRotation[3] = (float) value; |
||||||
if (swapAxes && value != 0) { |
break; |
||||||
value = -value; |
case AC_QUAT_X: |
||||||
} |
queternionRotationUsed = true; |
||||||
quaternionRotation[yIndex] = (float) value; |
quaternionRotation[0] = (float) value; |
||||||
break; |
break; |
||||||
case AC_QUAT_Z: |
case AC_QUAT_Y: |
||||||
quaternionRotation[zIndex] = (float) value; |
queternionRotationUsed = true; |
||||||
break; |
if (swapAxes && value != 0) { |
||||||
default: |
value = -value; |
||||||
LOGGER.log(Level.WARNING, "Unknown ipo curve type: {0}.", bezierCurves[j].getType()); |
} |
||||||
} |
quaternionRotation[yIndex] = (float) value; |
||||||
} |
break; |
||||||
translations[index] = localRotation.multLocal(new Vector3f(translation[0], translation[1], translation[2])); |
case AC_QUAT_Z: |
||||||
rotations[index] = spatialTrack ? new Quaternion().fromAngles(objectRotation) : new Quaternion(quaternionRotation[0], quaternionRotation[1], quaternionRotation[2], quaternionRotation[3]); |
quaternionRotation[zIndex] = (float) value; |
||||||
scales[index] = new Vector3f(scale[0], scale[1], scale[2]); |
break; |
||||||
} |
default: |
||||||
if (spatialTrack) { |
LOGGER.log(Level.WARNING, "Unknown ipo curve type: {0}.", bezierCurves[j].getType()); |
||||||
calculatedTrack = new SpatialTrack(times, translations, rotations, scales); |
} |
||||||
} else { |
} |
||||||
calculatedTrack = new BoneTrack(targetIndex, times, translations, rotations, scales); |
translations[index] = localRotation.multLocal(new Vector3f(translation[0], translation[1], translation[2])); |
||||||
} |
if(queternionRotationUsed) { |
||||||
} |
rotations[index] = new Quaternion(quaternionRotation[0], quaternionRotation[1], quaternionRotation[2], quaternionRotation[3]); |
||||||
return calculatedTrack; |
} else { |
||||||
} |
rotations[index] = new Quaternion().fromAngles(eulerRotation); |
||||||
} |
} |
||||||
|
|
||||||
|
scales[index] = new Vector3f(scale[0], scale[1], scale[2]); |
||||||
|
} |
||||||
|
if (spatialTrack) { |
||||||
|
calculatedTrack = new SpatialTrack(times, translations, rotations, scales); |
||||||
|
} else { |
||||||
|
calculatedTrack = new BoneTrack(targetIndex, times, translations, rotations, scales); |
||||||
|
} |
||||||
|
|
||||||
|
if(queternionRotationUsed && eulerRotationUsed) { |
||||||
|
LOGGER.warning("Animation uses both euler and quaternion tracks for rotations. Quaternion rotation is applied. Make sure that this is what you wanted!"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return calculatedTrack; |
||||||
|
} |
||||||
|
} |
||||||
|
Loading…
Reference in new issue