Blender IPO animations enhancement

Hi all

I have a small but (at least for me) a useful enhancement. In blender simple key-frame animations can record location, rotation and scale for each axis separately and the user is free to record key-frames for certain axis only. The allows animations to be conveniently reused on multiple objects, if e.g. they move all along the x axis but have different y&z values.
However, the JME blender import currently initializes location, rotation and scale with a zero Vector3f / identity Quaternion, thus the position in the SpatialTrack will be incorrect.
To correct this and make animations behave in JME as they do in Blender I’ve created a patch for the Ipo class which initializes location, rotation & scale with the object’s transform instead of using zero values.

@Kaelthas
I’ve tested it for animations but not bones and I’d be glad if you could review this and push it to the core, because I think it would be nice if animations behave in JME as they do in Blender :wink:

Cheers!

This is the patch:

[java]
From b8920c46f9e7c69c0725d6e8601400557b71e9e5 Mon Sep 17 00:00:00 2001
Date: Wed, 1 Jan 2014 16:55:39 +0100
Subject: [PATCH] Use the object’s local transform for the initial IPO track
values to achieve the same behaviour as in Blender


…/plugins/blender/animations/ArmatureHelper.java | 4 ±
…/jme3/scene/plugins/blender/animations/Ipo.java | 45 ++++++++++++++++±----
…/plugins/blender/animations/1f252995fdd6493ba6a24b192d89d1f95b38937eIpoHelper.java | 3 ±
…/blender/modifiers/ObjectAnimationModifier.java | 2 ±
4 files changed, 41 insertions(+), 13 deletions(-)

diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/animations/ArmatureHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/animations/ArmatureHelper.java
index 0864a12…6903c21 100644
— a/engine/src/blender/com/jme3/scene/plugins/blender/animations/ArmatureHelper.java
+++ b/engine/src/blender/com/jme3/scene/plugins/blender/animations/ArmatureHelper.java
@@ -183,7 +183,7 @@ public class ArmatureHelper extends AbstractBlenderHelper {

             Bone bone = skeleton.getBone(boneIndex);
             Ipo ipo = new Ipo(bezierCurves, fixUpAxis, blenderContext.getBlenderVersion());
  •            tracks.add((BoneTrack) ipo.calculateTrack(boneIndex, bone.getLocalRotation(), 0, ipo.getLastFrame(), fps, false));
    
  •            tracks.add((BoneTrack) ipo.calculateTrack(boneIndex, bone.getLocalPosition(), bone.getLocalRotation(), bone.getLocalScale(), 0, ipo.getLastFrame(), fps, false));
           }
       }
       this.equaliseBoneTracks(tracks);
    

@@ -221,7 +221,7 @@ public class ArmatureHelper extends AbstractBlenderHelper {
Bone bone = skeleton.getBone(boneIndex);
Ipo ipo = ipoHelper.fromIpoStructure(ipoStructure, blenderContext);
if (ipo != null) {

  •                    tracks.add((BoneTrack) ipo.calculateTrack(boneIndex, bone.getLocalRotation(), 0, ipo.getLastFrame(), fps, false));
    
  •                    tracks.add((BoneTrack) ipo.calculateTrack(boneIndex, bone.getLocalPosition(), bone.getLocalRotation(), bone.getLocalScale(), 0, ipo.getLastFrame(), fps, false));
                   }
               }
           }
    

diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/animations/Ipo.java b/engine/src/blender/com/jme3/scene/plugins/blender/animations/Ipo.java
index 423c87f…e412460 100644
— a/engine/src/blender/com/jme3/scene/plugins/blender/animations/Ipo.java
+++ b/engine/src/blender/com/jme3/scene/plugins/blender/animations/Ipo.java
@@ -115,40 +115,64 @@ public class Ipo {
* 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 localQuaternionRotation
    
  • * @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 firs frame of tracks (inclusive)
    
  • *            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 diference 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)
    *            as jme while other features have different one (Z is UP)
    * @return bone track for the specified bone
    */
    
  • public Track calculateTrack(int targetIndex, Quaternion localQuaternionRotation, 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) {
    // 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[3];
    
  •        float[] translation = new float[] {
    
  •              localTranslation.x,
    
  •              localTranslation.y,
    
  •              localTranslation.z
    
  •        };
    
  •        Quaternion[] rotations = new Quaternion[framesAmount + 1];
    
  •        float[] quaternionRotation = new float[] { 0, 0, 0, 1 };
    
  •        float[] objectRotation = new float[3];
    
  •        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[] { 1.0f, 1.0f, 1.0f };
    
  •        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;
           if(spatialTrack && fixUpAxis) {
               yIndex = 2;
    

@@ -160,6 +184,9 @@ public class Ipo {
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()) {
@@ -222,7 +249,7 @@ public class Ipo {
LOGGER.log(Level.WARNING, “Unknown ipo curve type: {0}.”, bezierCurves[j].getType());
}
}

  •            translations[index] = localQuaternionRotation.multLocal(new Vector3f(translation[0], translation[1], translation[2]));
    
  •            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]);
           }
    

diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/animations/IpoHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/animations/IpoHelper.java
index 5dbf923…a65f4e9 100644
— a/engine/src/blender/com/jme3/scene/plugins/blender/animations/IpoHelper.java
+++ b/engine/src/blender/com/jme3/scene/plugins/blender/animations/IpoHelper.java
@@ -2,6 +2,7 @@ package com.jme3.scene.plugins.blender.animations;

import com.jme3.animation.BoneTrack;
import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
import com.jme3.scene.plugins.blender.BlenderContext;
import com.jme3.scene.plugins.blender.curves.BezierCurve;
@@ -186,7 +187,7 @@ public class IpoHelper extends AbstractBlenderHelper {
}

     @Override
  •    public BoneTrack calculateTrack(int boneIndex, Quaternion localQuaternionRotation, int startFrame, int stopFrame, int fps, boolean boneTrack) {
    
  •    public BoneTrack calculateTrack(int boneIndex, Vector3f localTranslation, Quaternion localRotation, Vector3f localScale, int startFrame, int stopFrame, int fps, boolean boneTrack) {
           throw new IllegalStateException("Constatnt ipo object cannot be used for calculating bone tracks!");
       }
    

    }
    diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ObjectAnimationModifier.java b/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ObjectAnimationModifier.java
    index 0895a0d…8f21afe 100644
    — a/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ObjectAnimationModifier.java
    +++ b/engine/src/blender/com/jme3/scene/plugins/blender/modifiers/ObjectAnimationModifier.java
    @@ -53,7 +53,7 @@ import com.jme3.scene.plugins.blender.file.BlenderFileException;

       Spatial object = (Spatial) blenderContext.getLoadedFeature(objectOMA, LoadedFeatureDataType.LOADED_FEATURE);
       // calculating track
    
  •    SpatialTrack track = (SpatialTrack) ipo.calculateTrack(-1, object.getLocalRotation(), 0, ipo.getLastFrame(), fps, true);
    
  •    SpatialTrack track = (SpatialTrack) ipo.calculateTrack(-1, object.getLocalTranslation(), object.getLocalRotation(), object.getLocalScale(), 0, ipo.getLastFrame(), fps, true);
    
       Animation animation = new Animation(objectAnimationName, ipo.getLastFrame() / (float) fps);
       animation.setTracks(new SpatialTrack[] { track });
    

–
1.8.3.2
[/java]

2 Likes

Hi @arpagaus

Thanks a lot for your fix. I have already commited it to the svn :slight_smile:

Hi @Kaelthas
Thank you. I use that feature a lot, I’m glad it existed in the first place :slight_smile: