瀏覽代碼

Bugfix: fix that allows to use either quaternion or euler rotation in
bone animation.

jmekaelthas 11 年之前
父節點
當前提交
3b187e9342
共有 1 個文件被更改,包括 260 次插入243 次删除
  1. 260 243
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/Ipo.java

+ 260 - 243
jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/Ipo.java

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