Draft of the new animation system
This commit is contained in:
parent
4040a1e412
commit
0e3ab8dd14
2
.gitignore
vendored
2
.gitignore
vendored
@ -2,7 +2,7 @@
|
|||||||
**/.classpath
|
**/.classpath
|
||||||
**/.settings
|
**/.settings
|
||||||
**/.project
|
**/.project
|
||||||
**/out
|
**/out/
|
||||||
/.gradle/
|
/.gradle/
|
||||||
/.nb-gradle/
|
/.nb-gradle/
|
||||||
/.idea/
|
/.idea/
|
||||||
|
113
jme3-core/src/main/java/com/jme3/anim/AnimClip.java
Normal file
113
jme3-core/src/main/java/com/jme3/anim/AnimClip.java
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
package com.jme3.anim;
|
||||||
|
|
||||||
|
import com.jme3.anim.tween.Tween;
|
||||||
|
import com.jme3.export.*;
|
||||||
|
import com.jme3.util.SafeArrayList;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Nehon on 20/12/2017.
|
||||||
|
*/
|
||||||
|
public class AnimClip implements Tween, JmeCloneable, Savable {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private double length;
|
||||||
|
|
||||||
|
private SafeArrayList<Tween> tracks = new SafeArrayList<>(Tween.class);
|
||||||
|
|
||||||
|
public AnimClip() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnimClip(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTracks(Tween[] tracks) {
|
||||||
|
for (Tween track : tracks) {
|
||||||
|
addTrack(track);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTrack(Tween track) {
|
||||||
|
tracks.add(track);
|
||||||
|
if (track.getLength() > length) {
|
||||||
|
length = track.getLength();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeTrack(Tween track) {
|
||||||
|
if (tracks.remove(track)) {
|
||||||
|
length = 0;
|
||||||
|
for (Tween t : tracks.getArray()) {
|
||||||
|
if (t.getLength() > length) {
|
||||||
|
length = t.getLength();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getLength() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean interpolate(double t) {
|
||||||
|
// Sanity check the inputs
|
||||||
|
if (t < 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Tween track : tracks.getArray()) {
|
||||||
|
track.interpolate(t);
|
||||||
|
}
|
||||||
|
return t <= length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
try {
|
||||||
|
return super.clone();
|
||||||
|
} catch (CloneNotSupportedException e) {
|
||||||
|
throw new RuntimeException("Error cloning", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields(Cloner cloner, Object original) {
|
||||||
|
SafeArrayList<Tween> newTracks = new SafeArrayList<>(Tween.class);
|
||||||
|
for (Tween track : tracks) {
|
||||||
|
newTracks.add(cloner.clone(track));
|
||||||
|
}
|
||||||
|
this.tracks = newTracks;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(JmeExporter ex) throws IOException {
|
||||||
|
OutputCapsule oc = ex.getCapsule(this);
|
||||||
|
oc.write(name, "name", null);
|
||||||
|
oc.write(tracks.getArray(), "tracks", null);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(JmeImporter im) throws IOException {
|
||||||
|
InputCapsule ic = im.getCapsule(this);
|
||||||
|
name = ic.readString("name", null);
|
||||||
|
Savable[] arr = ic.readSavableArray("tracks", null);
|
||||||
|
if (arr != null) {
|
||||||
|
tracks = new SafeArrayList<>(Tween.class);
|
||||||
|
for (Savable savable : arr) {
|
||||||
|
tracks.add((Tween) savable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
83
jme3-core/src/main/java/com/jme3/anim/AnimComposer.java
Normal file
83
jme3-core/src/main/java/com/jme3/anim/AnimComposer.java
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package com.jme3.anim;
|
||||||
|
|
||||||
|
import com.jme3.renderer.RenderManager;
|
||||||
|
import com.jme3.renderer.ViewPort;
|
||||||
|
import com.jme3.scene.control.AbstractControl;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Nehon on 20/12/2017.
|
||||||
|
*/
|
||||||
|
public class AnimComposer extends AbstractControl {
|
||||||
|
|
||||||
|
private Map<String, AnimClip> animClipMap = new HashMap<>();
|
||||||
|
|
||||||
|
private AnimClip currentAnimClip;
|
||||||
|
private float time;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve an animation from the list of animations.
|
||||||
|
*
|
||||||
|
* @param name The name of the animation to retrieve.
|
||||||
|
* @return The animation corresponding to the given name, or null, if no
|
||||||
|
* such named animation exists.
|
||||||
|
*/
|
||||||
|
public AnimClip getAnimClip(String name) {
|
||||||
|
return animClipMap.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an animation to be available for playing to this
|
||||||
|
* <code>AnimControl</code>.
|
||||||
|
*
|
||||||
|
* @param anim The animation to add.
|
||||||
|
*/
|
||||||
|
public void addAnimClip(AnimClip anim) {
|
||||||
|
animClipMap.put(anim.getName(), anim);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove an animation so that it is no longer available for playing.
|
||||||
|
*
|
||||||
|
* @param anim The animation to remove.
|
||||||
|
*/
|
||||||
|
public void removeAnimClip(AnimClip anim) {
|
||||||
|
if (!animClipMap.containsKey(anim.getName())) {
|
||||||
|
throw new IllegalArgumentException("Given animation does not exist "
|
||||||
|
+ "in this AnimControl");
|
||||||
|
}
|
||||||
|
|
||||||
|
animClipMap.remove(anim.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentAnimClip(String name) {
|
||||||
|
currentAnimClip = animClipMap.get(name);
|
||||||
|
time = 0;
|
||||||
|
if (currentAnimClip == null) {
|
||||||
|
throw new IllegalArgumentException("Unknown clip " + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
currentAnimClip = null;
|
||||||
|
time = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void controlUpdate(float tpf) {
|
||||||
|
if (currentAnimClip != null) {
|
||||||
|
time += tpf;
|
||||||
|
boolean running = currentAnimClip.interpolate(time);
|
||||||
|
if (!running) {
|
||||||
|
time -= currentAnimClip.getLength();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void controlRender(RenderManager rm, ViewPort vp) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,7 @@
|
|||||||
package com.jme3.animation;
|
package com.jme3.anim;
|
||||||
|
|
||||||
import com.jme3.export.*;
|
import com.jme3.export.*;
|
||||||
import com.jme3.math.Matrix4f;
|
import com.jme3.math.Matrix4f;
|
||||||
import com.jme3.util.TempVars;
|
|
||||||
import com.jme3.util.clone.Cloner;
|
import com.jme3.util.clone.Cloner;
|
||||||
import com.jme3.util.clone.JmeCloneable;
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
|
|
||||||
@ -60,33 +59,6 @@ public class Armature implements JmeCloneable, Savable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * Special-purpose copy constructor.
|
|
||||||
// * <p>
|
|
||||||
// * Shallow copies bind pose data from the source skeleton, does not
|
|
||||||
// * copy any other data.
|
|
||||||
// *
|
|
||||||
// * @param source The source Skeleton to copy from
|
|
||||||
// */
|
|
||||||
// public Armature(Armature source) {
|
|
||||||
// Joint[] sourceList = source.jointList;
|
|
||||||
// jointList = new Joint[sourceList.length];
|
|
||||||
// for (int i = 0; i < sourceList.length; i++) {
|
|
||||||
// jointList[i] = new Joint(sourceList[i]);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// rootJoints = new Bone[source.rootJoints.length];
|
|
||||||
// for (int i = 0; i < rootJoints.length; i++) {
|
|
||||||
// rootJoints[i] = recreateBoneStructure(source.rootJoints[i]);
|
|
||||||
// }
|
|
||||||
// createSkinningMatrices();
|
|
||||||
//
|
|
||||||
// for (int i = rootJoints.length - 1; i >= 0; i--) {
|
|
||||||
// rootJoints[i].update();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update all joints sin this Amature.
|
* Update all joints sin this Amature.
|
||||||
*/
|
*/
|
||||||
@ -176,8 +148,18 @@ public class Armature implements JmeCloneable, Savable {
|
|||||||
//make sure all bones are updated
|
//make sure all bones are updated
|
||||||
update();
|
update();
|
||||||
//Save the current pose as bind pose
|
//Save the current pose as bind pose
|
||||||
for (Joint rootJoint : rootJoints) {
|
for (Joint joint : jointList) {
|
||||||
rootJoint.setBindPose();
|
joint.setBindPose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This methods sets this armature in its bind pose (aligned with the undeformed mesh)
|
||||||
|
* Note that this is only useful for debugging porpose.
|
||||||
|
*/
|
||||||
|
public void resetToBindPose() {
|
||||||
|
for (Joint joint : rootJoints) {
|
||||||
|
joint.resetToBindPose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,11 +169,9 @@ public class Armature implements JmeCloneable, Savable {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Matrix4f[] computeSkinningMatrices() {
|
public Matrix4f[] computeSkinningMatrices() {
|
||||||
TempVars vars = TempVars.get();
|
|
||||||
for (int i = 0; i < jointList.length; i++) {
|
for (int i = 0; i < jointList.length; i++) {
|
||||||
jointList[i].getOffsetTransform(skinningMatrixes[i], vars.quat1, vars.vect1, vars.vect2, vars.tempMat3);
|
jointList[i].getOffsetTransform(skinningMatrixes[i]);
|
||||||
}
|
}
|
||||||
vars.release();
|
|
||||||
return skinningMatrixes;
|
return skinningMatrixes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,5 +227,4 @@ public class Armature implements JmeCloneable, Savable {
|
|||||||
output.write(rootJoints, "rootJoints", null);
|
output.write(rootJoints, "rootJoints", null);
|
||||||
output.write(jointList, "jointList", null);
|
output.write(jointList, "jointList", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package com.jme3.animation;
|
package com.jme3.anim;
|
||||||
|
|
||||||
import com.jme3.export.*;
|
import com.jme3.export.*;
|
||||||
import com.jme3.material.MatParamOverride;
|
import com.jme3.material.MatParamOverride;
|
||||||
@ -23,13 +23,6 @@ public class Joint implements Savable, JmeCloneable {
|
|||||||
private ArrayList<Joint> children = new ArrayList<>();
|
private ArrayList<Joint> children = new ArrayList<>();
|
||||||
private Geometry targetGeometry;
|
private Geometry targetGeometry;
|
||||||
|
|
||||||
public Joint() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public Joint(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The attachment node.
|
* The attachment node.
|
||||||
*/
|
*/
|
||||||
@ -43,29 +36,37 @@ public class Joint implements Savable, JmeCloneable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The base transform of the joint in local space.
|
* The base transform of the joint in local space.
|
||||||
* Those transform are the bone's initial value.
|
* Those transform are the joint's initial value.
|
||||||
*/
|
*/
|
||||||
private Transform baseLocalTransform = new Transform();
|
private Transform baseLocalTransform = new Transform();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The transform of the bone in model space. Relative to the origin of the model.
|
* The transform of the joint in model space. Relative to the origin of the model.
|
||||||
*/
|
*/
|
||||||
private Transform modelTransform = new Transform();
|
private Transform modelTransform = new Transform();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The matrix used to transform affected vertices position into the bone model space.
|
* The matrix used to transform affected vertices position into the joint model space.
|
||||||
* Used for skinning.
|
* Used for skinning.
|
||||||
*/
|
*/
|
||||||
private Matrix4f inverseModelBindMatrix = new Matrix4f();
|
private Matrix4f inverseModelBindMatrix = new Matrix4f();
|
||||||
|
|
||||||
|
|
||||||
|
public Joint() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Joint(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates world transforms for this bone and it's children.
|
* Updates world transforms for this bone and it's children.
|
||||||
*/
|
*/
|
||||||
public final void update() {
|
public final void update() {
|
||||||
this.updateModelTransforms();
|
this.updateModelTransforms();
|
||||||
|
|
||||||
for (int i = children.size() - 1; i >= 0; i--) {
|
for (Joint child : children) {
|
||||||
children.get(i).update();
|
child.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +129,7 @@ public class Joint implements Savable, JmeCloneable {
|
|||||||
*
|
*
|
||||||
* @param outTransform
|
* @param outTransform
|
||||||
*/
|
*/
|
||||||
void getOffsetTransform(Matrix4f outTransform, Quaternion tmp1, Vector3f tmp2, Vector3f tmp3, Matrix3f tmp4) {
|
void getOffsetTransform(Matrix4f outTransform) {
|
||||||
modelTransform.toTransformMatrix(outTransform).mult(inverseModelBindMatrix, outTransform);
|
modelTransform.toTransformMatrix(outTransform).mult(inverseModelBindMatrix, outTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,6 +137,19 @@ public class Joint implements Savable, JmeCloneable {
|
|||||||
//Note that the whole Armature must be updated before calling this method.
|
//Note that the whole Armature must be updated before calling this method.
|
||||||
modelTransform.toTransformMatrix(inverseModelBindMatrix);
|
modelTransform.toTransformMatrix(inverseModelBindMatrix);
|
||||||
inverseModelBindMatrix.invertLocal();
|
inverseModelBindMatrix.invertLocal();
|
||||||
|
baseLocalTransform.set(localTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void resetToBindPose() {
|
||||||
|
localTransform.fromTransformMatrix(inverseModelBindMatrix.invert()); // local = modelBind
|
||||||
|
if (parent != null) {
|
||||||
|
localTransform.combineWithParent(parent.modelTransform.invert()); // local = local Bind
|
||||||
|
}
|
||||||
|
updateModelTransforms();
|
||||||
|
|
||||||
|
for (Joint child : children) {
|
||||||
|
child.resetToBindPose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3f getLocalTranslation() {
|
public Vector3f getLocalTranslation() {
|
113
jme3-core/src/main/java/com/jme3/anim/JointTrack.java
Normal file
113
jme3-core/src/main/java/com/jme3/anim/JointTrack.java
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.anim;
|
||||||
|
|
||||||
|
import com.jme3.export.*;
|
||||||
|
import com.jme3.math.*;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains a list of transforms and times for each keyframe.
|
||||||
|
*
|
||||||
|
* @author Rémy Bouquet
|
||||||
|
*/
|
||||||
|
public final class JointTrack extends TransformTrack implements JmeCloneable, Savable {
|
||||||
|
|
||||||
|
private Joint target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialization-only. Do not use.
|
||||||
|
*/
|
||||||
|
public JointTrack() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a bone track for the given bone index
|
||||||
|
*
|
||||||
|
* @param target The Joint target of 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 JointTrack(Joint target, float[] times, Vector3f[] translations, Quaternion[] rotations, Vector3f[] scales) {
|
||||||
|
super(times, translations, rotations, scales);
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean interpolate(double t) {
|
||||||
|
setDefaultTransform(target.getLocalTransform());
|
||||||
|
boolean running = super.interpolate(t);
|
||||||
|
Transform transform = getInterpolatedTransform();
|
||||||
|
target.setLocalTransform(transform);
|
||||||
|
return running;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTarget(Joint target) {
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
try {
|
||||||
|
return super.clone();
|
||||||
|
} catch (CloneNotSupportedException e) {
|
||||||
|
throw new RuntimeException("Error cloning", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields(Cloner cloner, Object original) {
|
||||||
|
super.cloneFields(cloner, original);
|
||||||
|
this.target = cloner.clone(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(JmeExporter ex) throws IOException {
|
||||||
|
super.write(ex);
|
||||||
|
OutputCapsule oc = ex.getCapsule(this);
|
||||||
|
oc.write(target, "target", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(JmeImporter im) throws IOException {
|
||||||
|
super.read(im);
|
||||||
|
InputCapsule ic = im.getCapsule(this);
|
||||||
|
target = (Joint) ic.readSavable("target", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -29,7 +29,7 @@
|
|||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
package com.jme3.animation;
|
package com.jme3.anim;
|
||||||
|
|
||||||
import com.jme3.export.*;
|
import com.jme3.export.*;
|
||||||
import com.jme3.material.MatParamOverride;
|
import com.jme3.material.MatParamOverride;
|
||||||
@ -53,15 +53,17 @@ import java.util.logging.Level;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Skeleton control deforms a model according to a armature, It handles the
|
* The Skinning control deforms a model according to an armature, It handles the
|
||||||
* computation of the deformation matrices and performs the transformations on
|
* computation of the deformation matrices and performs the transformations on
|
||||||
* the mesh
|
* the mesh
|
||||||
|
* <p>
|
||||||
|
* It can perform software skinning or Hardware skinning
|
||||||
*
|
*
|
||||||
* @author Rémy Bouquet Based on AnimControl by Kirill Vainer
|
* @author Rémy Bouquet Based on SkeletonControl by Kirill Vainer
|
||||||
*/
|
*/
|
||||||
public class ArmatureControl extends AbstractControl implements Cloneable, JmeCloneable {
|
public class SkinningControl extends AbstractControl implements Cloneable, JmeCloneable {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(ArmatureControl.class.getName());
|
private static final Logger logger = Logger.getLogger(SkinningControl.class.getName());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The armature of the model.
|
* The armature of the model.
|
||||||
@ -71,7 +73,7 @@ public class ArmatureControl extends AbstractControl implements Cloneable, JmeCl
|
|||||||
/**
|
/**
|
||||||
* List of geometries affected by this control.
|
* List of geometries affected by this control.
|
||||||
*/
|
*/
|
||||||
private SafeArrayList<Geometry> targets = new SafeArrayList<Geometry>(Geometry.class);
|
private SafeArrayList<Geometry> targets = new SafeArrayList<>(Geometry.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to track when a mesh was updated. Meshes are only updated if they
|
* Used to track when a mesh was updated. Meshes are only updated if they
|
||||||
@ -113,16 +115,16 @@ public class ArmatureControl extends AbstractControl implements Cloneable, JmeCl
|
|||||||
/**
|
/**
|
||||||
* Serialization only. Do not use.
|
* Serialization only. Do not use.
|
||||||
*/
|
*/
|
||||||
public ArmatureControl() {
|
public SkinningControl() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a armature control. The list of targets will be acquired
|
* Creates a armature control. The list of targets will be acquired
|
||||||
* automatically when the control is attached to a node.
|
* automatically when the control is attached to a node.
|
||||||
*
|
*
|
||||||
* @param skeleton the armature
|
* @param armature the armature
|
||||||
*/
|
*/
|
||||||
public ArmatureControl(Armature armature) {
|
public SkinningControl(Armature armature) {
|
||||||
if (armature == null) {
|
if (armature == null) {
|
||||||
throw new IllegalArgumentException("armature cannot be null");
|
throw new IllegalArgumentException("armature cannot be null");
|
||||||
}
|
}
|
||||||
@ -283,7 +285,7 @@ public class ArmatureControl extends AbstractControl implements Cloneable, JmeCl
|
|||||||
if (hwSkinningSupported) {
|
if (hwSkinningSupported) {
|
||||||
hwSkinningEnabled = true;
|
hwSkinningEnabled = true;
|
||||||
|
|
||||||
Logger.getLogger(ArmatureControl.class.getName()).log(Level.INFO, "Hardware skinning engaged for {0}", spatial);
|
Logger.getLogger(SkinningControl.class.getName()).log(Level.INFO, "Hardware skinning engaged for {0}", spatial);
|
||||||
} else {
|
} else {
|
||||||
switchToSoftware();
|
switchToSoftware();
|
||||||
}
|
}
|
||||||
@ -308,6 +310,7 @@ public class ArmatureControl extends AbstractControl implements Cloneable, JmeCl
|
|||||||
@Override
|
@Override
|
||||||
protected void controlUpdate(float tpf) {
|
protected void controlUpdate(float tpf) {
|
||||||
wasMeshUpdated = false;
|
wasMeshUpdated = false;
|
||||||
|
armature.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
//only do this for software updates
|
//only do this for software updates
|
||||||
@ -558,9 +561,8 @@ public class ArmatureControl extends AbstractControl implements Cloneable, JmeCl
|
|||||||
* has additional indexes since tangent has 4 components instead of 3 for
|
* has additional indexes since tangent has 4 components instead of 3 for
|
||||||
* pos and norm
|
* pos and norm
|
||||||
*
|
*
|
||||||
* @param maxWeightsPerVert maximum number of weights per vertex
|
|
||||||
* @param mesh the mesh
|
* @param mesh the mesh
|
||||||
* @param offsetMatrices the offsetMaytrices to apply
|
* @param offsetMatrices the offsetMatrices to apply
|
||||||
* @param tb the tangent vertexBuffer
|
* @param tb the tangent vertexBuffer
|
||||||
*/
|
*/
|
||||||
private void applySkinningTangents(Mesh mesh, Matrix4f[] offsetMatrices, VertexBuffer tb) {
|
private void applySkinningTangents(Mesh mesh, Matrix4f[] offsetMatrices, VertexBuffer tb) {
|
344
jme3-core/src/main/java/com/jme3/anim/TransformTrack.java
Normal file
344
jme3-core/src/main/java/com/jme3/anim/TransformTrack.java
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.anim;
|
||||||
|
|
||||||
|
import com.jme3.anim.interpolator.FrameInterpolator;
|
||||||
|
import com.jme3.anim.tween.Tween;
|
||||||
|
import com.jme3.animation.CompactQuaternionArray;
|
||||||
|
import com.jme3.animation.CompactVector3Array;
|
||||||
|
import com.jme3.export.*;
|
||||||
|
import com.jme3.math.*;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains a list of transforms and times for each keyframe.
|
||||||
|
*
|
||||||
|
* @author Rémy Bouquet
|
||||||
|
*/
|
||||||
|
public abstract class TransformTrack implements Tween, JmeCloneable, Savable {
|
||||||
|
|
||||||
|
private double length;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms and times for track.
|
||||||
|
*/
|
||||||
|
private CompactVector3Array translations;
|
||||||
|
private CompactQuaternionArray rotations;
|
||||||
|
private CompactVector3Array scales;
|
||||||
|
private Transform transform = new Transform();
|
||||||
|
private Transform defaultTransform = new Transform();
|
||||||
|
private FrameInterpolator interpolator = FrameInterpolator.DEFAULT;
|
||||||
|
private float[] times;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialization-only. Do not use.
|
||||||
|
*/
|
||||||
|
public TransformTrack() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a transform track for the given bone index
|
||||||
|
*
|
||||||
|
* @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 TransformTrack(float[] times, Vector3f[] translations, Quaternion[] rotations, Vector3f[] scales) {
|
||||||
|
this.setKeyframes(times, translations, rotations, scales);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a bone track for the given bone index
|
||||||
|
*
|
||||||
|
* @param targetJointIndex the bone's index
|
||||||
|
*/
|
||||||
|
public TransformTrack(int targetJointIndex) {
|
||||||
|
this();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the array of rotations of this track
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Quaternion[] getRotations() {
|
||||||
|
return rotations.toObjectArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the array of scales for this track
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Vector3f[] getScales() {
|
||||||
|
return scales == null ? null : scales.toObjectArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the arrays of time for this track
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float[] getTimes() {
|
||||||
|
return times;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the array of translations of this track
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Vector3f[] getTranslations() {
|
||||||
|
return translations.toObjectArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the keyframes times for this Joint track
|
||||||
|
*
|
||||||
|
* @param times the keyframes times
|
||||||
|
*/
|
||||||
|
public void setTimes(float[] times) {
|
||||||
|
if (times.length == 0) {
|
||||||
|
throw new RuntimeException("TransformTrack with no keyframes!");
|
||||||
|
}
|
||||||
|
this.times = times;
|
||||||
|
length = times[times.length - 1] - times[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the translations for this joint track
|
||||||
|
*
|
||||||
|
* @param translations the translation of the bone for each frame
|
||||||
|
*/
|
||||||
|
public void setKeyframesTranslation(Vector3f[] translations) {
|
||||||
|
if (times == null) {
|
||||||
|
throw new RuntimeException("TransformTrack doesn't have any time for key frames, please call setTimes first");
|
||||||
|
}
|
||||||
|
if (translations.length == 0) {
|
||||||
|
throw new RuntimeException("TransformTrack with no translation keyframes!");
|
||||||
|
}
|
||||||
|
this.translations = new CompactVector3Array();
|
||||||
|
this.translations.add(translations);
|
||||||
|
this.translations.freeze();
|
||||||
|
|
||||||
|
assert times != null && times.length == translations.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the scales for this joint track
|
||||||
|
*
|
||||||
|
* @param scales the scales of the bone for each frame
|
||||||
|
*/
|
||||||
|
public void setKeyframesScale(Vector3f[] scales) {
|
||||||
|
if (times == null) {
|
||||||
|
throw new RuntimeException("TransformTrack doesn't have any time for key frames, please call setTimes first");
|
||||||
|
}
|
||||||
|
if (scales.length == 0) {
|
||||||
|
throw new RuntimeException("TransformTrack with no scale keyframes!");
|
||||||
|
}
|
||||||
|
this.scales = new CompactVector3Array();
|
||||||
|
this.scales.add(scales);
|
||||||
|
this.scales.freeze();
|
||||||
|
|
||||||
|
assert times != null && times.length == scales.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the rotations for this joint track
|
||||||
|
*
|
||||||
|
* @param rotations the rotations of the bone for each frame
|
||||||
|
*/
|
||||||
|
public void setKeyframesRotation(Quaternion[] rotations) {
|
||||||
|
if (times == null) {
|
||||||
|
throw new RuntimeException("TransformTrack doesn't have any time for key frames, please call setTimes first");
|
||||||
|
}
|
||||||
|
if (rotations.length == 0) {
|
||||||
|
throw new RuntimeException("TransformTrack with no rotation keyframes!");
|
||||||
|
}
|
||||||
|
this.rotations = new CompactQuaternionArray();
|
||||||
|
this.rotations.add(rotations);
|
||||||
|
this.rotations.freeze();
|
||||||
|
|
||||||
|
assert times != null && times.length == rotations.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the translations, rotations and scales for this bone 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) {
|
||||||
|
setTimes(times);
|
||||||
|
if (translations != null) {
|
||||||
|
setKeyframesTranslation(translations);
|
||||||
|
}
|
||||||
|
if (rotations != null) {
|
||||||
|
setKeyframesRotation(rotations);
|
||||||
|
}
|
||||||
|
if (scales != null) {
|
||||||
|
setKeyframesScale(scales);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getLength() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean interpolate(double t) {
|
||||||
|
float time = (float) t;
|
||||||
|
|
||||||
|
transform.set(defaultTransform);
|
||||||
|
int lastFrame = times.length - 1;
|
||||||
|
if (time < 0 || lastFrame == 0) {
|
||||||
|
if (translations != null) {
|
||||||
|
translations.get(0, transform.getTranslation());
|
||||||
|
}
|
||||||
|
if (rotations != null) {
|
||||||
|
rotations.get(0, transform.getRotation());
|
||||||
|
}
|
||||||
|
if (scales != null) {
|
||||||
|
scales.get(0, transform.getScale());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int startFrame = 0;
|
||||||
|
int endFrame = 1;
|
||||||
|
float blend = 0;
|
||||||
|
if (time >= times[lastFrame]) {
|
||||||
|
startFrame = lastFrame;
|
||||||
|
|
||||||
|
time = time - times[startFrame] + times[startFrame - 1];
|
||||||
|
blend = (time - times[startFrame - 1])
|
||||||
|
/ (times[startFrame] - times[startFrame - 1]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// use lastFrame so we never overflow the array
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < lastFrame && times[i] < time; i++) {
|
||||||
|
startFrame = i;
|
||||||
|
endFrame = i + 1;
|
||||||
|
}
|
||||||
|
blend = (time - times[startFrame])
|
||||||
|
/ (times[endFrame] - times[startFrame]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform interpolated = interpolator.interpolate(blend, startFrame, translations, rotations, scales, times);
|
||||||
|
|
||||||
|
if (translations != null) {
|
||||||
|
transform.setTranslation(interpolated.getTranslation());
|
||||||
|
}
|
||||||
|
if (rotations != null) {
|
||||||
|
transform.setRotation(interpolated.getRotation());
|
||||||
|
}
|
||||||
|
if (scales != null) {
|
||||||
|
transform.setScale(interpolated.getScale());
|
||||||
|
}
|
||||||
|
|
||||||
|
return time < length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Transform getInterpolatedTransform() {
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultTransform(Transform transforms) {
|
||||||
|
defaultTransform.set(transforms);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFrameInterpolator(FrameInterpolator interpolator) {
|
||||||
|
this.interpolator = interpolator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
try {
|
||||||
|
return super.clone();
|
||||||
|
} catch (CloneNotSupportedException e) {
|
||||||
|
throw new RuntimeException("Error cloning", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields(Cloner cloner, Object original) {
|
||||||
|
int tablesLength = times.length;
|
||||||
|
|
||||||
|
times = this.times.clone();
|
||||||
|
Vector3f[] sourceTranslations = this.getTranslations();
|
||||||
|
Quaternion[] sourceRotations = this.getRotations();
|
||||||
|
Vector3f[] sourceScales = this.getScales();
|
||||||
|
|
||||||
|
Vector3f[] translations = new Vector3f[tablesLength];
|
||||||
|
Quaternion[] rotations = new Quaternion[tablesLength];
|
||||||
|
Vector3f[] scales = new Vector3f[tablesLength];
|
||||||
|
for (int i = 0; i < tablesLength; ++i) {
|
||||||
|
translations[i] = sourceTranslations[i].clone();
|
||||||
|
rotations[i] = sourceRotations[i].clone();
|
||||||
|
scales[i] = sourceScales != null ? sourceScales[i].clone() : new Vector3f(1.0f, 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
setKeyframesTranslation(translations);
|
||||||
|
setKeyframesScale(scales);
|
||||||
|
setKeyframesRotation(rotations);
|
||||||
|
setFrameInterpolator(this.interpolator);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.jme3.anim.interpolator;
|
||||||
|
|
||||||
|
import static com.jme3.anim.interpolator.FrameInterpolator.TrackDataReader;
|
||||||
|
import static com.jme3.anim.interpolator.FrameInterpolator.TrackTimeReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by nehon on 15/04/17.
|
||||||
|
*/
|
||||||
|
public abstract class AnimInterpolator<T> {
|
||||||
|
|
||||||
|
public abstract T interpolate(float t, int currentIndex, TrackDataReader<T> data, TrackTimeReader times, T store);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,151 @@
|
|||||||
|
package com.jme3.anim.interpolator;
|
||||||
|
|
||||||
|
import com.jme3.math.*;
|
||||||
|
|
||||||
|
import static com.jme3.anim.interpolator.FrameInterpolator.TrackDataReader;
|
||||||
|
import static com.jme3.anim.interpolator.FrameInterpolator.TrackTimeReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by nehon on 15/04/17.
|
||||||
|
*/
|
||||||
|
public class AnimInterpolators {
|
||||||
|
|
||||||
|
//Rotation interpolators
|
||||||
|
|
||||||
|
public static final AnimInterpolator<Quaternion> NLerp = new AnimInterpolator<Quaternion>() {
|
||||||
|
private Quaternion next = new Quaternion();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Quaternion interpolate(float t, int currentIndex, TrackDataReader<Quaternion> data, TrackTimeReader times, Quaternion store) {
|
||||||
|
data.getEntryClamp(currentIndex, store);
|
||||||
|
data.getEntryClamp(currentIndex + 1, next);
|
||||||
|
store.nlerp(next, t);
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final AnimInterpolator<Quaternion> SLerp = new AnimInterpolator<Quaternion>() {
|
||||||
|
private Quaternion next = new Quaternion();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Quaternion interpolate(float t, int currentIndex, TrackDataReader<Quaternion> data, TrackTimeReader times, Quaternion store) {
|
||||||
|
data.getEntryClamp(currentIndex, store);
|
||||||
|
data.getEntryClamp(currentIndex + 1, next);
|
||||||
|
//MathUtils.slerpNoInvert(store, next, t, store);
|
||||||
|
MathUtils.slerp(store, next, t, store);
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final AnimInterpolator<Quaternion> SQuad = new AnimInterpolator<Quaternion>() {
|
||||||
|
private Quaternion a = new Quaternion();
|
||||||
|
private Quaternion b = new Quaternion();
|
||||||
|
|
||||||
|
private Quaternion q0 = new Quaternion();
|
||||||
|
private Quaternion q1 = new Quaternion();
|
||||||
|
private Quaternion q2 = new Quaternion();
|
||||||
|
private Quaternion q3 = new Quaternion();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Quaternion interpolate(float t, int currentIndex, TrackDataReader<Quaternion> data, TrackTimeReader times, Quaternion store) {
|
||||||
|
data.getEntryModSkip(currentIndex - 1, q0);
|
||||||
|
data.getEntryModSkip(currentIndex, q1);
|
||||||
|
data.getEntryModSkip(currentIndex + 1, q2);
|
||||||
|
data.getEntryModSkip(currentIndex + 2, q3);
|
||||||
|
MathUtils.squad(q0, q1, q2, q3, a, b, t, store);
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Position / Scale interpolators
|
||||||
|
|
||||||
|
public static final AnimInterpolator<Vector3f> LinearVec3f = new AnimInterpolator<Vector3f>() {
|
||||||
|
private Vector3f next = new Vector3f();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector3f interpolate(float t, int currentIndex, TrackDataReader<Vector3f> data, TrackTimeReader times, Vector3f store) {
|
||||||
|
data.getEntryClamp(currentIndex, store);
|
||||||
|
data.getEntryClamp(currentIndex + 1, next);
|
||||||
|
store.interpolateLocal(next, t);
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CatmullRom interpolation
|
||||||
|
*/
|
||||||
|
public static final CatmullRomInterpolator CatmullRom = new CatmullRomInterpolator();
|
||||||
|
|
||||||
|
public static class CatmullRomInterpolator extends AnimInterpolator<Vector3f> {
|
||||||
|
private Vector3f p0 = new Vector3f();
|
||||||
|
private Vector3f p1 = new Vector3f();
|
||||||
|
private Vector3f p2 = new Vector3f();
|
||||||
|
private Vector3f p3 = new Vector3f();
|
||||||
|
private float tension = 0.7f;
|
||||||
|
|
||||||
|
public CatmullRomInterpolator(float tension) {
|
||||||
|
this.tension = tension;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CatmullRomInterpolator() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector3f interpolate(float t, int currentIndex, TrackDataReader<Vector3f> data, TrackTimeReader times, Vector3f store) {
|
||||||
|
data.getEntryModSkip(currentIndex - 1, p0);
|
||||||
|
data.getEntryModSkip(currentIndex, p1);
|
||||||
|
data.getEntryModSkip(currentIndex + 1, p2);
|
||||||
|
data.getEntryModSkip(currentIndex + 2, p3);
|
||||||
|
|
||||||
|
FastMath.interpolateCatmullRom(t, tension, p0, p1, p2, p3, store);
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Time Interpolators
|
||||||
|
|
||||||
|
public static class TimeInterpolator extends AnimInterpolator<Float> {
|
||||||
|
private EaseFunction ease;
|
||||||
|
|
||||||
|
public TimeInterpolator(EaseFunction ease) {
|
||||||
|
this.ease = ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float interpolate(float t, int currentIndex, TrackDataReader<Float> data, TrackTimeReader times, Float store) {
|
||||||
|
return ease.apply(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//in
|
||||||
|
public static final TimeInterpolator easeInQuad = new TimeInterpolator(Easing.inQuad);
|
||||||
|
public static final TimeInterpolator easeInCubic = new TimeInterpolator(Easing.inCubic);
|
||||||
|
public static final TimeInterpolator easeInQuart = new TimeInterpolator(Easing.inQuart);
|
||||||
|
public static final TimeInterpolator easeInQuint = new TimeInterpolator(Easing.inQuint);
|
||||||
|
public static final TimeInterpolator easeInBounce = new TimeInterpolator(Easing.inBounce);
|
||||||
|
public static final TimeInterpolator easeInElastic = new TimeInterpolator(Easing.inElastic);
|
||||||
|
|
||||||
|
//out
|
||||||
|
public static final TimeInterpolator easeOutQuad = new TimeInterpolator(Easing.outQuad);
|
||||||
|
public static final TimeInterpolator easeOutCubic = new TimeInterpolator(Easing.outCubic);
|
||||||
|
public static final TimeInterpolator easeOutQuart = new TimeInterpolator(Easing.outQuart);
|
||||||
|
public static final TimeInterpolator easeOutQuint = new TimeInterpolator(Easing.outQuint);
|
||||||
|
public static final TimeInterpolator easeOutBounce = new TimeInterpolator(Easing.outBounce);
|
||||||
|
public static final TimeInterpolator easeOutElastic = new TimeInterpolator(Easing.outElastic);
|
||||||
|
|
||||||
|
//inout
|
||||||
|
public static final TimeInterpolator easeInOutQuad = new TimeInterpolator(Easing.inOutQuad);
|
||||||
|
public static final TimeInterpolator easeInOutCubic = new TimeInterpolator(Easing.inOutCubic);
|
||||||
|
public static final TimeInterpolator easeInOutQuart = new TimeInterpolator(Easing.inOutQuart);
|
||||||
|
public static final TimeInterpolator easeInOutQuint = new TimeInterpolator(Easing.inOutQuint);
|
||||||
|
public static final TimeInterpolator easeInOutBounce = new TimeInterpolator(Easing.inOutBounce);
|
||||||
|
public static final TimeInterpolator easeInOutElastic = new TimeInterpolator(Easing.inOutElastic);
|
||||||
|
|
||||||
|
//extra
|
||||||
|
public static final TimeInterpolator smoothStep = new TimeInterpolator(Easing.smoothStep);
|
||||||
|
public static final TimeInterpolator smootherStep = new TimeInterpolator(Easing.smootherStep);
|
||||||
|
|
||||||
|
public static final TimeInterpolator constant = new TimeInterpolator(Easing.constant);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,121 @@
|
|||||||
|
package com.jme3.anim.interpolator;
|
||||||
|
|
||||||
|
import com.jme3.animation.*;
|
||||||
|
import com.jme3.math.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by nehon on 15/04/17.
|
||||||
|
*/
|
||||||
|
public class FrameInterpolator {
|
||||||
|
|
||||||
|
public static final FrameInterpolator DEFAULT = new FrameInterpolator();
|
||||||
|
|
||||||
|
private AnimInterpolator<Float> timeInterpolator;
|
||||||
|
private AnimInterpolator<Vector3f> translationInterpolator = AnimInterpolators.LinearVec3f;
|
||||||
|
private AnimInterpolator<Quaternion> rotationInterpolator = AnimInterpolators.NLerp;
|
||||||
|
private AnimInterpolator<Vector3f> scaleInterpolator = AnimInterpolators.LinearVec3f;
|
||||||
|
|
||||||
|
private TrackDataReader<Vector3f> translationReader = new TrackDataReader<>();
|
||||||
|
private TrackDataReader<Quaternion> rotationReader = new TrackDataReader<>();
|
||||||
|
private TrackDataReader<Vector3f> scaleReader = new TrackDataReader<>();
|
||||||
|
private TrackTimeReader timesReader = new TrackTimeReader();
|
||||||
|
|
||||||
|
private Transform transforms = new Transform();
|
||||||
|
|
||||||
|
public Transform interpolate(float t, int currentIndex, CompactVector3Array translations, CompactQuaternionArray rotations, CompactVector3Array scales, float[] times){
|
||||||
|
timesReader.setData(times);
|
||||||
|
if( timeInterpolator != null){
|
||||||
|
t = timeInterpolator.interpolate(t,currentIndex, null, timesReader, null );
|
||||||
|
}
|
||||||
|
if(translations != null) {
|
||||||
|
translationReader.setData(translations);
|
||||||
|
translationInterpolator.interpolate(t, currentIndex, translationReader, timesReader, transforms.getTranslation());
|
||||||
|
}
|
||||||
|
if(rotations != null) {
|
||||||
|
rotationReader.setData(rotations);
|
||||||
|
rotationInterpolator.interpolate(t, currentIndex, rotationReader, timesReader, transforms.getRotation());
|
||||||
|
}
|
||||||
|
if(scales != null){
|
||||||
|
scaleReader.setData(scales);
|
||||||
|
scaleInterpolator.interpolate(t, currentIndex, scaleReader, timesReader, transforms.getScale());
|
||||||
|
}
|
||||||
|
return transforms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimeInterpolator(AnimInterpolator<Float> timeInterpolator) {
|
||||||
|
this.timeInterpolator = timeInterpolator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTranslationInterpolator(AnimInterpolator<Vector3f> translationInterpolator) {
|
||||||
|
this.translationInterpolator = translationInterpolator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRotationInterpolator(AnimInterpolator<Quaternion> rotationInterpolator) {
|
||||||
|
this.rotationInterpolator = rotationInterpolator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScaleInterpolator(AnimInterpolator<Vector3f> scaleInterpolator) {
|
||||||
|
this.scaleInterpolator = scaleInterpolator;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class TrackTimeReader {
|
||||||
|
private float[] data;
|
||||||
|
|
||||||
|
protected void setData(float[] data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getEntry(int index) {
|
||||||
|
return data[mod(index, data.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLength() {
|
||||||
|
return data.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TrackDataReader<T> {
|
||||||
|
|
||||||
|
private CompactArray<T> data;
|
||||||
|
|
||||||
|
protected void setData(CompactArray<T> data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getEntryMod(int index, T store) {
|
||||||
|
return data.get(mod(index, data.getTotalObjectSize()), store);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getEntryClamp(int index, T store) {
|
||||||
|
index = (int) FastMath.clamp(index, 0, data.getTotalObjectSize() - 1);
|
||||||
|
return data.get(index, store);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getEntryModSkip(int index, T store) {
|
||||||
|
int total = data.getTotalObjectSize();
|
||||||
|
if (index == -1) {
|
||||||
|
index--;
|
||||||
|
} else if (index >= total) {
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = mod(index, total);
|
||||||
|
|
||||||
|
|
||||||
|
return data.get(index, store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Euclidean modulo (cycle on 0,n instead of -n,0; 0,n)
|
||||||
|
*
|
||||||
|
* @param val
|
||||||
|
* @param n
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static int mod(int val, int n) {
|
||||||
|
return ((val % n) + n) % n;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
110
jme3-core/src/main/java/com/jme3/anim/tween/AbstractTween.java
Normal file
110
jme3-core/src/main/java/com/jme3/anim/tween/AbstractTween.java
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015, Simsilica, LLC
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.jme3.anim.tween;
|
||||||
|
|
||||||
|
|
||||||
|
import com.jme3.export.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base implementation of the Tween interface that provides
|
||||||
|
* default implementations of the getLength() and interopolate()
|
||||||
|
* methods that provide common tween clamping and bounds checking.
|
||||||
|
* Subclasses need only override the doInterpolate() method and
|
||||||
|
* the rest is handled for them.
|
||||||
|
*
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public abstract class AbstractTween implements Tween {
|
||||||
|
|
||||||
|
private double length;
|
||||||
|
|
||||||
|
protected AbstractTween(double length) {
|
||||||
|
this.length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getLength() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLength(double length) {
|
||||||
|
this.length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation clamps the time value, converts
|
||||||
|
* it to 0 to 1.0 based on getLength(), and calls doInterpolate().
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean interpolate(double t) {
|
||||||
|
if (t < 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale t to be between 0 and 1 for our length
|
||||||
|
if (length == 0) {
|
||||||
|
t = 1;
|
||||||
|
} else {
|
||||||
|
t = t / length;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean done = false;
|
||||||
|
if (t >= 1.0) {
|
||||||
|
t = 1.0;
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
doInterpolate(t);
|
||||||
|
return !done;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void doInterpolate(double t);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(JmeExporter ex) throws IOException {
|
||||||
|
OutputCapsule oc = ex.getCapsule(this);
|
||||||
|
oc.write(length, "length", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(JmeImporter im) throws IOException {
|
||||||
|
InputCapsule ic = im.getCapsule(this);
|
||||||
|
length = ic.readDouble("length", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
71
jme3-core/src/main/java/com/jme3/anim/tween/Tween.java
Normal file
71
jme3-core/src/main/java/com/jme3/anim/tween/Tween.java
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015, Simsilica, LLC
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.jme3.anim.tween;
|
||||||
|
|
||||||
|
|
||||||
|
import com.jme3.export.Savable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents some action that interpolates across input between 0
|
||||||
|
* and some length value. (For example, movement, rotation, fading.)
|
||||||
|
* It's also possible to have zero length 'instant' tweens.
|
||||||
|
*
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public interface Tween extends Savable, Cloneable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the length of the tween. If 't' represents time in
|
||||||
|
* seconds then this is the notional time in seconds that the tween
|
||||||
|
* will run. Note: all of the caveats are because tweens may be
|
||||||
|
* externally scaled in such a way that 't' no longer represents
|
||||||
|
* actual time.
|
||||||
|
*/
|
||||||
|
public double getLength();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the implementation specific interpolation to the
|
||||||
|
* specified 'tween' value as a value in the range from 0 to
|
||||||
|
* getLength(). If the value is greater or equal to getLength()
|
||||||
|
* then it is internally clamped and the method returns false.
|
||||||
|
* If 't' is still in the tween's range then this method returns
|
||||||
|
* true.
|
||||||
|
*/
|
||||||
|
public boolean interpolate(double t);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -33,6 +33,7 @@ package com.jme3.animation;
|
|||||||
|
|
||||||
import com.jme3.math.FastMath;
|
import com.jme3.math.FastMath;
|
||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.TempVars;
|
||||||
|
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,6 +47,7 @@ import java.util.BitSet;
|
|||||||
*
|
*
|
||||||
* @author Kirill Vainer
|
* @author Kirill Vainer
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public final class AnimChannel {
|
public final class AnimChannel {
|
||||||
|
|
||||||
private static final float DEFAULT_BLEND_TIME = 0.15f;
|
private static final float DEFAULT_BLEND_TIME = 0.15f;
|
||||||
|
@ -64,7 +64,9 @@ import java.util.Map;
|
|||||||
* 1) Morph/Pose animation
|
* 1) Morph/Pose animation
|
||||||
*
|
*
|
||||||
* @author Kirill Vainer
|
* @author Kirill Vainer
|
||||||
|
* @deprecated use {@link com.jme3.anim.AnimComposer}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public final class AnimControl extends AbstractControl implements Cloneable, JmeCloneable {
|
public final class AnimControl extends AbstractControl implements Cloneable, JmeCloneable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,6 +37,7 @@ package com.jme3.animation;
|
|||||||
*
|
*
|
||||||
* @author Kirill Vainer
|
* @author Kirill Vainer
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public interface AnimEventListener {
|
public interface AnimEventListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,13 +37,16 @@ import com.jme3.util.SafeArrayList;
|
|||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.TempVars;
|
||||||
import com.jme3.util.clone.Cloner;
|
import com.jme3.util.clone.Cloner;
|
||||||
import com.jme3.util.clone.JmeCloneable;
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The animation class updates the animation target with the tracks of a given type.
|
* The animation class updates the animation target with the tracks of a given type.
|
||||||
*
|
*
|
||||||
* @author Kirill Vainer, Marcin Roguski (Kaelthas)
|
* @author Kirill Vainer, Marcin Roguski (Kaelthas)
|
||||||
|
* @deprecated use {@link com.jme3.anim.AnimClip}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class Animation implements Savable, Cloneable, JmeCloneable {
|
public class Animation implements Savable, Cloneable, JmeCloneable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,15 +32,12 @@
|
|||||||
package com.jme3.animation;
|
package com.jme3.animation;
|
||||||
|
|
||||||
import com.jme3.audio.AudioNode;
|
import com.jme3.audio.AudioNode;
|
||||||
import com.jme3.export.InputCapsule;
|
import com.jme3.export.*;
|
||||||
import com.jme3.export.JmeExporter;
|
|
||||||
import com.jme3.export.JmeImporter;
|
|
||||||
import com.jme3.export.OutputCapsule;
|
|
||||||
import com.jme3.scene.Node;
|
import com.jme3.scene.Node;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.TempVars;
|
||||||
import com.jme3.util.clone.Cloner;
|
import com.jme3.util.clone.Cloner;
|
||||||
import com.jme3.util.clone.JmeCloneable;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@ -62,6 +59,7 @@ import java.util.logging.Logger;
|
|||||||
*
|
*
|
||||||
* @author Nehon
|
* @author Nehon
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class AudioTrack implements ClonableTrack {
|
public class AudioTrack implements ClonableTrack {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(AudioTrack.class.getName());
|
private static final Logger logger = Logger.getLogger(AudioTrack.class.getName());
|
||||||
|
@ -67,7 +67,9 @@ import java.util.ArrayList;
|
|||||||
*
|
*
|
||||||
* @author Kirill Vainer
|
* @author Kirill Vainer
|
||||||
* @author Rémy Bouquet
|
* @author Rémy Bouquet
|
||||||
|
* @deprecated use {@link com.jme3.anim.Joint}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public final class Bone implements Savable, JmeCloneable {
|
public final class Bone implements Savable, JmeCloneable {
|
||||||
|
|
||||||
// Version #2: Changed naming of transforms as they were misleading
|
// Version #2: Changed naming of transforms as they were misleading
|
||||||
|
@ -35,8 +35,12 @@ import com.jme3.export.*;
|
|||||||
import com.jme3.math.Quaternion;
|
import com.jme3.math.Quaternion;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.TempVars;
|
||||||
|
<<<<<<< HEAD
|
||||||
import com.jme3.util.clone.Cloner;
|
import com.jme3.util.clone.Cloner;
|
||||||
import com.jme3.util.clone.JmeCloneable;
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
|
=======
|
||||||
|
|
||||||
|
>>>>>>> Draft of the new animation system
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
|
|
||||||
@ -44,7 +48,9 @@ import java.util.BitSet;
|
|||||||
* Contains a list of transforms and times for each keyframe.
|
* Contains a list of transforms and times for each keyframe.
|
||||||
*
|
*
|
||||||
* @author Kirill Vainer
|
* @author Kirill Vainer
|
||||||
|
* @deprecated use {@link com.jme3.anim.JointTrack}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public final class BoneTrack implements JmeCloneable, Track {
|
public final class BoneTrack implements JmeCloneable, Track {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,6 +44,7 @@ import com.jme3.util.clone.JmeCloneable;
|
|||||||
*
|
*
|
||||||
* @author Nehon
|
* @author Nehon
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public interface ClonableTrack extends Track, JmeCloneable {
|
public interface ClonableTrack extends Track, JmeCloneable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,10 +32,7 @@
|
|||||||
package com.jme3.animation;
|
package com.jme3.animation;
|
||||||
|
|
||||||
import com.jme3.effect.ParticleEmitter;
|
import com.jme3.effect.ParticleEmitter;
|
||||||
import com.jme3.export.InputCapsule;
|
import com.jme3.export.*;
|
||||||
import com.jme3.export.JmeExporter;
|
|
||||||
import com.jme3.export.JmeImporter;
|
|
||||||
import com.jme3.export.OutputCapsule;
|
|
||||||
import com.jme3.renderer.RenderManager;
|
import com.jme3.renderer.RenderManager;
|
||||||
import com.jme3.renderer.ViewPort;
|
import com.jme3.renderer.ViewPort;
|
||||||
import com.jme3.scene.Node;
|
import com.jme3.scene.Node;
|
||||||
@ -67,6 +64,7 @@ import java.util.logging.Logger;
|
|||||||
*
|
*
|
||||||
* @author Nehon
|
* @author Nehon
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class EffectTrack implements ClonableTrack {
|
public class EffectTrack implements ClonableTrack {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(EffectTrack.class.getName());
|
private static final Logger logger = Logger.getLogger(EffectTrack.class.getName());
|
||||||
@ -130,15 +128,17 @@ public class EffectTrack implements ClonableTrack {
|
|||||||
@Override
|
@Override
|
||||||
protected void controlRender(RenderManager rm, ViewPort vp) {
|
protected void controlRender(RenderManager rm, ViewPort vp) {
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
//Anim listener that stops the Emmitter when the animation is finished or changed.
|
//Anim listener that stops the Emmitter when the animation is finished or changed.
|
||||||
private class OnEndListener implements AnimEventListener {
|
private class OnEndListener implements AnimEventListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
|
public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
|
public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,6 +188,7 @@ public class EffectTrack implements ClonableTrack {
|
|||||||
* @see Track#setTime(float, float, com.jme3.animation.AnimControl,
|
* @see Track#setTime(float, float, com.jme3.animation.AnimControl,
|
||||||
* com.jme3.animation.AnimChannel, com.jme3.util.TempVars)
|
* com.jme3.animation.AnimChannel, com.jme3.util.TempVars)
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void setTime(float time, float weight, AnimControl control, AnimChannel channel, TempVars vars) {
|
public void setTime(float time, float weight, AnimControl control, AnimChannel channel, TempVars vars) {
|
||||||
|
|
||||||
if (time >= length) {
|
if (time >= length) {
|
||||||
@ -233,6 +234,7 @@ public class EffectTrack implements ClonableTrack {
|
|||||||
*
|
*
|
||||||
* @return length of the track
|
* @return length of the track
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public float getLength() {
|
public float getLength() {
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
@ -325,6 +327,7 @@ public class EffectTrack implements ClonableTrack {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void cleanUp() {
|
public void cleanUp() {
|
||||||
TrackInfo t = (TrackInfo) emitter.getUserData("TrackInfo");
|
TrackInfo t = (TrackInfo) emitter.getUserData("TrackInfo");
|
||||||
t.getTracks().remove(this);
|
t.getTracks().remove(this);
|
||||||
@ -413,6 +416,7 @@ public class EffectTrack implements ClonableTrack {
|
|||||||
* @param ex exporter
|
* @param ex exporter
|
||||||
* @throws IOException exception
|
* @throws IOException exception
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void write(JmeExporter ex) throws IOException {
|
public void write(JmeExporter ex) throws IOException {
|
||||||
OutputCapsule out = ex.getCapsule(this);
|
OutputCapsule out = ex.getCapsule(this);
|
||||||
//reset the particle emission rate on the emitter before saving.
|
//reset the particle emission rate on the emitter before saving.
|
||||||
@ -431,6 +435,7 @@ public class EffectTrack implements ClonableTrack {
|
|||||||
* @param im importer
|
* @param im importer
|
||||||
* @throws IOException Exception
|
* @throws IOException Exception
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void read(JmeImporter im) throws IOException {
|
public void read(JmeImporter im) throws IOException {
|
||||||
InputCapsule in = im.getCapsule(this);
|
InputCapsule in = im.getCapsule(this);
|
||||||
this.particlesPerSeconds = in.readFloat("particlesPerSeconds", 0);
|
this.particlesPerSeconds = in.readFloat("particlesPerSeconds", 0);
|
||||||
|
@ -35,6 +35,7 @@ package com.jme3.animation;
|
|||||||
* <code>LoopMode</code> determines how animations repeat, or if they
|
* <code>LoopMode</code> determines how animations repeat, or if they
|
||||||
* do not repeat.
|
* do not repeat.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public enum LoopMode {
|
public enum LoopMode {
|
||||||
/**
|
/**
|
||||||
* The animation will play repeatedly, when it reaches the end
|
* The animation will play repeatedly, when it reaches the end
|
||||||
|
@ -34,12 +34,14 @@ package com.jme3.animation;
|
|||||||
import com.jme3.export.*;
|
import com.jme3.export.*;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
import com.jme3.util.BufferUtils;
|
import com.jme3.util.BufferUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A pose is a list of offsets that say where a mesh vertices should be for this pose.
|
* A pose is a list of offsets that say where a mesh vertices should be for this pose.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public final class Pose implements Savable, Cloneable {
|
public final class Pose implements Savable, Cloneable {
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
@ -31,11 +31,13 @@
|
|||||||
*/
|
*/
|
||||||
package com.jme3.animation;
|
package com.jme3.animation;
|
||||||
|
|
||||||
|
import com.jme3.anim.Armature;
|
||||||
import com.jme3.export.*;
|
import com.jme3.export.*;
|
||||||
import com.jme3.math.Matrix4f;
|
import com.jme3.math.Matrix4f;
|
||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.TempVars;
|
||||||
import com.jme3.util.clone.JmeCloneable;
|
|
||||||
import com.jme3.util.clone.Cloner;
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -46,7 +48,9 @@ import java.util.List;
|
|||||||
* animated matrixes.
|
* animated matrixes.
|
||||||
*
|
*
|
||||||
* @author Kirill Vainer
|
* @author Kirill Vainer
|
||||||
|
* @deprecated use {@link Armature}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public final class Skeleton implements Savable, JmeCloneable {
|
public final class Skeleton implements Savable, JmeCloneable {
|
||||||
|
|
||||||
private Bone[] rootBones;
|
private Bone[] rootBones;
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.jme3.animation;
|
package com.jme3.animation;
|
||||||
|
|
||||||
|
import com.jme3.anim.SkinningControl;
|
||||||
import com.jme3.export.*;
|
import com.jme3.export.*;
|
||||||
import com.jme3.material.MatParamOverride;
|
import com.jme3.material.MatParamOverride;
|
||||||
import com.jme3.math.FastMath;
|
import com.jme3.math.FastMath;
|
||||||
@ -57,7 +58,9 @@ import java.util.logging.Logger;
|
|||||||
* the mesh
|
* the mesh
|
||||||
*
|
*
|
||||||
* @author Rémy Bouquet Based on AnimControl by Kirill Vainer
|
* @author Rémy Bouquet Based on AnimControl by Kirill Vainer
|
||||||
|
* @deprecated use {@link SkinningControl}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class SkeletonControl extends AbstractControl implements Cloneable, JmeCloneable {
|
public class SkeletonControl extends AbstractControl implements Cloneable, JmeCloneable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,10 +31,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.jme3.animation;
|
package com.jme3.animation;
|
||||||
|
|
||||||
import com.jme3.export.InputCapsule;
|
import com.jme3.export.*;
|
||||||
import com.jme3.export.JmeExporter;
|
|
||||||
import com.jme3.export.JmeImporter;
|
|
||||||
import com.jme3.export.OutputCapsule;
|
|
||||||
import com.jme3.math.Quaternion;
|
import com.jme3.math.Quaternion;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
@ -48,6 +45,7 @@ import java.io.IOException;
|
|||||||
*
|
*
|
||||||
* @author Marcin Roguski (Kaelthas)
|
* @author Marcin Roguski (Kaelthas)
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class SpatialTrack implements JmeCloneable, Track {
|
public class SpatialTrack implements JmeCloneable, Track {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,6 +34,7 @@ package com.jme3.animation;
|
|||||||
import com.jme3.export.Savable;
|
import com.jme3.export.Savable;
|
||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.TempVars;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public interface Track extends Savable, Cloneable {
|
public interface Track extends Savable, Cloneable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,13 +31,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.jme3.animation;
|
package com.jme3.animation;
|
||||||
|
|
||||||
import com.jme3.export.InputCapsule;
|
import com.jme3.export.*;
|
||||||
import com.jme3.export.JmeExporter;
|
|
||||||
import com.jme3.export.JmeImporter;
|
|
||||||
import com.jme3.export.OutputCapsule;
|
|
||||||
import com.jme3.export.Savable;
|
|
||||||
import com.jme3.util.clone.Cloner;
|
import com.jme3.util.clone.Cloner;
|
||||||
import com.jme3.util.clone.JmeCloneable;
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@ -50,6 +47,7 @@ import java.util.ArrayList;
|
|||||||
*
|
*
|
||||||
* @author Nehon
|
* @author Nehon
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class TrackInfo implements Savable, JmeCloneable {
|
public class TrackInfo implements Savable, JmeCloneable {
|
||||||
|
|
||||||
ArrayList<Track> tracks = new ArrayList<Track>();
|
ArrayList<Track> tracks = new ArrayList<Track>();
|
||||||
|
13
jme3-core/src/main/java/com/jme3/math/EaseFunction.java
Normal file
13
jme3-core/src/main/java/com/jme3/math/EaseFunction.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package com.jme3.math;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Nehon on 26/03/2017.
|
||||||
|
*/
|
||||||
|
public interface EaseFunction {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param value a value from 0 to 1. Passing a value out of this range will have unexpected behavior.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
float apply(float value);
|
||||||
|
}
|
163
jme3-core/src/main/java/com/jme3/math/Easing.java
Normal file
163
jme3-core/src/main/java/com/jme3/math/Easing.java
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
package com.jme3.math;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose several Easing function from Robert Penner
|
||||||
|
* Created by Nehon on 26/03/2017.
|
||||||
|
*/
|
||||||
|
public class Easing {
|
||||||
|
|
||||||
|
|
||||||
|
public static EaseFunction constant = new EaseFunction() {
|
||||||
|
@Override
|
||||||
|
public float apply(float value) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* In
|
||||||
|
*/
|
||||||
|
public static EaseFunction linear = new EaseFunction() {
|
||||||
|
@Override
|
||||||
|
public float apply(float value) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static EaseFunction inQuad = new EaseFunction() {
|
||||||
|
@Override
|
||||||
|
public float apply(float value) {
|
||||||
|
return value * value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static EaseFunction inCubic = new EaseFunction() {
|
||||||
|
@Override
|
||||||
|
public float apply(float value) {
|
||||||
|
return value * value * value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static EaseFunction inQuart = new EaseFunction() {
|
||||||
|
@Override
|
||||||
|
public float apply(float value) {
|
||||||
|
return value * value * value * value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static EaseFunction inQuint = new EaseFunction() {
|
||||||
|
@Override
|
||||||
|
public float apply(float value) {
|
||||||
|
return value * value * value * value * value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Out Elastic and bounce
|
||||||
|
*/
|
||||||
|
public static EaseFunction outElastic = new EaseFunction() {
|
||||||
|
@Override
|
||||||
|
public float apply(float value) {
|
||||||
|
return FastMath.pow(2f, -10f * value) * FastMath.sin((value - 0.3f / 4f) * (2f * FastMath.PI) / 0.3f) + 1f;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static EaseFunction outBounce = new EaseFunction() {
|
||||||
|
@Override
|
||||||
|
public float apply(float value) {
|
||||||
|
if (value < (1f / 2.75f)) {
|
||||||
|
return (7.5625f * value * value);
|
||||||
|
} else if (value < (2f / 2.75f)) {
|
||||||
|
return (7.5625f * (value -= (1.5f / 2.75f)) * value + 0.75f);
|
||||||
|
} else if (value < (2.5 / 2.75)) {
|
||||||
|
return (7.5625f * (value -= (2.25f / 2.75f)) * value + 0.9375f);
|
||||||
|
} else {
|
||||||
|
return (7.5625f * (value -= (2.625f / 2.75f)) * value + 0.984375f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In Elastic and bounce
|
||||||
|
*/
|
||||||
|
public static EaseFunction inElastic = new Invert(outElastic);
|
||||||
|
public static EaseFunction inBounce = new Invert(outBounce);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Out
|
||||||
|
*/
|
||||||
|
public static EaseFunction outQuad = new Invert(inQuad);
|
||||||
|
public static EaseFunction outCubic = new Invert(inCubic);
|
||||||
|
public static EaseFunction outQuart = new Invert(inQuart);
|
||||||
|
public static EaseFunction outQuint = new Invert(inQuint);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* inOut
|
||||||
|
*/
|
||||||
|
public static EaseFunction inOutQuad = new InOut(inQuad, outQuad);
|
||||||
|
public static EaseFunction inOutCubic = new InOut(inCubic, outCubic);
|
||||||
|
public static EaseFunction inOutQuart = new InOut(inQuart, outQuart);
|
||||||
|
public static EaseFunction inOutQuint = new InOut(inQuint, outQuint);
|
||||||
|
public static EaseFunction inOutElastic = new InOut(inElastic, outElastic);
|
||||||
|
public static EaseFunction inOutBounce = new InOut(inBounce, outBounce);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static EaseFunction smoothStep = new EaseFunction() {
|
||||||
|
@Override
|
||||||
|
public float apply(float t) {
|
||||||
|
return t * t * (3f - 2f * t);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static EaseFunction smootherStep = new EaseFunction() {
|
||||||
|
@Override
|
||||||
|
public float apply(float t) {
|
||||||
|
return t * t * t * (t * (t * 6f - 15f) + 10f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Ease function composed of 2 sb function for custom in and out easing
|
||||||
|
*/
|
||||||
|
public static class InOut implements EaseFunction {
|
||||||
|
|
||||||
|
private EaseFunction in;
|
||||||
|
private EaseFunction out;
|
||||||
|
|
||||||
|
public InOut(EaseFunction in, EaseFunction out) {
|
||||||
|
this.in = in;
|
||||||
|
this.out = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float apply(float value) {
|
||||||
|
if (value < 0.5) {
|
||||||
|
value = value * 2;
|
||||||
|
return inQuad.apply(value) / 2;
|
||||||
|
} else {
|
||||||
|
value = (value - 0.5f) * 2;
|
||||||
|
return outQuad.apply(value) / 2 + 0.5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Invert implements EaseFunction {
|
||||||
|
|
||||||
|
private EaseFunction func;
|
||||||
|
|
||||||
|
public Invert(EaseFunction func) {
|
||||||
|
this.func = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float apply(float value) {
|
||||||
|
return 1f - func.apply(1f - value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
165
jme3-core/src/main/java/com/jme3/math/MathUtils.java
Normal file
165
jme3-core/src/main/java/com/jme3/math/MathUtils.java
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
package com.jme3.math;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Nehon on 23/04/2017.
|
||||||
|
*/
|
||||||
|
public class MathUtils {
|
||||||
|
|
||||||
|
public static Quaternion log(Quaternion q, Quaternion store) {
|
||||||
|
float a = FastMath.acos(q.w);
|
||||||
|
float sina = FastMath.sin(a);
|
||||||
|
|
||||||
|
store.w = 0;
|
||||||
|
if (sina > 0) {
|
||||||
|
store.x = a * q.x / sina;
|
||||||
|
store.y = a * q.y / sina;
|
||||||
|
store.z = a * q.z / sina;
|
||||||
|
} else {
|
||||||
|
store.x = 0;
|
||||||
|
store.y = 0;
|
||||||
|
store.z = 0;
|
||||||
|
}
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Quaternion exp(Quaternion q, Quaternion store) {
|
||||||
|
|
||||||
|
float len = FastMath.sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
|
||||||
|
float sinLen = FastMath.sin(len);
|
||||||
|
float cosLen = FastMath.cos(len);
|
||||||
|
|
||||||
|
store.w = cosLen;
|
||||||
|
if (len > 0) {
|
||||||
|
store.x = sinLen * q.x / len;
|
||||||
|
store.y = sinLen * q.y / len;
|
||||||
|
store.z = sinLen * q.z / len;
|
||||||
|
} else {
|
||||||
|
store.x = 0;
|
||||||
|
store.y = 0;
|
||||||
|
store.z = 0;
|
||||||
|
}
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! This version of slerp, used by squad, does not check for theta > 90.
|
||||||
|
public static Quaternion slerpNoInvert(Quaternion q1, Quaternion q2, float t, Quaternion store) {
|
||||||
|
float dot = q1.dot(q2);
|
||||||
|
|
||||||
|
if (dot > -0.95f && dot < 0.95f) {
|
||||||
|
float angle = FastMath.acos(dot);
|
||||||
|
float sin1 = FastMath.sin(angle * (1 - t));
|
||||||
|
float sin2 = FastMath.sin(angle * t);
|
||||||
|
float sin3 = FastMath.sin(angle);
|
||||||
|
store.x = (q1.x * sin1 + q2.x * sin2) / sin3;
|
||||||
|
store.y = (q1.y * sin1 + q2.y * sin2) / sin3;
|
||||||
|
store.z = (q1.z * sin1 + q2.z * sin2) / sin3;
|
||||||
|
store.w = (q1.w * sin1 + q2.w * sin2) / sin3;
|
||||||
|
System.err.println("real slerp");
|
||||||
|
} else {
|
||||||
|
// if the angle is small, use linear interpolation
|
||||||
|
store.set(q1).nlerp(q2, t);
|
||||||
|
System.err.println("nlerp");
|
||||||
|
}
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Quaternion slerp(Quaternion q1, Quaternion q2, float t, Quaternion store) {
|
||||||
|
|
||||||
|
float dot = (q1.x * q2.x) + (q1.y * q2.y) + (q1.z * q2.z)
|
||||||
|
+ (q1.w * q2.w);
|
||||||
|
|
||||||
|
if (dot < 0.0f) {
|
||||||
|
// Negate the second quaternion and the result of the dot product
|
||||||
|
q2.x = -q2.x;
|
||||||
|
q2.y = -q2.y;
|
||||||
|
q2.z = -q2.z;
|
||||||
|
q2.w = -q2.w;
|
||||||
|
dot = -dot;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the first and second scale for the interpolation
|
||||||
|
float scale0 = 1 - t;
|
||||||
|
float scale1 = t;
|
||||||
|
|
||||||
|
// Check if the angle between the 2 quaternions was big enough to
|
||||||
|
// warrant such calculations
|
||||||
|
if (dot < 0.9f) {// Get the angle between the 2 quaternions,
|
||||||
|
// and then store the sin() of that angle
|
||||||
|
float theta = FastMath.acos(dot);
|
||||||
|
float invSinTheta = 1f / FastMath.sin(theta);
|
||||||
|
|
||||||
|
// Calculate the scale for q1 and q2, according to the angle and
|
||||||
|
// it's sine value
|
||||||
|
scale0 = FastMath.sin((1 - t) * theta) * invSinTheta;
|
||||||
|
scale1 = FastMath.sin((t * theta)) * invSinTheta;
|
||||||
|
|
||||||
|
// Calculate the x, y, z and w values for the quaternion by using a
|
||||||
|
// special
|
||||||
|
// form of linear interpolation for quaternions.
|
||||||
|
store.x = (scale0 * q1.x) + (scale1 * q2.x);
|
||||||
|
store.y = (scale0 * q1.y) + (scale1 * q2.y);
|
||||||
|
store.z = (scale0 * q1.z) + (scale1 * q2.z);
|
||||||
|
store.w = (scale0 * q1.w) + (scale1 * q2.w);
|
||||||
|
} else {
|
||||||
|
store.x = (scale0 * q1.x) + (scale1 * q2.x);
|
||||||
|
store.y = (scale0 * q1.y) + (scale1 * q2.y);
|
||||||
|
store.z = (scale0 * q1.z) + (scale1 * q2.z);
|
||||||
|
store.w = (scale0 * q1.w) + (scale1 * q2.w);
|
||||||
|
store.normalizeLocal();
|
||||||
|
}
|
||||||
|
// Return the interpolated quaternion
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
|
||||||
|
// //! Given 3 quaternions, qn-1,qn and qn+1, calculate a control point to be used in spline interpolation
|
||||||
|
// private static Quaternion spline(Quaternion qnm1, Quaternion qn, Quaternion qnp1, Quaternion store, Quaternion tmp) {
|
||||||
|
// store.set(-qn.x, -qn.y, -qn.z, qn.w);
|
||||||
|
// //store.set(qn).inverseLocal();
|
||||||
|
// tmp.set(store);
|
||||||
|
//
|
||||||
|
// log(store.multLocal(qnm1), store);
|
||||||
|
// log(tmp.multLocal(qnp1), tmp);
|
||||||
|
// store.addLocal(tmp).multLocal(1f / -4f);
|
||||||
|
// exp(store, tmp);
|
||||||
|
// store.set(tmp).multLocal(qn);
|
||||||
|
//
|
||||||
|
// return store.normalizeLocal();
|
||||||
|
// //return qn * (((qni * qnm1).log() + (qni * qnp1).log()) / -4).exp();
|
||||||
|
// }
|
||||||
|
|
||||||
|
//! Given 3 quaternions, qn-1,qn and qn+1, calculate a control point to be used in spline interpolation
|
||||||
|
private static Quaternion spline(Quaternion qnm1, Quaternion qn, Quaternion qnp1, Quaternion store, Quaternion tmp) {
|
||||||
|
Quaternion invQn = new Quaternion(-qn.x, -qn.y, -qn.z, qn.w);
|
||||||
|
|
||||||
|
|
||||||
|
log(invQn.mult(qnp1), tmp);
|
||||||
|
log(invQn.mult(qnm1), store);
|
||||||
|
store.addLocal(tmp).multLocal(-1f / 4f);
|
||||||
|
exp(store, tmp);
|
||||||
|
store.set(qn).multLocal(tmp);
|
||||||
|
|
||||||
|
return store.normalizeLocal();
|
||||||
|
//return qn * (((qni * qnm1).log() + (qni * qnp1).log()) / -4).exp();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! spherical cubic interpolation
|
||||||
|
public static Quaternion squad(Quaternion q0, Quaternion q1, Quaternion q2, Quaternion q3, Quaternion a, Quaternion b, float t, Quaternion store) {
|
||||||
|
|
||||||
|
spline(q0, q1, q2, a, store);
|
||||||
|
spline(q1, q2, q3, b, store);
|
||||||
|
|
||||||
|
slerp(a, b, t, store);
|
||||||
|
slerp(q1, q2, t, a);
|
||||||
|
return slerp(a, store, 2 * t * (1 - t), b);
|
||||||
|
//slerpNoInvert(a, b, t, store);
|
||||||
|
//slerpNoInvert(q1, q2, t, a);
|
||||||
|
//return slerpNoInvert(a, store, 2 * t * (1 - t), b);
|
||||||
|
|
||||||
|
// quaternion c = slerpNoInvert(q1, q2, t),
|
||||||
|
// d = slerpNoInvert(a, b, t);
|
||||||
|
// return slerpNoInvert(c, d, 2 * t * (1 - t));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -181,7 +181,8 @@ public final class Transform implements Savable, Cloneable, java.io.Serializable
|
|||||||
* @param delta An amount between 0 and 1 representing how far to interpolate from t1 to t2.
|
* @param delta An amount between 0 and 1 representing how far to interpolate from t1 to t2.
|
||||||
*/
|
*/
|
||||||
public void interpolateTransforms(Transform t1, Transform t2, float delta) {
|
public void interpolateTransforms(Transform t1, Transform t2, float delta) {
|
||||||
this.rot.slerp(t1.rot,t2.rot,delta);
|
t1.rot.nlerp(t2.rot, delta);
|
||||||
|
this.rot.set(t1.rot);
|
||||||
this.translation.interpolateLocal(t1.translation,t2.translation,delta);
|
this.translation.interpolateLocal(t1.translation,t2.translation,delta);
|
||||||
this.scale.interpolateLocal(t1.scale,t2.scale,delta);
|
this.scale.interpolateLocal(t1.scale,t2.scale,delta);
|
||||||
}
|
}
|
||||||
|
@ -32,8 +32,8 @@ package com.jme3.scene.debug.custom;
|
|||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import com.jme3.animation.Armature;
|
import com.jme3.anim.Armature;
|
||||||
import com.jme3.animation.Joint;
|
import com.jme3.anim.Joint;
|
||||||
import com.jme3.bounding.*;
|
import com.jme3.bounding.*;
|
||||||
import com.jme3.math.Quaternion;
|
import com.jme3.math.Quaternion;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.jme3.scene.debug.custom;
|
package com.jme3.scene.debug.custom;
|
||||||
|
|
||||||
import com.jme3.animation.*;
|
import com.jme3.anim.*;
|
||||||
import com.jme3.app.Application;
|
import com.jme3.app.Application;
|
||||||
import com.jme3.app.state.AbstractAppState;
|
import com.jme3.app.state.AbstractAppState;
|
||||||
import com.jme3.app.state.AppStateManager;
|
import com.jme3.app.state.AppStateManager;
|
||||||
@ -55,9 +55,9 @@ public class ArmatureDebugAppState extends AbstractAppState {
|
|||||||
debugNode.updateGeometricState();
|
debugNode.updateGeometricState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArmatureDebugger addArmature(ArmatureControl armatureControl, boolean guessJointsOrientation) {
|
public ArmatureDebugger addArmature(SkinningControl skinningControl, boolean guessJointsOrientation) {
|
||||||
Armature armature = armatureControl.getArmature();
|
Armature armature = skinningControl.getArmature();
|
||||||
Spatial forSpatial = armatureControl.getSpatial();
|
Spatial forSpatial = skinningControl.getSpatial();
|
||||||
return addArmature(armature, forSpatial, guessJointsOrientation);
|
return addArmature(armature, forSpatial, guessJointsOrientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,9 @@ package com.jme3.scene.debug.custom;
|
|||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import com.jme3.animation.*;
|
import com.jme3.anim.Armature;
|
||||||
|
import com.jme3.anim.Joint;
|
||||||
|
import com.jme3.animation.Bone;
|
||||||
import com.jme3.asset.AssetManager;
|
import com.jme3.asset.AssetManager;
|
||||||
import com.jme3.material.Material;
|
import com.jme3.material.Material;
|
||||||
import com.jme3.math.ColorRGBA;
|
import com.jme3.math.ColorRGBA;
|
||||||
@ -91,7 +93,7 @@ public class ArmatureDebugger extends BatchNode {
|
|||||||
|
|
||||||
interJointWires = new ArmatureInterJointsWire(armature, bonesLength, guessJointsOrientation);
|
interJointWires = new ArmatureInterJointsWire(armature, bonesLength, guessJointsOrientation);
|
||||||
wires = new Geometry(name + "_interwires", interJointWires);
|
wires = new Geometry(name + "_interwires", interJointWires);
|
||||||
this.attachChild(wires);
|
// this.attachChild(wires);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void initialize(AssetManager assetManager) {
|
protected void initialize(AssetManager assetManager) {
|
||||||
@ -152,7 +154,7 @@ public class ArmatureDebugger extends BatchNode {
|
|||||||
super.updateLogicalState(tpf);
|
super.updateLogicalState(tpf);
|
||||||
bones.updateGeometry();
|
bones.updateGeometry();
|
||||||
if (interJointWires != null) {
|
if (interJointWires != null) {
|
||||||
interJointWires.updateGeometry();
|
// interJointWires.updateGeometry();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,8 +33,8 @@ package com.jme3.scene.debug.custom;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import com.jme3.animation.Armature;
|
import com.jme3.anim.Armature;
|
||||||
import com.jme3.animation.Joint;
|
import com.jme3.anim.Joint;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
import com.jme3.scene.Mesh;
|
import com.jme3.scene.Mesh;
|
||||||
import com.jme3.scene.VertexBuffer;
|
import com.jme3.scene.VertexBuffer;
|
||||||
|
@ -43,11 +43,12 @@ import com.jme3.renderer.Limits;
|
|||||||
import com.jme3.scene.Node;
|
import com.jme3.scene.Node;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.control.Control;
|
import com.jme3.scene.control.Control;
|
||||||
import com.jme3.scene.debug.custom.SkeletonDebugAppState;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
//import com.jme3.scene.debug.custom.SkeletonDebugAppState;
|
||||||
|
|
||||||
public class TestGltfLoading extends SimpleApplication {
|
public class TestGltfLoading extends SimpleApplication {
|
||||||
|
|
||||||
Node autoRotate = new Node("autoRotate");
|
Node autoRotate = new Node("autoRotate");
|
||||||
@ -74,8 +75,8 @@ public class TestGltfLoading extends SimpleApplication {
|
|||||||
*/
|
*/
|
||||||
public void simpleInitApp() {
|
public void simpleInitApp() {
|
||||||
|
|
||||||
SkeletonDebugAppState skeletonDebugAppState = new SkeletonDebugAppState();
|
// SkeletonDebugAppState skeletonDebugAppState = new SkeletonDebugAppState();
|
||||||
getStateManager().attach(skeletonDebugAppState);
|
// getStateManager().attach(skeletonDebugAppState);
|
||||||
|
|
||||||
String folder = System.getProperty("user.home");
|
String folder = System.getProperty("user.home");
|
||||||
assetManager.registerLocator(folder, FileLocator.class);
|
assetManager.registerLocator(folder, FileLocator.class);
|
||||||
@ -112,7 +113,7 @@ public class TestGltfLoading extends SimpleApplication {
|
|||||||
// loadModel("Models/gltf/box/box.gltf", Vector3f.ZERO, 1);
|
// loadModel("Models/gltf/box/box.gltf", Vector3f.ZERO, 1);
|
||||||
// loadModel("Models/gltf/duck/Duck.gltf", new Vector3f(0, -1, 0), 1);
|
// loadModel("Models/gltf/duck/Duck.gltf", new Vector3f(0, -1, 0), 1);
|
||||||
// loadModel("Models/gltf/damagedHelmet/damagedHelmet.gltf", Vector3f.ZERO, 1);
|
// loadModel("Models/gltf/damagedHelmet/damagedHelmet.gltf", Vector3f.ZERO, 1);
|
||||||
// loadModel("Models/gltf/hornet/scene.gltf", new Vector3f(0, -0.5f, 0), 0.4f);
|
loadModel("Models/gltf/hornet/scene.gltf", new Vector3f(0, -0.5f, 0), 0.4f);
|
||||||
//// loadModel("Models/gltf/adamHead/adamHead.gltf", Vector3f.ZERO, 0.6f);
|
//// loadModel("Models/gltf/adamHead/adamHead.gltf", Vector3f.ZERO, 0.6f);
|
||||||
// loadModel("Models/gltf/busterDrone/busterDrone.gltf", new Vector3f(0, 0f, 0), 0.8f);
|
// loadModel("Models/gltf/busterDrone/busterDrone.gltf", new Vector3f(0, 0f, 0), 0.8f);
|
||||||
// loadModel("Models/gltf/animatedCube/AnimatedCube.gltf", Vector3f.ZERO, 0.5f);
|
// loadModel("Models/gltf/animatedCube/AnimatedCube.gltf", Vector3f.ZERO, 0.5f);
|
||||||
@ -206,14 +207,14 @@ public class TestGltfLoading extends SimpleApplication {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ctrl.setHardwareSkinningPreferred(false);
|
ctrl.setHardwareSkinningPreferred(false);
|
||||||
getStateManager().getState(SkeletonDebugAppState.class).addSkeleton(ctrl, true);
|
//getStateManager().getState(SkeletonDebugAppState.class).addSkeleton(ctrl, true);
|
||||||
// AnimControl aCtrl = findControl(s, AnimControl.class);
|
// AnimControl aCtrl = findControl(s, AnimControl.class);
|
||||||
// //ctrl.getSpatial().removeControl(ctrl);
|
// //ctrl.getSpatial().removeControl(ctrl);
|
||||||
// if (aCtrl == null) {
|
// if (aCtrl == null) {
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
// if (aCtrl.getSkeleton() != null) {
|
// if (aCtrl.getArmature() != null) {
|
||||||
// getStateManager().getState(SkeletonDebugAppState.class).addSkeleton(aCtrl.getSkeleton(), aCtrl.getSpatial(), true);
|
// getStateManager().getState(SkeletonDebugAppState.class).addSkeleton(aCtrl.getArmature(), aCtrl.getSpatial(), true);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -42,11 +42,12 @@ import com.jme3.renderer.Limits;
|
|||||||
import com.jme3.scene.Node;
|
import com.jme3.scene.Node;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.control.Control;
|
import com.jme3.scene.control.Control;
|
||||||
import com.jme3.scene.debug.custom.SkeletonDebugAppState;
|
|
||||||
import com.jme3.scene.plugins.gltf.GltfModelKey;
|
import com.jme3.scene.plugins.gltf.GltfModelKey;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
//import com.jme3.scene.debug.custom.SkeletonDebugAppState;
|
||||||
|
|
||||||
public class TestGltfLoading2 extends SimpleApplication {
|
public class TestGltfLoading2 extends SimpleApplication {
|
||||||
|
|
||||||
Node autoRotate = new Node("autoRotate");
|
Node autoRotate = new Node("autoRotate");
|
||||||
@ -73,8 +74,8 @@ public class TestGltfLoading2 extends SimpleApplication {
|
|||||||
*/
|
*/
|
||||||
public void simpleInitApp() {
|
public void simpleInitApp() {
|
||||||
|
|
||||||
SkeletonDebugAppState skeletonDebugAppState = new SkeletonDebugAppState();
|
// SkeletonDebugAppState skeletonDebugAppState = new SkeletonDebugAppState();
|
||||||
getStateManager().attach(skeletonDebugAppState);
|
// getStateManager().attach(skeletonDebugAppState);
|
||||||
|
|
||||||
// cam.setLocation(new Vector3f(4.0339394f, 2.645184f, 6.4627485f));
|
// cam.setLocation(new Vector3f(4.0339394f, 2.645184f, 6.4627485f));
|
||||||
// cam.setRotation(new Quaternion(-0.013950467f, 0.98604023f, -0.119502485f, -0.11510504f));
|
// cam.setRotation(new Quaternion(-0.013950467f, 0.98604023f, -0.119502485f, -0.11510504f));
|
||||||
@ -226,7 +227,7 @@ public class TestGltfLoading2 extends SimpleApplication {
|
|||||||
if (ctrl == null) {
|
if (ctrl == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//System.err.println(ctrl.getSkeleton().toString());
|
//System.err.println(ctrl.getArmature().toString());
|
||||||
//ctrl.setHardwareSkinningPreferred(false);
|
//ctrl.setHardwareSkinningPreferred(false);
|
||||||
// getStateManager().getState(SkeletonDebugAppState.class).addSkeleton(ctrl, true);
|
// getStateManager().getState(SkeletonDebugAppState.class).addSkeleton(ctrl, true);
|
||||||
// AnimControl aCtrl = findControl(s, AnimControl.class);
|
// AnimControl aCtrl = findControl(s, AnimControl.class);
|
||||||
@ -234,8 +235,8 @@ public class TestGltfLoading2 extends SimpleApplication {
|
|||||||
// if (aCtrl == null) {
|
// if (aCtrl == null) {
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
// if (aCtrl.getSkeleton() != null) {
|
// if (aCtrl.getArmature() != null) {
|
||||||
// getStateManager().getState(SkeletonDebugAppState.class).addSkeleton(aCtrl.getSkeleton(), aCtrl.getSpatial(), true);
|
// getStateManager().getState(SkeletonDebugAppState.class).addSkeleton(aCtrl.getArmature(), aCtrl.getSpatial(), true);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package jme3test.model.anim;
|
||||||
|
|
||||||
|
import com.jme3.system.Timer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nehon
|
||||||
|
*/
|
||||||
|
public class EraseTimer extends Timer {
|
||||||
|
|
||||||
|
|
||||||
|
//private static final long TIMER_RESOLUTION = 1000L;
|
||||||
|
//private static final float INVERSE_TIMER_RESOLUTION = 1f/1000L;
|
||||||
|
private static final long TIMER_RESOLUTION = 1000000000L;
|
||||||
|
private static final float INVERSE_TIMER_RESOLUTION = 1f / 1000000000L;
|
||||||
|
|
||||||
|
private long startTime;
|
||||||
|
private long previousTime;
|
||||||
|
private float tpf;
|
||||||
|
private float fps;
|
||||||
|
|
||||||
|
public EraseTimer() {
|
||||||
|
//startTime = System.currentTimeMillis();
|
||||||
|
startTime = System.nanoTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the time in seconds. The timer starts
|
||||||
|
* at 0.0 seconds.
|
||||||
|
*
|
||||||
|
* @return the current time in seconds
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public float getTimeInSeconds() {
|
||||||
|
return getTime() * INVERSE_TIMER_RESOLUTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTime() {
|
||||||
|
//return System.currentTimeMillis() - startTime;
|
||||||
|
return System.nanoTime() - startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getResolution() {
|
||||||
|
return TIMER_RESOLUTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getFrameRate() {
|
||||||
|
return fps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getTimePerFrame() {
|
||||||
|
return tpf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update() {
|
||||||
|
tpf = (getTime() - previousTime) * (1.0f / TIMER_RESOLUTION);
|
||||||
|
if (tpf >= 0.2) {
|
||||||
|
//the frame lasted more than 200ms we erase its time to 16ms.
|
||||||
|
tpf = 0.016666f;
|
||||||
|
} else {
|
||||||
|
fps = 1.0f / tpf;
|
||||||
|
}
|
||||||
|
previousTime = getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
//startTime = System.currentTimeMillis();
|
||||||
|
startTime = System.nanoTime();
|
||||||
|
previousTime = getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -1,15 +1,22 @@
|
|||||||
package jme3test.model.anim;
|
package jme3test.model.anim;
|
||||||
|
|
||||||
import com.jme3.animation.*;
|
import com.jme3.anim.*;
|
||||||
import com.jme3.app.ChaseCameraAppState;
|
import com.jme3.app.ChaseCameraAppState;
|
||||||
import com.jme3.app.SimpleApplication;
|
import com.jme3.app.SimpleApplication;
|
||||||
|
import com.jme3.input.KeyInput;
|
||||||
|
import com.jme3.input.controls.ActionListener;
|
||||||
|
import com.jme3.input.controls.KeyTrigger;
|
||||||
import com.jme3.light.DirectionalLight;
|
import com.jme3.light.DirectionalLight;
|
||||||
import com.jme3.material.Material;
|
import com.jme3.material.Material;
|
||||||
import com.jme3.math.*;
|
import com.jme3.math.*;
|
||||||
import com.jme3.scene.*;
|
import com.jme3.scene.*;
|
||||||
import com.jme3.scene.debug.custom.ArmatureDebugAppState;
|
import com.jme3.scene.debug.custom.ArmatureDebugAppState;
|
||||||
|
import com.jme3.scene.shape.Cylinder;
|
||||||
import com.jme3.util.TangentBinormalGenerator;
|
import com.jme3.util.TangentBinormalGenerator;
|
||||||
|
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.nio.ShortBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Nehon on 18/12/2017.
|
* Created by Nehon on 18/12/2017.
|
||||||
*/
|
*/
|
||||||
@ -25,6 +32,7 @@ public class TestArmature extends SimpleApplication {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void simpleInitApp() {
|
public void simpleInitApp() {
|
||||||
|
setTimer(new EraseTimer());
|
||||||
renderManager.setSinglePassLightBatchSize(2);
|
renderManager.setSinglePassLightBatchSize(2);
|
||||||
//cam.setFrustumPerspective(90f, (float) cam.getWidth() / cam.getHeight(), 0.01f, 10f);
|
//cam.setFrustumPerspective(90f, (float) cam.getWidth() / cam.getHeight(), 0.01f, 10f);
|
||||||
viewPort.setBackgroundColor(ColorRGBA.DarkGray);
|
viewPort.setBackgroundColor(ColorRGBA.DarkGray);
|
||||||
@ -34,20 +42,61 @@ public class TestArmature extends SimpleApplication {
|
|||||||
j2 = new Joint("Joint_2");
|
j2 = new Joint("Joint_2");
|
||||||
root.addChild(j1);
|
root.addChild(j1);
|
||||||
j1.addChild(j2);
|
j1.addChild(j2);
|
||||||
j1.setLocalTranslation(new Vector3f(0, 0.5f, 0));
|
root.setLocalTranslation(new Vector3f(0, 0, 0.5f));
|
||||||
j1.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.HALF_PI * 0.3f, Vector3f.UNIT_Z));
|
j1.setLocalTranslation(new Vector3f(0, 0.0f, -0.5f));
|
||||||
j2.setLocalTranslation(new Vector3f(0, 0.2f, 0));
|
j2.setLocalTranslation(new Vector3f(0, 0.0f, -0.2f));
|
||||||
Joint[] joints = new Joint[]{root, j1, j2};
|
Joint[] joints = new Joint[]{root, j1, j2};
|
||||||
|
|
||||||
Armature armature = new Armature(joints);
|
final Armature armature = new Armature(joints);
|
||||||
armature.setBindPose();
|
armature.setBindPose();
|
||||||
|
|
||||||
ArmatureControl ac = new ArmatureControl(armature);
|
AnimClip clip = new AnimClip("anim");
|
||||||
|
float[] times = new float[]{0, 2, 4};
|
||||||
|
Quaternion[] rotations = new Quaternion[]{
|
||||||
|
new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X),
|
||||||
|
new Quaternion().fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_X),
|
||||||
|
new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X)
|
||||||
|
};
|
||||||
|
Vector3f[] translations = new Vector3f[]{
|
||||||
|
new Vector3f(0, 0.2f, 0),
|
||||||
|
new Vector3f(0, 1.0f, 0),
|
||||||
|
new Vector3f(0, 0.2f, 0),
|
||||||
|
};
|
||||||
|
Vector3f[] scales = new Vector3f[]{
|
||||||
|
new Vector3f(1, 1, 1),
|
||||||
|
new Vector3f(2, 2, 2),
|
||||||
|
new Vector3f(1, 1, 1),
|
||||||
|
};
|
||||||
|
Vector3f[] scales2 = new Vector3f[]{
|
||||||
|
new Vector3f(1, 1, 1),
|
||||||
|
new Vector3f(0.5f, 0.5f, 0.5f),
|
||||||
|
new Vector3f(1, 1, 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
JointTrack track1 = new JointTrack(j1, times, null, rotations, null);
|
||||||
|
JointTrack track2 = new JointTrack(j2, times, null, rotations, null);
|
||||||
|
clip.addTrack(track1);
|
||||||
|
clip.addTrack(track2);
|
||||||
|
|
||||||
|
final AnimComposer composer = new AnimComposer();
|
||||||
|
composer.addAnimClip(clip);
|
||||||
|
|
||||||
|
SkinningControl ac = new SkinningControl(armature);
|
||||||
|
ac.setHardwareSkinningPreferred(false);
|
||||||
Node node = new Node("Test Armature");
|
Node node = new Node("Test Armature");
|
||||||
|
|
||||||
rootNode.attachChild(node);
|
rootNode.attachChild(node);
|
||||||
|
|
||||||
|
Geometry cylinder = new Geometry("cylinder", createMesh());
|
||||||
|
Material m = new Material(assetManager, "Common/MatDefs/Misc/fakeLighting.j3md");
|
||||||
|
m.setColor("Color", ColorRGBA.randomColor());
|
||||||
|
cylinder.setMaterial(m);
|
||||||
|
node.attachChild(cylinder);
|
||||||
|
node.addControl(composer);
|
||||||
node.addControl(ac);
|
node.addControl(ac);
|
||||||
|
|
||||||
|
composer.setCurrentAnimClip("anim");
|
||||||
|
|
||||||
ArmatureDebugAppState debugAppState = new ArmatureDebugAppState();
|
ArmatureDebugAppState debugAppState = new ArmatureDebugAppState();
|
||||||
debugAppState.addArmature(ac, true);
|
debugAppState.addArmature(ac, true);
|
||||||
stateManager.attach(debugAppState);
|
stateManager.attach(debugAppState);
|
||||||
@ -71,6 +120,23 @@ public class TestArmature extends SimpleApplication {
|
|||||||
chaseCam.setMinDistance(0.01f);
|
chaseCam.setMinDistance(0.01f);
|
||||||
chaseCam.setZoomSpeed(0.01f);
|
chaseCam.setZoomSpeed(0.01f);
|
||||||
chaseCam.setDefaultVerticalRotation(0.3f);
|
chaseCam.setDefaultVerticalRotation(0.3f);
|
||||||
|
|
||||||
|
|
||||||
|
inputManager.addMapping("bind", new KeyTrigger(KeyInput.KEY_SPACE));
|
||||||
|
inputManager.addListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void onAction(String name, boolean isPressed, float tpf) {
|
||||||
|
if (isPressed) {
|
||||||
|
play = false;
|
||||||
|
composer.reset();
|
||||||
|
armature.resetToBindPose();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
play = true;
|
||||||
|
composer.setCurrentAnimClip("anim");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, "bind");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -99,14 +165,70 @@ public class TestArmature extends SimpleApplication {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Mesh createMesh() {
|
||||||
|
Cylinder c = new Cylinder(30, 16, 0.1f, 1, true);
|
||||||
|
|
||||||
|
ShortBuffer jointIndex = (ShortBuffer) VertexBuffer.createBuffer(VertexBuffer.Format.UnsignedShort, 4, c.getVertexCount());
|
||||||
|
jointIndex.rewind();
|
||||||
|
c.setMaxNumWeights(1);
|
||||||
|
FloatBuffer jointWeight = (FloatBuffer) VertexBuffer.createBuffer(VertexBuffer.Format.Float, 4, c.getVertexCount());
|
||||||
|
jointWeight.rewind();
|
||||||
|
VertexBuffer vb = c.getBuffer(VertexBuffer.Type.Position);
|
||||||
|
FloatBuffer fvb = (FloatBuffer) vb.getData();
|
||||||
|
fvb.rewind();
|
||||||
|
for (int i = 0; i < c.getVertexCount(); i++) {
|
||||||
|
fvb.get();
|
||||||
|
fvb.get();
|
||||||
|
float z = fvb.get();
|
||||||
|
int index = 0;
|
||||||
|
if (z > 0) {
|
||||||
|
index = 0;
|
||||||
|
} else if (z > -0.2) {
|
||||||
|
index = 1;
|
||||||
|
} else {
|
||||||
|
index = 2;
|
||||||
|
}
|
||||||
|
jointIndex.put((short) index).put((short) 0).put((short) 0).put((short) 0);
|
||||||
|
jointWeight.put(1f).put(0f).put(0f).put(0f);
|
||||||
|
|
||||||
|
}
|
||||||
|
c.setBuffer(VertexBuffer.Type.BoneIndex, 4, jointIndex);
|
||||||
|
c.setBuffer(VertexBuffer.Type.BoneWeight, 4, jointWeight);
|
||||||
|
|
||||||
|
c.updateCounts();
|
||||||
|
c.updateBound();
|
||||||
|
//the mesh has some skinning let's create needed buffers for HW skinning
|
||||||
|
//creating empty buffers for HW skinning
|
||||||
|
//the buffers will be setup if ever used.
|
||||||
|
VertexBuffer weightsHW = new VertexBuffer(VertexBuffer.Type.HWBoneWeight);
|
||||||
|
VertexBuffer indicesHW = new VertexBuffer(VertexBuffer.Type.HWBoneIndex);
|
||||||
|
//setting usage to cpuOnly so that the buffer is not send empty to the GPU
|
||||||
|
indicesHW.setUsage(VertexBuffer.Usage.CpuOnly);
|
||||||
|
weightsHW.setUsage(VertexBuffer.Usage.CpuOnly);
|
||||||
|
c.setBuffer(weightsHW);
|
||||||
|
c.setBuffer(indicesHW);
|
||||||
|
c.generateBindPose();
|
||||||
|
|
||||||
|
c.prepareForAnim(false);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
float time = 0;
|
float time = 0;
|
||||||
|
boolean play = true;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void simpleUpdate(float tpf) {
|
public void simpleUpdate(float tpf) {
|
||||||
time += tpf;
|
|
||||||
float rot = FastMath.sin(time);
|
|
||||||
j1.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.HALF_PI * rot, Vector3f.UNIT_Z));
|
// if (play == false) {
|
||||||
j2.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.HALF_PI * rot, Vector3f.UNIT_Z));
|
// return;
|
||||||
|
// }
|
||||||
|
// time += tpf;
|
||||||
|
// float rot = FastMath.sin(time);
|
||||||
|
// j1.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.HALF_PI * rot, Vector3f.UNIT_Z));
|
||||||
|
// j2.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.HALF_PI * rot, Vector3f.UNIT_Z));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user