Automatic loading of both bone and object animations (no need to specify animations in blender key any more).
git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8305 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
ce259299e2
commit
0b274b3c1b
@ -33,12 +33,8 @@ package com.jme3.asset;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import com.jme3.bounding.BoundingVolume;
|
import com.jme3.bounding.BoundingVolume;
|
||||||
import com.jme3.collision.Collidable;
|
import com.jme3.collision.Collidable;
|
||||||
@ -66,13 +62,6 @@ import com.jme3.texture.Texture;
|
|||||||
public class BlenderKey extends ModelKey {
|
public class BlenderKey extends ModelKey {
|
||||||
|
|
||||||
protected static final int DEFAULT_FPS = 25;
|
protected static final int DEFAULT_FPS = 25;
|
||||||
/**
|
|
||||||
* Animation definitions. The key is the object name that owns the animation. The value is a map between animation
|
|
||||||
* name and its start and stop frames. Blender stores a pointer for animation within object. Therefore one object
|
|
||||||
* can only have one animation at the time. We want to be able to switch between animations for one object so we
|
|
||||||
* need to map the object name to animation names the object will use.
|
|
||||||
*/
|
|
||||||
protected Map<String, Map<String, int[]>> animations;
|
|
||||||
/**
|
/**
|
||||||
* FramesPerSecond parameter describe how many frames there are in each second. It allows to calculate the time
|
* FramesPerSecond parameter describe how many frames there are in each second. It allows to calculate the time
|
||||||
* between the frames.
|
* between the frames.
|
||||||
@ -126,76 +115,6 @@ public class BlenderKey extends ModelKey {
|
|||||||
super(name);
|
super(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This method adds an animation definition. If a definition already eixists in the key then it is replaced.
|
|
||||||
* @param objectName
|
|
||||||
* the name of animation's owner
|
|
||||||
* @param name
|
|
||||||
* the name of the animation
|
|
||||||
* @param start
|
|
||||||
* the start frame of the animation
|
|
||||||
* @param stop
|
|
||||||
* the stop frame of the animation
|
|
||||||
*/
|
|
||||||
public synchronized void addAnimation(String objectName, String name, int start, int stop) {
|
|
||||||
if (objectName == null) {
|
|
||||||
throw new IllegalArgumentException("Object name cannot be null!");
|
|
||||||
}
|
|
||||||
if (name == null) {
|
|
||||||
throw new IllegalArgumentException("Animation name cannot be null!");
|
|
||||||
}
|
|
||||||
if (start > stop) {
|
|
||||||
throw new IllegalArgumentException("Start frame cannot be greater than stop frame!");
|
|
||||||
}
|
|
||||||
if (animations == null) {
|
|
||||||
animations = new HashMap<String, Map<String, int[]>>();
|
|
||||||
animations.put(objectName, new HashMap<String, int[]>());
|
|
||||||
}
|
|
||||||
Map<String, int[]> objectAnimations = animations.get(objectName);
|
|
||||||
if (objectAnimations == null) {
|
|
||||||
objectAnimations = new HashMap<String, int[]>();
|
|
||||||
animations.put(objectName, objectAnimations);
|
|
||||||
}
|
|
||||||
objectAnimations.put(name, new int[] { start, stop });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the animation frames boundaries.
|
|
||||||
* @param objectName
|
|
||||||
* the name of animation's owner
|
|
||||||
* @param name
|
|
||||||
* animation name
|
|
||||||
* @return animation frame boundaries in a table [start, stop] or null if animation of the given name does not
|
|
||||||
* exists
|
|
||||||
*/
|
|
||||||
public int[] getAnimationFrames(String objectName, String name) {
|
|
||||||
Map<String, int[]> objectAnimations = animations == null ? null : animations.get(objectName);
|
|
||||||
int[] frames = objectAnimations == null ? null : objectAnimations.get(name);
|
|
||||||
return frames == null ? null : frames.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the animation names for the given object name.
|
|
||||||
* @param objectName
|
|
||||||
* the name of the object
|
|
||||||
* @return an array of animations for this object
|
|
||||||
*/
|
|
||||||
public Set<String> getAnimationNames(String objectName) {
|
|
||||||
Map<String, int[]> objectAnimations = animations == null ? null : animations.get(objectName);
|
|
||||||
return objectAnimations == null ? null : objectAnimations.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the animations map.
|
|
||||||
* The key is the animated spatial name. The value is a map where the key
|
|
||||||
* is the animation name and the value is 2-element array of int that has
|
|
||||||
* start and stop frame of the animation.
|
|
||||||
* @return the animations map
|
|
||||||
*/
|
|
||||||
public Map<String, Map<String, int[]>> getAnimations() {
|
|
||||||
return animations;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns frames per second amount. The default value is BlenderKey.DEFAULT_FPS = 25.
|
* This method returns frames per second amount. The default value is BlenderKey.DEFAULT_FPS = 25.
|
||||||
* @return the frames per second amount
|
* @return the frames per second amount
|
||||||
@ -424,22 +343,6 @@ public class BlenderKey extends ModelKey {
|
|||||||
public void write(JmeExporter e) throws IOException {
|
public void write(JmeExporter e) throws IOException {
|
||||||
super.write(e);
|
super.write(e);
|
||||||
OutputCapsule oc = e.getCapsule(this);
|
OutputCapsule oc = e.getCapsule(this);
|
||||||
// saving animations
|
|
||||||
oc.write(animations == null ? 0 : animations.size(), "anim-size", 0);
|
|
||||||
if (animations != null) {
|
|
||||||
int objectCounter = 0;
|
|
||||||
for (Entry<String, Map<String, int[]>> animEntry : animations.entrySet()) {
|
|
||||||
oc.write(animEntry.getKey(), "animated-object-" + objectCounter, null);
|
|
||||||
int animsAmount = animEntry.getValue().size();
|
|
||||||
oc.write(animsAmount, "anims-amount-" + objectCounter, 0);
|
|
||||||
for (Entry<String, int[]> animsEntry : animEntry.getValue().entrySet()) {
|
|
||||||
oc.write(animsEntry.getKey(), "anim-name-" + objectCounter, null);
|
|
||||||
oc.write(animsEntry.getValue(), "anim-frames-" + objectCounter, null);
|
|
||||||
}
|
|
||||||
++objectCounter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// saving the rest of the data
|
|
||||||
oc.write(fps, "fps", DEFAULT_FPS);
|
oc.write(fps, "fps", DEFAULT_FPS);
|
||||||
oc.write(generatedTextureWidth, "generated-texture-width", 20);
|
oc.write(generatedTextureWidth, "generated-texture-width", 20);
|
||||||
oc.write(generatedTextureHeight, "generated-texture-height", 20);
|
oc.write(generatedTextureHeight, "generated-texture-height", 20);
|
||||||
@ -458,28 +361,6 @@ public class BlenderKey extends ModelKey {
|
|||||||
public void read(JmeImporter e) throws IOException {
|
public void read(JmeImporter e) throws IOException {
|
||||||
super.read(e);
|
super.read(e);
|
||||||
InputCapsule ic = e.getCapsule(this);
|
InputCapsule ic = e.getCapsule(this);
|
||||||
// reading animations
|
|
||||||
int animSize = ic.readInt("anim-size", 0);
|
|
||||||
if (animSize > 0) {
|
|
||||||
if (animations == null) {
|
|
||||||
animations = new HashMap<String, Map<String, int[]>>(animSize);
|
|
||||||
} else {
|
|
||||||
animations.clear();
|
|
||||||
}
|
|
||||||
for (int i = 0; i < animSize; ++i) {
|
|
||||||
String objectName = ic.readString("animated-object-" + i, null);
|
|
||||||
int animationsAmount = ic.readInt("anims-amount-" + i, 0);
|
|
||||||
Map<String, int[]> objectAnimations = new HashMap<String, int[]>(animationsAmount);
|
|
||||||
for (int j = 0; j < animationsAmount; ++j) {
|
|
||||||
String animName = ic.readString("anim-name-" + i, null);
|
|
||||||
int[] animFrames = ic.readIntArray("anim-frames-" + i, null);
|
|
||||||
objectAnimations.put(animName, animFrames);
|
|
||||||
}
|
|
||||||
animations.put(objectName, objectAnimations);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// reading the rest of the data
|
|
||||||
fps = ic.readInt("fps", DEFAULT_FPS);
|
fps = ic.readInt("fps", DEFAULT_FPS);
|
||||||
generatedTextureWidth = ic.readInt("generated-texture-width", 20);
|
generatedTextureWidth = ic.readInt("generated-texture-width", 20);
|
||||||
generatedTextureHeight = ic.readInt("generated-texture-height", 20);
|
generatedTextureHeight = ic.readInt("generated-texture-height", 20);
|
||||||
@ -498,7 +379,6 @@ public class BlenderKey extends ModelKey {
|
|||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = super.hashCode();
|
int result = super.hashCode();
|
||||||
result = prime * result + (animations == null ? 0 : animations.hashCode());
|
|
||||||
result = prime * result + (assetRootPath == null ? 0 : assetRootPath.hashCode());
|
result = prime * result + (assetRootPath == null ? 0 : assetRootPath.hashCode());
|
||||||
result = prime * result + (defaultMaterial == null ? 0 : defaultMaterial.hashCode());
|
result = prime * result + (defaultMaterial == null ? 0 : defaultMaterial.hashCode());
|
||||||
result = prime * result + (faceCullMode == null ? 0 : faceCullMode.hashCode());
|
result = prime * result + (faceCullMode == null ? 0 : faceCullMode.hashCode());
|
||||||
@ -526,13 +406,6 @@ public class BlenderKey extends ModelKey {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
BlenderKey other = (BlenderKey) obj;
|
BlenderKey other = (BlenderKey) obj;
|
||||||
if (animations == null) {
|
|
||||||
if (other.animations != null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (!animations.equals(other.animations)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (assetRootPath == null) {
|
if (assetRootPath == null) {
|
||||||
if (other.assetRootPath != null) {
|
if (other.assetRootPath != null) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -39,7 +39,7 @@ import java.util.logging.Level;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import com.jme3.animation.Bone;
|
import com.jme3.animation.Bone;
|
||||||
import com.jme3.animation.BoneTrack;
|
import com.jme3.animation.Track;
|
||||||
import com.jme3.math.Matrix4f;
|
import com.jme3.math.Matrix4f;
|
||||||
import com.jme3.math.Quaternion;
|
import com.jme3.math.Quaternion;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
@ -320,20 +320,16 @@ public class ArmatureHelper extends AbstractBlenderHelper {
|
|||||||
* the structure containing the tracks
|
* the structure containing the tracks
|
||||||
* @param blenderContext
|
* @param blenderContext
|
||||||
* the blender context
|
* the blender context
|
||||||
* @param objectName
|
|
||||||
* the name of the object that will use these tracks
|
|
||||||
* @param animationName
|
|
||||||
* the animation name
|
|
||||||
* @return a list of tracks for the specified animation
|
* @return a list of tracks for the specified animation
|
||||||
* @throws BlenderFileException
|
* @throws BlenderFileException
|
||||||
* an exception is thrown when there are problems with the blend
|
* an exception is thrown when there are problems with the blend
|
||||||
* file
|
* file
|
||||||
*/
|
*/
|
||||||
public BoneTrack[] getTracks(Structure actionStructure, BlenderContext blenderContext, String objectName, String animationName) throws BlenderFileException {
|
public Track<?>[] getTracks(Structure actionStructure, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
if (blenderVersion < 250) {
|
if (blenderVersion < 250) {
|
||||||
return this.getTracks249(actionStructure, blenderContext, objectName, animationName);
|
return this.getTracks249(actionStructure, blenderContext);
|
||||||
} else {
|
} else {
|
||||||
return this.getTracks250(actionStructure, blenderContext, objectName, animationName);
|
return this.getTracks250(actionStructure, blenderContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,26 +340,21 @@ public class ArmatureHelper extends AbstractBlenderHelper {
|
|||||||
* the structure containing the tracks
|
* the structure containing the tracks
|
||||||
* @param blenderContext
|
* @param blenderContext
|
||||||
* the blender context
|
* the blender context
|
||||||
* @param objectName
|
|
||||||
* the name of the object that will use these tracks
|
|
||||||
* @param animationName
|
|
||||||
* the animation name
|
|
||||||
* @return a list of tracks for the specified animation
|
* @return a list of tracks for the specified animation
|
||||||
* @throws BlenderFileException
|
* @throws BlenderFileException
|
||||||
* an exception is thrown when there are problems with the blend
|
* an exception is thrown when there are problems with the blend
|
||||||
* file
|
* file
|
||||||
*/
|
*/
|
||||||
private BoneTrack[] getTracks250(Structure actionStructure, BlenderContext blenderContext, String objectName, String animationName) throws BlenderFileException {
|
private Track<?>[] getTracks250(Structure actionStructure, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
LOGGER.log(Level.INFO, "Getting tracks!");
|
LOGGER.log(Level.INFO, "Getting tracks!");
|
||||||
int fps = blenderContext.getBlenderKey().getFps();
|
int fps = blenderContext.getBlenderKey().getFps();
|
||||||
int[] animationFrames = blenderContext.getBlenderKey().getAnimationFrames(objectName, animationName);
|
|
||||||
Structure groups = (Structure) actionStructure.getFieldValue("groups");
|
Structure groups = (Structure) actionStructure.getFieldValue("groups");
|
||||||
List<Structure> actionGroups = groups.evaluateListBase(blenderContext);//bActionGroup
|
List<Structure> actionGroups = groups.evaluateListBase(blenderContext);//bActionGroup
|
||||||
if (actionGroups != null && actionGroups.size() > 0 && (bonesMap == null || bonesMap.size() == 0)) {
|
if (actionGroups != null && actionGroups.size() > 0 && (bonesMap == null || bonesMap.size() == 0)) {
|
||||||
throw new IllegalStateException("No bones found! Cannot proceed to calculating tracks!");
|
throw new IllegalStateException("No bones found! Cannot proceed to calculating tracks!");
|
||||||
}
|
}
|
||||||
|
|
||||||
List<BoneTrack> tracks = new ArrayList<BoneTrack>();
|
List<Track<?>> tracks = new ArrayList<Track<?>>();
|
||||||
for (Structure actionGroup : actionGroups) {
|
for (Structure actionGroup : actionGroups) {
|
||||||
String name = actionGroup.getFieldValue("name").toString();
|
String name = actionGroup.getFieldValue("name").toString();
|
||||||
Integer boneIndex = bonesMap.get(name);
|
Integer boneIndex = bonesMap.get(name);
|
||||||
@ -389,10 +380,10 @@ public class ArmatureHelper extends AbstractBlenderHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ipo ipo = new Ipo(bezierCurves);
|
Ipo ipo = new Ipo(bezierCurves);
|
||||||
tracks.add(ipo.calculateTrack(boneIndex.intValue(), animationFrames[0], animationFrames[1], fps));
|
tracks.add(ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tracks.toArray(new BoneTrack[tracks.size()]);
|
return tracks.toArray(new Track<?>[tracks.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -402,26 +393,21 @@ public class ArmatureHelper extends AbstractBlenderHelper {
|
|||||||
* the structure containing the tracks
|
* the structure containing the tracks
|
||||||
* @param blenderContext
|
* @param blenderContext
|
||||||
* the blender context
|
* the blender context
|
||||||
* @param objectName
|
|
||||||
* the name of the object that will use these tracks
|
|
||||||
* @param animationName
|
|
||||||
* the animation name
|
|
||||||
* @return a list of tracks for the specified animation
|
* @return a list of tracks for the specified animation
|
||||||
* @throws BlenderFileException
|
* @throws BlenderFileException
|
||||||
* an exception is thrown when there are problems with the blend
|
* an exception is thrown when there are problems with the blend
|
||||||
* file
|
* file
|
||||||
*/
|
*/
|
||||||
private BoneTrack[] getTracks249(Structure actionStructure, BlenderContext blenderContext, String objectName, String animationName) throws BlenderFileException {
|
private Track<?>[] getTracks249(Structure actionStructure, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
LOGGER.log(Level.INFO, "Getting tracks!");
|
LOGGER.log(Level.INFO, "Getting tracks!");
|
||||||
IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
|
IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
|
||||||
int fps = blenderContext.getBlenderKey().getFps();
|
int fps = blenderContext.getBlenderKey().getFps();
|
||||||
int[] animationFrames = blenderContext.getBlenderKey().getAnimationFrames(objectName, animationName);
|
|
||||||
Structure chanbase = (Structure) actionStructure.getFieldValue("chanbase");
|
Structure chanbase = (Structure) actionStructure.getFieldValue("chanbase");
|
||||||
List<Structure> actionChannels = chanbase.evaluateListBase(blenderContext);//bActionChannel
|
List<Structure> actionChannels = chanbase.evaluateListBase(blenderContext);//bActionChannel
|
||||||
if (actionChannels != null && actionChannels.size() > 0 && (bonesMap == null || bonesMap.size() == 0)) {
|
if (actionChannels != null && actionChannels.size() > 0 && (bonesMap == null || bonesMap.size() == 0)) {
|
||||||
throw new IllegalStateException("No bones found! Cannot proceed to calculating tracks!");
|
throw new IllegalStateException("No bones found! Cannot proceed to calculating tracks!");
|
||||||
}
|
}
|
||||||
List<BoneTrack> tracks = new ArrayList<BoneTrack>();
|
List<Track<?>> tracks = new ArrayList<Track<?>>();
|
||||||
for (Structure bActionChannel : actionChannels) {
|
for (Structure bActionChannel : actionChannels) {
|
||||||
String name = bActionChannel.getFieldValue("name").toString();
|
String name = bActionChannel.getFieldValue("name").toString();
|
||||||
Integer boneIndex = bonesMap.get(name);
|
Integer boneIndex = bonesMap.get(name);
|
||||||
@ -430,11 +416,11 @@ public class ArmatureHelper extends AbstractBlenderHelper {
|
|||||||
if (!p.isNull()) {
|
if (!p.isNull()) {
|
||||||
Structure ipoStructure = p.fetchData(blenderContext.getInputStream()).get(0);
|
Structure ipoStructure = p.fetchData(blenderContext.getInputStream()).get(0);
|
||||||
Ipo ipo = ipoHelper.createIpo(ipoStructure, blenderContext);
|
Ipo ipo = ipoHelper.createIpo(ipoStructure, blenderContext);
|
||||||
tracks.add(ipo.calculateTrack(boneIndex.intValue(), animationFrames[0], animationFrames[1], fps));
|
tracks.add(ipo.calculateTrack(boneIndex.intValue(), 0, ipo.getLastFrame(), fps));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tracks.toArray(new BoneTrack[tracks.size()]);
|
return tracks.toArray(new Track<?>[tracks.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package com.jme3.scene.plugins.blender.animations;
|
package com.jme3.scene.plugins.blender.animations;
|
||||||
|
|
||||||
import com.jme3.animation.BoneTrack;
|
import com.jme3.animation.BoneTrack;
|
||||||
|
import com.jme3.animation.SpatialTrack;
|
||||||
|
import com.jme3.animation.Track;
|
||||||
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;
|
||||||
@ -28,7 +30,7 @@ public class Ipo {
|
|||||||
/** 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 BoneTrack calculatedTrack;
|
private Track<?> calculatedTrack;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor. Stores the bezier curves.
|
* Constructor. Stores the bezier curves.
|
||||||
@ -105,8 +107,9 @@ public class Ipo {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method calculates the value of the curves as a bone track between the specified frames.
|
* This method calculates the value of the curves as a bone track between the specified frames.
|
||||||
* @param boneIndex
|
* @param targetIndex
|
||||||
* the index of the bone for which the method calculates the tracks
|
* 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 startFrame
|
* @param startFrame
|
||||||
* the firs frame of tracks (inclusive)
|
* the firs frame of tracks (inclusive)
|
||||||
* @param stopFrame
|
* @param stopFrame
|
||||||
@ -115,63 +118,68 @@ public class Ipo {
|
|||||||
* frame rate (frames per second)
|
* frame rate (frames per second)
|
||||||
* @return bone track for the specified bone
|
* @return bone track for the specified bone
|
||||||
*/
|
*/
|
||||||
public BoneTrack calculateTrack(int boneIndex, int startFrame, int stopFrame, int fps) {
|
public Track<?> calculateTrack(int targetIndex, int startFrame, int stopFrame, int fps) {
|
||||||
//preparing data for track
|
if(calculatedTrack == null) {
|
||||||
int framesAmount = stopFrame - startFrame;
|
//preparing data for track
|
||||||
float start = (startFrame - 1.0f) / fps;
|
int framesAmount = stopFrame - startFrame;
|
||||||
float timeBetweenFrames = 1.0f / fps;
|
float start = (startFrame - 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[3];
|
float[] translation = new float[3];
|
||||||
Quaternion[] rotations = new Quaternion[framesAmount + 1];
|
Quaternion[] rotations = new Quaternion[framesAmount + 1];
|
||||||
float[] quaternionRotation = new float[4];
|
float[] quaternionRotation = new float[4];
|
||||||
float[] objectRotation = new float[3];
|
float[] objectRotation = new float[3];
|
||||||
boolean bObjectRotation = false;
|
boolean bSpatialTrack = targetIndex < 0;
|
||||||
Vector3f[] scales = new Vector3f[framesAmount + 1];
|
Vector3f[] scales = new Vector3f[framesAmount + 1];
|
||||||
float[] scale = new float[3];
|
float[] scale = new float[3];
|
||||||
|
|
||||||
//calculating track data
|
//calculating track data
|
||||||
for (int frame = startFrame; frame <= stopFrame; ++frame) {
|
for (int frame = startFrame; frame <= stopFrame; ++frame) {
|
||||||
int index = frame - startFrame;
|
int index = frame - startFrame;
|
||||||
times[index] = start + (frame - 1) * timeBetweenFrames;
|
times[index] = start + (frame - 1) * timeBetweenFrames;
|
||||||
for (int j = 0; j < bezierCurves.length; ++j) {
|
for (int j = 0; j < bezierCurves.length; ++j) {
|
||||||
double value = bezierCurves[j].evaluate(frame, BezierCurve.Y_VALUE);
|
double value = bezierCurves[j].evaluate(frame, BezierCurve.Y_VALUE);
|
||||||
switch (bezierCurves[j].getType()) {
|
switch (bezierCurves[j].getType()) {
|
||||||
case AC_LOC_X:
|
case AC_LOC_X:
|
||||||
case AC_LOC_Y:
|
case AC_LOC_Y:
|
||||||
case AC_LOC_Z:
|
case AC_LOC_Z:
|
||||||
translation[bezierCurves[j].getType() - 1] = (float) value;
|
translation[bezierCurves[j].getType() - 1] = (float) value;
|
||||||
break;
|
break;
|
||||||
case OB_ROT_X:
|
case OB_ROT_X:
|
||||||
case OB_ROT_Y:
|
case OB_ROT_Y:
|
||||||
case OB_ROT_Z:
|
case OB_ROT_Z:
|
||||||
objectRotation[bezierCurves[j].getType() - 7] = (float) value;
|
objectRotation[bezierCurves[j].getType() - 7] = (float) value;
|
||||||
bObjectRotation = true;
|
break;
|
||||||
break;
|
case AC_SIZE_X:
|
||||||
case AC_SIZE_X:
|
case AC_SIZE_Y:
|
||||||
case AC_SIZE_Y:
|
case AC_SIZE_Z:
|
||||||
case AC_SIZE_Z:
|
scale[bezierCurves[j].getType() - 13] = (float) value;
|
||||||
scale[bezierCurves[j].getType() - 13] = (float) value;
|
break;
|
||||||
break;
|
case AC_QUAT_W:
|
||||||
case AC_QUAT_W:
|
quaternionRotation[3] = (float) value;
|
||||||
quaternionRotation[3] = (float) value;
|
break;
|
||||||
break;
|
case AC_QUAT_X:
|
||||||
case AC_QUAT_X:
|
case AC_QUAT_Y:
|
||||||
case AC_QUAT_Y:
|
case AC_QUAT_Z:
|
||||||
case AC_QUAT_Z:
|
quaternionRotation[bezierCurves[j].getType() - 26] = (float) value;
|
||||||
quaternionRotation[bezierCurves[j].getType() - 26] = (float) value;
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
//TODO: error? info? warning?
|
||||||
//TODO: error? info? warning?
|
}
|
||||||
}
|
}
|
||||||
|
translations[index] = new Vector3f(translation[0], translation[1], translation[2]);
|
||||||
|
rotations[index] = bSpatialTrack ? new Quaternion().fromAngles(objectRotation)
|
||||||
|
: new Quaternion(quaternionRotation[0], quaternionRotation[1], quaternionRotation[2], quaternionRotation[3]);
|
||||||
|
scales[index] = new Vector3f(scale[0], scale[1], scale[2]);
|
||||||
}
|
}
|
||||||
translations[index] = new Vector3f(translation[0], translation[1], translation[2]);
|
if(bSpatialTrack) {
|
||||||
rotations[index] = bObjectRotation ? new Quaternion().fromAngles(objectRotation)
|
calculatedTrack = new SpatialTrack(times, translations, rotations, scales);
|
||||||
: new Quaternion(quaternionRotation[0], quaternionRotation[1], quaternionRotation[2], quaternionRotation[3]);
|
} else {
|
||||||
scales[index] = new Vector3f(scale[0], scale[1], scale[2]);
|
calculatedTrack = new BoneTrack(targetIndex, times, translations, rotations, scales);
|
||||||
}
|
}
|
||||||
calculatedTrack = new BoneTrack(boneIndex, times, translations, rotations, scales);
|
}
|
||||||
return calculatedTrack;
|
return calculatedTrack;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,7 +6,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@ -15,6 +14,7 @@ import com.jme3.animation.Animation;
|
|||||||
import com.jme3.animation.Bone;
|
import com.jme3.animation.Bone;
|
||||||
import com.jme3.animation.Skeleton;
|
import com.jme3.animation.Skeleton;
|
||||||
import com.jme3.animation.SkeletonControl;
|
import com.jme3.animation.SkeletonControl;
|
||||||
|
import com.jme3.animation.Track;
|
||||||
import com.jme3.math.Matrix4f;
|
import com.jme3.math.Matrix4f;
|
||||||
import com.jme3.scene.Geometry;
|
import com.jme3.scene.Geometry;
|
||||||
import com.jme3.scene.Mesh;
|
import com.jme3.scene.Mesh;
|
||||||
@ -116,28 +116,27 @@ import com.jme3.util.BufferUtils;
|
|||||||
this.readVerticesWeightsData(objectStructure, meshStructure, blenderContext);
|
this.readVerticesWeightsData(objectStructure, meshStructure, blenderContext);
|
||||||
|
|
||||||
//read animations
|
//read animations
|
||||||
String objectName = objectStructure.getName();
|
ArrayList<Animation> animations = new ArrayList<Animation>();
|
||||||
Set<String> animationNames = blenderContext.getBlenderKey().getAnimationNames(objectName);
|
List<FileBlockHeader> actionHeaders = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
|
||||||
System.out.println("Loaded animation " + objectName);
|
for (FileBlockHeader header : actionHeaders) {
|
||||||
if (animationNames != null && animationNames.size() > 0) {
|
Structure actionStructure = header.getStructure(blenderContext);
|
||||||
ArrayList<Animation> animations = new ArrayList<Animation>();
|
String actionName = actionStructure.getName();
|
||||||
List<FileBlockHeader> actionHeaders = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
|
|
||||||
for (FileBlockHeader header : actionHeaders) {
|
|
||||||
Structure actionStructure = header.getStructure(blenderContext);
|
|
||||||
String actionName = actionStructure.getName();
|
|
||||||
if (animationNames.contains(actionName)) {
|
|
||||||
int[] animationFrames = blenderContext.getBlenderKey().getAnimationFrames(objectName, actionName);
|
|
||||||
int fps = blenderContext.getBlenderKey().getFps();
|
|
||||||
float start = (float) animationFrames[0] / (float) fps;
|
|
||||||
float stop = (float) animationFrames[1] / (float) fps;
|
|
||||||
Animation boneAnimation = new Animation(actionName, stop - start);
|
|
||||||
boneAnimation.setTracks(armatureHelper.getTracks(actionStructure, blenderContext, objectName, actionName));
|
|
||||||
animations.add(boneAnimation);
|
|
||||||
|
|
||||||
|
Track<?>[] tracks = armatureHelper.getTracks(actionStructure, blenderContext);
|
||||||
|
//determining the animation time
|
||||||
|
float maximumTrackLength = 0;
|
||||||
|
for(Track<?> track : tracks) {
|
||||||
|
float length = track.getLength();
|
||||||
|
if(length > maximumTrackLength) {
|
||||||
|
maximumTrackLength = length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
animData = new AnimData(new Skeleton(bones), animations);
|
|
||||||
|
Animation boneAnimation = new Animation(actionName, maximumTrackLength);
|
||||||
|
boneAnimation.setTracks(tracks);
|
||||||
|
animations.add(boneAnimation);
|
||||||
}
|
}
|
||||||
|
animData = new AnimData(new Skeleton(bones), animations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,22 @@
|
|||||||
package com.jme3.scene.plugins.blender.modifiers;
|
package com.jme3.scene.plugins.blender.modifiers;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.animation.AnimControl;
|
||||||
|
import com.jme3.animation.Animation;
|
||||||
|
import com.jme3.animation.Track;
|
||||||
import com.jme3.scene.Node;
|
import com.jme3.scene.Node;
|
||||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.IpoHelper;
|
||||||
|
import com.jme3.scene.plugins.blender.constraints.Constraint;
|
||||||
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.FileBlockHeader;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
import com.jme3.scene.plugins.blender.file.Structure;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
import com.jme3.scene.plugins.ogre.AnimData;
|
import com.jme3.scene.plugins.ogre.AnimData;
|
||||||
|
|
||||||
@ -41,13 +53,12 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
*/
|
*/
|
||||||
public ObjectAnimationModifier(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
|
public ObjectAnimationModifier(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
LOGGER.warning("Object animation modifier not yet implemented!");
|
LOGGER.warning("Object animation modifier not yet implemented!");
|
||||||
/*
|
|
||||||
Pointer pIpo = (Pointer) objectStructure.getFieldValue("ipo");
|
Pointer pIpo = (Pointer) objectStructure.getFieldValue("ipo");
|
||||||
if (pIpo.isNotNull()) {
|
if (pIpo.isNotNull()) {
|
||||||
// check if there is an action name connected with this ipo
|
// check if there is an action name connected with this ipo
|
||||||
String objectAnimationName = null;
|
String objectAnimationName = null;
|
||||||
List<FileBlockHeader> actionBlocks = blenderContext
|
List<FileBlockHeader> actionBlocks = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
|
||||||
.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
|
|
||||||
for (FileBlockHeader actionBlock : actionBlocks) {
|
for (FileBlockHeader actionBlock : actionBlocks) {
|
||||||
Structure action = actionBlock.getStructure(blenderContext);
|
Structure action = actionBlock.getStructure(blenderContext);
|
||||||
List<Structure> actionChannels = ((Structure) action.getFieldValue("chanbase")).evaluateListBase(blenderContext);
|
List<Structure> actionChannels = ((Structure) action.getFieldValue("chanbase")).evaluateListBase(blenderContext);
|
||||||
@ -68,38 +79,51 @@ import com.jme3.scene.plugins.ogre.AnimData;
|
|||||||
IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
|
IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
|
||||||
Structure ipoStructure = pIpo.fetchData(blenderContext.getInputStream()).get(0);
|
Structure ipoStructure = pIpo.fetchData(blenderContext.getInputStream()).get(0);
|
||||||
Ipo ipo = ipoHelper.createIpo(ipoStructure, blenderContext);
|
Ipo ipo = ipoHelper.createIpo(ipoStructure, blenderContext);
|
||||||
int[] animationFrames = blenderContext.getBlenderKey().getAnimationFrames(objectName, objectAnimationName);
|
|
||||||
if (animationFrames == null) {// if the name was created here there are no frames set for the animation
|
|
||||||
animationFrames = new int[] { 1, ipo.getLastFrame() };
|
|
||||||
}
|
|
||||||
int fps = blenderContext.getBlenderKey().getFps();
|
int fps = blenderContext.getBlenderKey().getFps();
|
||||||
float start = (float) animationFrames[0] / (float) fps;
|
|
||||||
float stop = (float) animationFrames[1] / (float) fps;
|
|
||||||
|
|
||||||
// calculating track for the only bone in this skeleton
|
// calculating track for the only bone in this skeleton
|
||||||
BoneTrack[] tracks = new BoneTrack[1];
|
Track<?> track = ipo.calculateTrack(-1, 0, ipo.getLastFrame(), fps);
|
||||||
tracks[0] = ipo.calculateTrack(0, animationFrames[0], animationFrames[1], fps);
|
|
||||||
|
|
||||||
BoneAnimation boneAnimation = new BoneAnimation(objectAnimationName, stop - start);
|
Animation animation = new Animation(objectAnimationName, ipo.getLastFrame() / fps);
|
||||||
boneAnimation.setTracks(tracks);
|
animation.setTracks(new Track<?>[] { track });
|
||||||
ArrayList<Animation> animations = new ArrayList<Animation>(1);
|
ArrayList<Animation> animations = new ArrayList<Animation>(1);
|
||||||
animations.add(boneAnimation);
|
animations.add(animation);
|
||||||
|
|
||||||
// preparing the object's bone
|
animData = new AnimData(null, animations);
|
||||||
ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
|
|
||||||
Transform t = objectHelper.getTransformation(objectStructure, blenderContext);
|
|
||||||
Bone bone = new Bone(null);
|
|
||||||
bone.setBindTransforms(t.getTranslation(), t.getRotation(), t.getScale());
|
|
||||||
|
|
||||||
animData = new AnimData(new Skeleton(new Bone[] { bone }), animations);
|
|
||||||
objectOMA = objectStructure.getOldMemoryAddress();
|
objectOMA = objectStructure.getOldMemoryAddress();
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Node apply(Node node, BlenderContext blenderContext) {
|
public Node apply(Node node, BlenderContext blenderContext) {
|
||||||
LOGGER.warning("Object animation modifier not yet implemented!");
|
if(invalid) {
|
||||||
|
LOGGER.log(Level.WARNING, "Armature modifier is invalid! Cannot be applied to: {0}", node.getName());
|
||||||
|
}//if invalid, animData will be null
|
||||||
|
if(animData == null) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<Animation> animList = animData.anims;
|
||||||
|
if (animList != null && animList.size() > 0) {
|
||||||
|
List<Constraint> constraints = blenderContext.getConstraints(this.objectOMA);
|
||||||
|
HashMap<String, Animation> anims = new HashMap<String, Animation>();
|
||||||
|
for (int i = 0; i < animList.size(); ++i) {
|
||||||
|
Animation animation = (Animation) animList.get(i).clone();
|
||||||
|
|
||||||
|
// baking constraints into animations
|
||||||
|
if (constraints != null && constraints.size() > 0) {
|
||||||
|
for (Constraint constraint : constraints) {
|
||||||
|
constraint.affectAnimation(animation, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anims.put(animation.getName(), animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimControl control = new AnimControl(null);
|
||||||
|
control.setAnimations(anims);
|
||||||
|
node.addControl(control);
|
||||||
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user