git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8267 75d07b2b-3a1a-0410-a2c5-0572b91ccdca3.0
parent
6600473a82
commit
bfc57cc7db
@ -0,0 +1,98 @@ |
||||
package com.jme3.animation; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import com.jme3.export.InputCapsule; |
||||
import com.jme3.export.JmeExporter; |
||||
import com.jme3.export.JmeImporter; |
||||
import com.jme3.export.OutputCapsule; |
||||
import com.jme3.scene.Spatial; |
||||
|
||||
/** |
||||
* This class animates the whole spatials. All spatial's children are also |
||||
* affected by their parent's movement. |
||||
* |
||||
* @author Marcin Roguski (Kaelthas) |
||||
*/ |
||||
public class SpatialAnimation implements Animation { |
||||
/** The name of the animation. */ |
||||
private String name; |
||||
/** The length of the animation. */ |
||||
private float length; |
||||
/** The track of the animation. */ |
||||
private SpatialTrack track; |
||||
|
||||
/** |
||||
* Constructor. Stores the name and length of the animation. |
||||
* @param name the name of the animation |
||||
* @param length the length of the animation |
||||
*/ |
||||
public SpatialAnimation(String name, float length) { |
||||
this.name = name; |
||||
this.length = length; |
||||
} |
||||
|
||||
@Override |
||||
public void setTime(float time, float blendAmount, AnimControl control, |
||||
AnimChannel channel) { |
||||
Spatial spatial = control.getSpatial(); |
||||
if (spatial != null) { |
||||
track.setTime(time, spatial); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* This method sets the animation track. |
||||
* @param track the animation track |
||||
*/ |
||||
public void setTrack(SpatialTrack track) { |
||||
this.track = track; |
||||
} |
||||
|
||||
/** |
||||
* @return the animation track |
||||
*/ |
||||
public SpatialTrack getTracks() { |
||||
return track; |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return name; |
||||
} |
||||
|
||||
@Override |
||||
public float getLength() { |
||||
return length; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return "SpatialAnim[name=" + name + ", length=" + length + "]"; |
||||
} |
||||
|
||||
@Override |
||||
public Animation clone() { |
||||
try { |
||||
return (Animation) super.clone(); |
||||
} catch (CloneNotSupportedException e) { |
||||
throw new AssertionError(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void write(JmeExporter ex) throws IOException { |
||||
OutputCapsule oc = ex.getCapsule(this); |
||||
oc.write(name, "name", null); |
||||
oc.write(length, "length", 0); |
||||
oc.write(track, "track", null); |
||||
} |
||||
|
||||
@Override |
||||
public void read(JmeImporter im) throws IOException { |
||||
InputCapsule in = im.getCapsule(this); |
||||
name = in.readString("name", null); |
||||
length = in.readFloat("length", 0); |
||||
track = (SpatialTrack) in.readSavable("track", null); |
||||
} |
||||
} |
@ -0,0 +1,195 @@ |
||||
package com.jme3.animation; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import com.jme3.export.InputCapsule; |
||||
import com.jme3.export.JmeExporter; |
||||
import com.jme3.export.JmeImporter; |
||||
import com.jme3.export.OutputCapsule; |
||||
import com.jme3.export.Savable; |
||||
import com.jme3.math.Quaternion; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.scene.Spatial; |
||||
|
||||
/** |
||||
* This class represents the track for spatial animation. |
||||
* |
||||
* @author Marcin Roguski (Kaelthas) |
||||
*/ |
||||
public class SpatialTrack implements Savable { |
||||
/** Translations of the track. */ |
||||
private CompactVector3Array translations; |
||||
/** Rotations of the track. */ |
||||
private CompactQuaternionArray rotations; |
||||
/** Scales of the track. */ |
||||
private CompactVector3Array scales; |
||||
/** The times of the animations frames. */ |
||||
private float[] times; |
||||
|
||||
// temp vectors for interpolation
|
||||
private transient final Vector3f tempV = new Vector3f(); |
||||
private transient final Quaternion tempQ = new Quaternion(); |
||||
private transient final Vector3f tempS = new Vector3f(); |
||||
private transient final Vector3f tempV2 = new Vector3f(); |
||||
private transient final Quaternion tempQ2 = new Quaternion(); |
||||
private transient final Vector3f tempS2 = new Vector3f(); |
||||
|
||||
public SpatialTrack() { |
||||
} |
||||
|
||||
/** |
||||
* Creates a spatial track for the given track data. |
||||
* |
||||
* @param times |
||||
* a float array with the time of each frame |
||||
* @param translations |
||||
* the translation of the bone for each frame |
||||
* @param rotations |
||||
* the rotation of the bone for each frame |
||||
* @param scales |
||||
* the scale of the bone for each frame |
||||
*/ |
||||
public SpatialTrack(float[] times, Vector3f[] translations, |
||||
Quaternion[] rotations, Vector3f[] scales) { |
||||
this.setKeyframes(times, translations, rotations, scales); |
||||
} |
||||
|
||||
/** |
||||
* |
||||
* Modify the spatial which this track modifies. |
||||
* |
||||
* @param time |
||||
* the current time of the animation |
||||
* @param spatial |
||||
* the spatial that should be animated with this track |
||||
*/ |
||||
public void setTime(float time, Spatial spatial) { |
||||
int lastFrame = times.length - 1; |
||||
if (time < 0 || lastFrame == 0) { |
||||
rotations.get(0, tempQ); |
||||
translations.get(0, tempV); |
||||
if (scales != null) { |
||||
scales.get(0, tempS); |
||||
} |
||||
} else if (time >= times[lastFrame]) { |
||||
rotations.get(lastFrame, tempQ); |
||||
translations.get(lastFrame, tempV); |
||||
if (scales != null) { |
||||
scales.get(lastFrame, tempS); |
||||
} |
||||
} else { |
||||
int startFrame = 0; |
||||
int endFrame = 1; |
||||
// use lastFrame so we never overflow the array
|
||||
for (int i = 0; i < lastFrame && times[i] < time; ++i) { |
||||
startFrame = i; |
||||
endFrame = i + 1; |
||||
} |
||||
|
||||
float blend = (time - times[startFrame]) / (times[endFrame] - times[startFrame]); |
||||
|
||||
rotations.get(startFrame, tempQ); |
||||
translations.get(startFrame, tempV); |
||||
if (scales != null) { |
||||
scales.get(startFrame, tempS); |
||||
} |
||||
rotations.get(endFrame, tempQ2); |
||||
translations.get(endFrame, tempV2); |
||||
if (scales != null) { |
||||
scales.get(endFrame, tempS2); |
||||
} |
||||
tempQ.nlerp(tempQ2, blend); |
||||
tempV.interpolate(tempV2, blend); |
||||
tempS.interpolate(tempS2, blend); |
||||
} |
||||
spatial.setLocalTranslation(tempV); |
||||
spatial.setLocalRotation(tempQ); |
||||
if (scales != null) { |
||||
spatial.setLocalScale(tempS); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Set the translations, rotations and scales for this track. |
||||
* |
||||
* @param times |
||||
* a float array with the time of each frame |
||||
* @param translations |
||||
* the translation of the bone for each frame |
||||
* @param rotations |
||||
* the rotation of the bone for each frame |
||||
* @param scales |
||||
* the scale of the bone for each frame |
||||
*/ |
||||
public void setKeyframes(float[] times, Vector3f[] translations, |
||||
Quaternion[] rotations, Vector3f[] scales) { |
||||
if (times.length == 0) { |
||||
throw new RuntimeException("BoneTrack with no keyframes!"); |
||||
} |
||||
|
||||
assert times.length == translations.length |
||||
&& times.length == rotations.length; |
||||
|
||||
this.times = times; |
||||
this.translations = new CompactVector3Array(); |
||||
this.translations.add(translations); |
||||
this.translations.freeze(); |
||||
this.rotations = new CompactQuaternionArray(); |
||||
this.rotations.add(rotations); |
||||
this.rotations.freeze(); |
||||
|
||||
assert times.length == scales.length; |
||||
|
||||
if (scales != null) { |
||||
this.scales = new CompactVector3Array(); |
||||
this.scales.add(scales); |
||||
this.scales.freeze(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @return the array of rotations of this track |
||||
*/ |
||||
public Quaternion[] getRotations() { |
||||
return rotations.toObjectArray(); |
||||
} |
||||
|
||||
/** |
||||
* @return the array of scales for this track |
||||
*/ |
||||
public Vector3f[] getScales() { |
||||
return scales == null ? null : scales.toObjectArray(); |
||||
} |
||||
|
||||
/** |
||||
* @return the arrays of time for this track |
||||
*/ |
||||
public float[] getTimes() { |
||||
return times; |
||||
} |
||||
|
||||
/** |
||||
* @return the array of translations of this track |
||||
*/ |
||||
public Vector3f[] getTranslations() { |
||||
return translations.toObjectArray(); |
||||
} |
||||
|
||||
@Override |
||||
public void write(JmeExporter ex) throws IOException { |
||||
OutputCapsule oc = ex.getCapsule(this); |
||||
oc.write(translations, "translations", null); |
||||
oc.write(rotations, "rotations", null); |
||||
oc.write(times, "times", null); |
||||
oc.write(scales, "scales", null); |
||||
} |
||||
|
||||
@Override |
||||
public void read(JmeImporter im) throws IOException { |
||||
InputCapsule ic = im.getCapsule(this); |
||||
translations = (CompactVector3Array) ic.readSavable("translations", null); |
||||
rotations = (CompactQuaternionArray) ic.readSavable("rotations", null); |
||||
times = ic.readFloatArray("times", null); |
||||
scales = (CompactVector3Array) ic.readSavable("scales", null); |
||||
} |
||||
} |
@ -0,0 +1,89 @@ |
||||
package jme3test.model.anim; |
||||
|
||||
import java.util.HashMap; |
||||
|
||||
import com.jme3.animation.AnimControl; |
||||
import com.jme3.animation.Animation; |
||||
import com.jme3.animation.SpatialAnimation; |
||||
import com.jme3.animation.SpatialTrack; |
||||
import com.jme3.app.SimpleApplication; |
||||
import com.jme3.light.AmbientLight; |
||||
import com.jme3.light.DirectionalLight; |
||||
import com.jme3.math.Quaternion; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.scene.Geometry; |
||||
import com.jme3.scene.Node; |
||||
import com.jme3.scene.shape.Box; |
||||
|
||||
public class TestSpatialAnim extends SimpleApplication { |
||||
|
||||
public static void main(String[] args) { |
||||
TestSpatialAnim app = new TestSpatialAnim(); |
||||
app.start(); |
||||
} |
||||
|
||||
@Override |
||||
public void simpleInitApp() { |
||||
|
||||
AmbientLight al = new AmbientLight(); |
||||
rootNode.addLight(al); |
||||
|
||||
DirectionalLight dl = new DirectionalLight(); |
||||
dl.setDirection(Vector3f.UNIT_XYZ.negate()); |
||||
rootNode.addLight(dl); |
||||
|
||||
// Create model
|
||||
Box box = new Box(1, 1, 1); |
||||
Geometry geom = new Geometry("box", box); |
||||
geom.setMaterial(assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m")); |
||||
Node model = new Node("model"); |
||||
model.attachChild(geom); |
||||
|
||||
Box child = new Box(0.5f, 0.5f, 0.5f); |
||||
Geometry childGeom = new Geometry("box", child); |
||||
childGeom.setMaterial(assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m")); |
||||
Node childModel = new Node("childmodel"); |
||||
childModel.setLocalTranslation(2, 2, 2); |
||||
childModel.attachChild(childGeom); |
||||
model.attachChild(childModel); |
||||
|
||||
//animation parameters
|
||||
float animTime = 5; |
||||
int fps = 25; |
||||
float totalXLength = 10; |
||||
|
||||
//calculating frames
|
||||
int totalFrames = (int) (fps * animTime); |
||||
float dT = animTime / totalFrames, t = 0; |
||||
float dX = totalXLength / totalFrames, x = 0; |
||||
float[] times = new float[totalFrames]; |
||||
Vector3f[] translations = new Vector3f[totalFrames]; |
||||
Quaternion[] rotations = new Quaternion[totalFrames]; |
||||
Vector3f[] scales = new Vector3f[totalFrames]; |
||||
for (int i = 0; i < totalFrames; ++i) { |
||||
times[i] = t; |
||||
t += dT; |
||||
translations[i] = new Vector3f(x, 0, 0); |
||||
x += dX; |
||||
rotations[i] = Quaternion.IDENTITY; |
||||
scales[i] = Vector3f.UNIT_XYZ; |
||||
} |
||||
SpatialTrack spatialTrack = new SpatialTrack(times, translations, rotations, scales); |
||||
|
||||
//creating the animation
|
||||
SpatialAnimation spatialAnimation = new SpatialAnimation("anim", animTime); |
||||
spatialAnimation.setTrack(spatialTrack); |
||||
|
||||
//create spatial animation control
|
||||
AnimControl control = new AnimControl(); |
||||
HashMap<String, Animation> animations = new HashMap<String, Animation>(); |
||||
animations.put("anim", spatialAnimation); |
||||
control.setAnimations(animations); |
||||
model.addControl(control); |
||||
|
||||
rootNode.attachChild(model); |
||||
|
||||
//run animation
|
||||
control.createChannel().setAnim("anim"); |
||||
} |
||||
} |
Loading…
Reference in new issue