Added the base of the blending system. Smooth transition between anims
This commit is contained in:
parent
dd5b90e281
commit
449429974e
@ -11,12 +11,12 @@ import java.io.IOException;
|
||||
/**
|
||||
* Created by Nehon on 20/12/2017.
|
||||
*/
|
||||
public class AnimClip implements Tween, JmeCloneable, Savable {
|
||||
public class AnimClip implements JmeCloneable, Savable {
|
||||
|
||||
private String name;
|
||||
private double length;
|
||||
|
||||
private SafeArrayList<Tween> tracks = new SafeArrayList<>(Tween.class);
|
||||
private TransformTrack[] tracks;
|
||||
|
||||
public AnimClip() {
|
||||
}
|
||||
@ -25,52 +25,27 @@ public class AnimClip implements Tween, JmeCloneable, Savable {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setTracks(Tween[] tracks) {
|
||||
for (Tween track : tracks) {
|
||||
addTrack(track);
|
||||
}
|
||||
}
|
||||
|
||||
public void addTrack(Tween track) {
|
||||
tracks.add(track);
|
||||
public void setTracks(TransformTrack[] tracks) {
|
||||
this.tracks = tracks;
|
||||
for (TransformTrack track : tracks) {
|
||||
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()) {
|
||||
if (t <= track.getLength()) {
|
||||
track.interpolate(t);
|
||||
}
|
||||
}
|
||||
return t <= length;
|
||||
public TransformTrack[] getTracks() {
|
||||
return tracks;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -84,9 +59,9 @@ public class AnimClip implements Tween, JmeCloneable, Savable {
|
||||
|
||||
@Override
|
||||
public void cloneFields(Cloner cloner, Object original) {
|
||||
SafeArrayList<Tween> newTracks = new SafeArrayList<>(Tween.class);
|
||||
for (Tween track : tracks) {
|
||||
newTracks.add(cloner.clone(track));
|
||||
TransformTrack[] newTracks = new TransformTrack[tracks.length];
|
||||
for (int i = 0; i < tracks.length; i++) {
|
||||
newTracks[i] = (cloner.clone(tracks[i]));
|
||||
}
|
||||
this.tracks = newTracks;
|
||||
}
|
||||
@ -95,7 +70,7 @@ public class AnimClip implements Tween, JmeCloneable, Savable {
|
||||
public void write(JmeExporter ex) throws IOException {
|
||||
OutputCapsule oc = ex.getCapsule(this);
|
||||
oc.write(name, "name", null);
|
||||
oc.write(tracks.getArray(), "tracks", null);
|
||||
oc.write(tracks, "tracks", null);
|
||||
|
||||
}
|
||||
|
||||
@ -105,9 +80,13 @@ public class AnimClip implements Tween, JmeCloneable, Savable {
|
||||
name = ic.readString("name", null);
|
||||
Savable[] arr = ic.readSavableArray("tracks", null);
|
||||
if (arr != null) {
|
||||
tracks = new SafeArrayList<>(Tween.class);
|
||||
for (Savable savable : arr) {
|
||||
addTrack((Tween) savable);
|
||||
tracks = new TransformTrack[arr.length];
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
TransformTrack t = (TransformTrack) arr[i];
|
||||
tracks[i] = t;
|
||||
if (t.getLength() > length) {
|
||||
length = t.getLength();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
package com.jme3.anim;
|
||||
|
||||
import com.jme3.anim.tween.AnimClipTween;
|
||||
import com.jme3.anim.tween.Tween;
|
||||
import com.jme3.anim.tween.action.Action;
|
||||
import com.jme3.anim.tween.action.SequenceAction;
|
||||
import com.jme3.export.*;
|
||||
import com.jme3.renderer.RenderManager;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
@ -16,7 +20,8 @@ public class AnimComposer extends AbstractControl {
|
||||
|
||||
private Map<String, AnimClip> animClipMap = new HashMap<>();
|
||||
|
||||
private AnimClip currentAnimClip;
|
||||
private Action currentAction;
|
||||
private Map<String, Action> actions = new HashMap<>();
|
||||
private float time;
|
||||
|
||||
/**
|
||||
@ -54,16 +59,45 @@ public class AnimComposer extends AbstractControl {
|
||||
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 setCurrentAction(String name) {
|
||||
Action action = action(name);
|
||||
if (currentAction != null) {
|
||||
currentAction.reset();
|
||||
}
|
||||
currentAction = action;
|
||||
time = 0;
|
||||
}
|
||||
|
||||
public Action action(String name) {
|
||||
Action action = actions.get(name);
|
||||
if (action == null) {
|
||||
AnimClipTween tween = tweenFromClip(name);
|
||||
action = new SequenceAction(tween);
|
||||
actions.put(name, action);
|
||||
}
|
||||
return action;
|
||||
}
|
||||
|
||||
public AnimClipTween tweenFromClip(String clipName) {
|
||||
AnimClip clip = animClipMap.get(clipName);
|
||||
if (clip == null) {
|
||||
throw new IllegalArgumentException("Cannot find clip named " + clipName);
|
||||
}
|
||||
return new AnimClipTween(clip);
|
||||
}
|
||||
|
||||
public SequenceAction actionSequence(String name, Tween... tweens) {
|
||||
SequenceAction action = new SequenceAction(tweens);
|
||||
actions.put(name, action);
|
||||
return action;
|
||||
}
|
||||
|
||||
public Action actionBlended(String name, Tween... tweens) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
currentAnimClip = null;
|
||||
currentAction = null;
|
||||
time = 0;
|
||||
}
|
||||
|
||||
@ -77,11 +111,11 @@ public class AnimComposer extends AbstractControl {
|
||||
|
||||
@Override
|
||||
protected void controlUpdate(float tpf) {
|
||||
if (currentAnimClip != null) {
|
||||
if (currentAction != null) {
|
||||
time += tpf;
|
||||
boolean running = currentAnimClip.interpolate(time);
|
||||
boolean running = currentAction.interpolate(time);
|
||||
if (!running) {
|
||||
time -= currentAnimClip.getLength();
|
||||
time -= currentAction.getLength();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -108,6 +142,11 @@ public class AnimComposer extends AbstractControl {
|
||||
for (String key : animClipMap.keySet()) {
|
||||
clips.put(key, cloner.clone(animClipMap.get(key)));
|
||||
}
|
||||
Map<String, Action> act = new HashMap<>();
|
||||
for (String key : actions.keySet()) {
|
||||
act.put(key, cloner.clone(actions.get(key)));
|
||||
}
|
||||
actions = act;
|
||||
animClipMap = clips;
|
||||
}
|
||||
|
||||
@ -116,6 +155,7 @@ public class AnimComposer extends AbstractControl {
|
||||
super.read(im);
|
||||
InputCapsule ic = im.getCapsule(this);
|
||||
animClipMap = (Map<String, AnimClip>) ic.readStringSavableMap("animClipMap", new HashMap<String, AnimClip>());
|
||||
actions = (Map<String, Action>) ic.readStringSavableMap("actions", new HashMap<String, Action>());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -123,5 +163,6 @@ public class AnimComposer extends AbstractControl {
|
||||
super.write(ex);
|
||||
OutputCapsule oc = ex.getCapsule(this);
|
||||
oc.writeStringSavableMap(animClipMap, "animClipMap", new HashMap<String, AnimClip>());
|
||||
oc.writeStringSavableMap(actions, "actions", new HashMap<String, Action>());
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.jme3.anim;
|
||||
|
||||
import com.jme3.anim.util.HasLocalTransform;
|
||||
import com.jme3.anim.util.JointModelTransform;
|
||||
import com.jme3.export.*;
|
||||
import com.jme3.material.MatParamOverride;
|
||||
@ -18,7 +19,7 @@ import java.util.List;
|
||||
* A Joint is the basic component of an armature designed to perform skeletal animation
|
||||
* Created by Nehon on 15/12/2017.
|
||||
*/
|
||||
public class Joint implements Savable, JmeCloneable {
|
||||
public class Joint implements Savable, JmeCloneable, HasLocalTransform {
|
||||
|
||||
private String name;
|
||||
private Joint parent;
|
||||
|
@ -1,108 +0,0 @@
|
||||
/*
|
||||
* 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 joint track for the given joint 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;
|
||||
this.defaultTransform = target.getLocalTransform();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean interpolate(double t) {
|
||||
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() {
|
||||
return super.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cloneFields(Cloner cloner, Object 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);
|
||||
}
|
||||
|
||||
}
|
@ -1,111 +0,0 @@
|
||||
/*
|
||||
* 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.scene.Spatial;
|
||||
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 SpatialTrack extends TransformTrack implements JmeCloneable, Savable {
|
||||
|
||||
private Spatial target;
|
||||
|
||||
/**
|
||||
* Serialization-only. Do not use.
|
||||
*/
|
||||
public SpatialTrack() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a spatial track for the given Spatial
|
||||
*
|
||||
* @param target The Spatial 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 SpatialTrack(Spatial target, float[] times, Vector3f[] translations, Quaternion[] rotations, Vector3f[] scales) {
|
||||
super(times, translations, rotations, scales);
|
||||
this.target = target;
|
||||
defaultTransform = target.getLocalTransform();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean interpolate(double t) {
|
||||
|
||||
boolean running = super.interpolate(t);
|
||||
Transform transform = getInterpolatedTransform();
|
||||
target.setLocalTransform(transform);
|
||||
return running;
|
||||
}
|
||||
|
||||
public void setTarget(Spatial target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object jmeClone() {
|
||||
return super.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cloneFields(Cloner cloner, Object 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 = (Spatial) ic.readSavable("target", null);
|
||||
}
|
||||
|
||||
}
|
@ -33,10 +33,13 @@ package com.jme3.anim;
|
||||
|
||||
import com.jme3.anim.interpolator.FrameInterpolator;
|
||||
import com.jme3.anim.tween.Tween;
|
||||
import com.jme3.anim.util.HasLocalTransform;
|
||||
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;
|
||||
|
||||
@ -45,9 +48,10 @@ import java.io.IOException;
|
||||
*
|
||||
* @author Rémy Bouquet
|
||||
*/
|
||||
public abstract class TransformTrack implements Tween, Cloneable, Savable {
|
||||
public class TransformTrack implements JmeCloneable, Savable {
|
||||
|
||||
private double length;
|
||||
private HasLocalTransform target;
|
||||
|
||||
/**
|
||||
* Transforms and times for track.
|
||||
@ -55,8 +59,6 @@ public abstract class TransformTrack implements Tween, Cloneable, Savable {
|
||||
private CompactVector3Array translations;
|
||||
private CompactQuaternionArray rotations;
|
||||
private CompactVector3Array scales;
|
||||
private Transform transform = new Transform();
|
||||
protected Transform defaultTransform = new Transform();
|
||||
private FrameInterpolator interpolator = FrameInterpolator.DEFAULT;
|
||||
private float[] times;
|
||||
|
||||
@ -74,7 +76,8 @@ public abstract class TransformTrack implements Tween, Cloneable, Savable {
|
||||
* @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) {
|
||||
public TransformTrack(HasLocalTransform target, float[] times, Vector3f[] translations, Quaternion[] rotations, Vector3f[] scales) {
|
||||
this.target = target;
|
||||
this.setKeyframes(times, translations, rotations, scales);
|
||||
}
|
||||
|
||||
@ -216,16 +219,13 @@ public abstract class TransformTrack implements Tween, Cloneable, Savable {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean interpolate(double t) {
|
||||
public void getTransformAtTime(double t, Transform transform) {
|
||||
float time = (float) t;
|
||||
|
||||
transform.set(defaultTransform);
|
||||
int lastFrame = times.length - 1;
|
||||
if (time < 0 || lastFrame == 0) {
|
||||
if (translations != null) {
|
||||
@ -237,7 +237,7 @@ public abstract class TransformTrack implements Tween, Cloneable, Savable {
|
||||
if (scales != null) {
|
||||
scales.get(0, transform.getScale());
|
||||
}
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
int startFrame = 0;
|
||||
@ -272,19 +272,20 @@ public abstract class TransformTrack implements Tween, Cloneable, Savable {
|
||||
if (scales != null) {
|
||||
transform.setScale(interpolated.getScale());
|
||||
}
|
||||
|
||||
return time < length;
|
||||
}
|
||||
|
||||
|
||||
public Transform getInterpolatedTransform() {
|
||||
return transform;
|
||||
}
|
||||
|
||||
public void setFrameInterpolator(FrameInterpolator interpolator) {
|
||||
this.interpolator = interpolator;
|
||||
}
|
||||
|
||||
public HasLocalTransform getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public void setTarget(HasLocalTransform target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JmeExporter ex) throws IOException {
|
||||
OutputCapsule oc = ex.getCapsule(this);
|
||||
@ -292,6 +293,7 @@ public abstract class TransformTrack implements Tween, Cloneable, Savable {
|
||||
oc.write(rotations, "rotations", null);
|
||||
oc.write(times, "times", null);
|
||||
oc.write(scales, "scales", null);
|
||||
oc.write(target, "target", null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -301,16 +303,22 @@ public abstract class TransformTrack implements Tween, Cloneable, Savable {
|
||||
rotations = (CompactQuaternionArray) ic.readSavable("rotations", null);
|
||||
times = ic.readFloatArray("times", null);
|
||||
scales = (CompactVector3Array) ic.readSavable("scales", null);
|
||||
target = (Joint) ic.readSavable("target", null);
|
||||
setTimes(times);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
public Object jmeClone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new RuntimeException("Error cloning", e);
|
||||
TransformTrack clone = (TransformTrack) super.clone();
|
||||
return clone;
|
||||
} catch (CloneNotSupportedException ex) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cloneFields(Cloner cloner, Object original) {
|
||||
this.target = cloner.clone(target);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,99 @@
|
||||
package com.jme3.anim.tween;
|
||||
|
||||
import com.jme3.anim.AnimClip;
|
||||
import com.jme3.anim.TransformTrack;
|
||||
import com.jme3.anim.tween.action.Action;
|
||||
import com.jme3.anim.util.HasLocalTransform;
|
||||
import com.jme3.anim.util.Weighted;
|
||||
import com.jme3.export.InputCapsule;
|
||||
import com.jme3.export.JmeExporter;
|
||||
import com.jme3.export.JmeImporter;
|
||||
import com.jme3.export.OutputCapsule;
|
||||
import com.jme3.math.Transform;
|
||||
import com.jme3.util.clone.Cloner;
|
||||
import com.jme3.util.clone.JmeCloneable;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class AnimClipTween implements Tween, Weighted, JmeCloneable {
|
||||
|
||||
private AnimClip clip;
|
||||
private Transform transform = new Transform();
|
||||
private float weight = 1f;
|
||||
private Action parentAction;
|
||||
|
||||
public AnimClipTween() {
|
||||
}
|
||||
|
||||
public AnimClipTween(AnimClip clip) {
|
||||
this.clip = clip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getLength() {
|
||||
return clip.getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean interpolate(double t) {
|
||||
// Sanity check the inputs
|
||||
if (t < 0) {
|
||||
return true;
|
||||
}
|
||||
if (parentAction != null) {
|
||||
weight = parentAction.getWeightForTween(this);
|
||||
}
|
||||
TransformTrack[] tracks = clip.getTracks();
|
||||
for (TransformTrack track : tracks) {
|
||||
HasLocalTransform target = track.getTarget();
|
||||
transform.set(target.getLocalTransform());
|
||||
track.getTransformAtTime(t, transform);
|
||||
|
||||
if (weight == 1f) {
|
||||
target.setLocalTransform(transform);
|
||||
} else {
|
||||
Transform tr = target.getLocalTransform();
|
||||
tr.interpolateTransforms(tr, transform, weight);
|
||||
target.setLocalTransform(tr);
|
||||
}
|
||||
}
|
||||
return t < clip.getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JmeExporter ex) throws IOException {
|
||||
OutputCapsule oc = ex.getCapsule(this);
|
||||
oc.write(clip, "clip", null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(JmeImporter im) throws IOException {
|
||||
InputCapsule ic = im.getCapsule(this);
|
||||
clip = (AnimClip) ic.readSavable("clip", null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object jmeClone() {
|
||||
try {
|
||||
AnimClipTween clone = (AnimClipTween) super.clone();
|
||||
return clone;
|
||||
} catch (CloneNotSupportedException ex) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cloneFields(Cloner cloner, Object original) {
|
||||
clip = cloner.clone(clip);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void setWeight(float weight) {
|
||||
// this.weight = weight;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void setParentAction(Action action) {
|
||||
this.parentAction = action;
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package com.jme3.anim.tween.action;
|
||||
|
||||
import com.jme3.anim.tween.Tween;
|
||||
import com.jme3.anim.util.Weighted;
|
||||
import com.jme3.export.InputCapsule;
|
||||
import com.jme3.export.JmeExporter;
|
||||
import com.jme3.export.JmeImporter;
|
||||
import com.jme3.export.OutputCapsule;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public abstract class Action implements Tween, Weighted {
|
||||
|
||||
protected Tween[] tweens;
|
||||
protected float weight = 1;
|
||||
protected double length;
|
||||
protected Action parentAction;
|
||||
|
||||
protected Action(Tween... tweens) {
|
||||
this.tweens = tweens;
|
||||
for (Tween tween : tweens) {
|
||||
if (tween instanceof Weighted) {
|
||||
((Weighted) tween).setParentAction(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean interpolate(double t) {
|
||||
if (parentAction != null) {
|
||||
weight = parentAction.getWeightForTween(this);
|
||||
}
|
||||
|
||||
return doInterpolate(t);
|
||||
}
|
||||
|
||||
public abstract float getWeightForTween(Tween tween);
|
||||
|
||||
public abstract boolean doInterpolate(double t);
|
||||
|
||||
public abstract void reset();
|
||||
|
||||
@Override
|
||||
public void setParentAction(Action parentAction) {
|
||||
this.parentAction = parentAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(JmeImporter im) throws IOException {
|
||||
InputCapsule ic = im.getCapsule(this);
|
||||
tweens = (Tween[]) ic.readSavableArray("tweens", null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JmeExporter ex) throws IOException {
|
||||
OutputCapsule oc = ex.getCapsule(this);
|
||||
oc.write(tweens, "tweens", null);
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package com.jme3.anim.tween.action;
|
||||
|
||||
import com.jme3.anim.tween.AbstractTween;
|
||||
import com.jme3.anim.tween.Tween;
|
||||
|
||||
public class SequenceAction extends Action {
|
||||
|
||||
private int currentIndex = 0;
|
||||
private double accumTime;
|
||||
private double transitionTime = 0;
|
||||
private float mainWeight = 1.0f;
|
||||
private double transitionLength = 0.4f;
|
||||
private TransitionTween transition = new TransitionTween(transitionLength);
|
||||
|
||||
|
||||
public SequenceAction(Tween... tweens) {
|
||||
super(tweens);
|
||||
for (Tween tween : tweens) {
|
||||
length += tween.getLength();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getWeightForTween(Tween tween) {
|
||||
return weight * mainWeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doInterpolate(double t) {
|
||||
Tween currentTween = tweens[currentIndex];
|
||||
if (transition.getLength() > currentTween.getLength()) {
|
||||
transition.setLength(currentTween.getLength());
|
||||
}
|
||||
|
||||
transition.interpolate(t - transitionTime);
|
||||
|
||||
boolean running = currentTween.interpolate(t - accumTime);
|
||||
if (!running) {
|
||||
accumTime += currentTween.getLength();
|
||||
currentIndex++;
|
||||
transitionTime = accumTime;
|
||||
transition.setLength(transitionLength);
|
||||
}
|
||||
|
||||
if (t >= length) {
|
||||
reset();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
currentIndex = 0;
|
||||
accumTime = 0;
|
||||
transitionTime = 0;
|
||||
mainWeight = 1;
|
||||
}
|
||||
|
||||
public void setTransitionLength(double transitionLength) {
|
||||
this.transitionLength = transitionLength;
|
||||
}
|
||||
|
||||
private class TransitionTween extends AbstractTween {
|
||||
|
||||
|
||||
public TransitionTween(double length) {
|
||||
super(length);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doInterpolate(double t) {
|
||||
mainWeight = (float) t;
|
||||
}
|
||||
}
|
||||
}
|
@ -61,10 +61,14 @@ public class AnimMigrationUtils {
|
||||
armature.setBindPose();
|
||||
skeletonArmatureMap.put(skeleton, armature);
|
||||
|
||||
List<TransformTrack> tracks = new ArrayList<>();
|
||||
|
||||
for (String animName : control.getAnimationNames()) {
|
||||
tracks.clear();
|
||||
Animation anim = control.getAnim(animName);
|
||||
AnimClip clip = new AnimClip(animName);
|
||||
Joint[] staticJoints = new Joint[joints.length];
|
||||
|
||||
System.arraycopy(joints, 0, staticJoints, 0, joints.length);
|
||||
for (Track track : anim.getTracks()) {
|
||||
if (track instanceof BoneTrack) {
|
||||
@ -72,17 +76,20 @@ public class AnimMigrationUtils {
|
||||
int index = boneTrack.getTargetBoneIndex();
|
||||
Bone bone = skeleton.getBone(index);
|
||||
Joint joint = joints[index];
|
||||
JointTrack jointTrack = fromBoneTrack(boneTrack, bone, joint);
|
||||
clip.addTrack(jointTrack);
|
||||
TransformTrack jointTrack = fromBoneTrack(boneTrack, bone, joint);
|
||||
tracks.add(jointTrack);
|
||||
//this joint is animated let's remove it from the static joints
|
||||
staticJoints[index] = null;
|
||||
}
|
||||
//TODO spatial tracks , Effect tracks, Audio tracks
|
||||
}
|
||||
|
||||
for (int i = 0; i < staticJoints.length; i++) {
|
||||
padJointTracks(clip, staticJoints[i]);
|
||||
padJointTracks(tracks, staticJoints[i]);
|
||||
}
|
||||
|
||||
clip.setTracks(tracks.toArray(new TransformTrack[tracks.size()]));
|
||||
|
||||
composer.addAnimClip(clip);
|
||||
}
|
||||
spatial.removeControl(control);
|
||||
@ -95,7 +102,7 @@ public class AnimMigrationUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static void padJointTracks(AnimClip clip, Joint staticJoint) {
|
||||
public static void padJointTracks(List<TransformTrack> tracks, Joint staticJoint) {
|
||||
Joint j = staticJoint;
|
||||
if (j != null) {
|
||||
// joint has no track , we create one with the default pose
|
||||
@ -103,8 +110,8 @@ public class AnimMigrationUtils {
|
||||
Vector3f[] translations = new Vector3f[]{j.getLocalTranslation()};
|
||||
Quaternion[] rotations = new Quaternion[]{j.getLocalRotation()};
|
||||
Vector3f[] scales = new Vector3f[]{j.getLocalScale()};
|
||||
JointTrack track = new JointTrack(j, times, translations, rotations, scales);
|
||||
clip.addTrack(track);
|
||||
TransformTrack track = new TransformTrack(j, times, translations, rotations, scales);
|
||||
tracks.add(track);
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,7 +151,7 @@ public class AnimMigrationUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static JointTrack fromBoneTrack(BoneTrack boneTrack, Bone bone, Joint joint) {
|
||||
public static TransformTrack fromBoneTrack(BoneTrack boneTrack, Bone bone, Joint joint) {
|
||||
float[] times = new float[boneTrack.getTimes().length];
|
||||
int length = times.length;
|
||||
System.arraycopy(boneTrack.getTimes(), 0, times, 0, length);
|
||||
@ -178,8 +185,8 @@ public class AnimMigrationUtils {
|
||||
scales[i] = newScale;
|
||||
}
|
||||
}
|
||||
|
||||
return new JointTrack(joint, times, translations, rotations, scales);
|
||||
TransformTrack t = new TransformTrack(joint, times, translations, rotations, scales);
|
||||
return t;
|
||||
}
|
||||
|
||||
private static Joint fromBone(Bone b) {
|
||||
|
@ -0,0 +1,10 @@
|
||||
package com.jme3.anim.util;
|
||||
|
||||
import com.jme3.export.Savable;
|
||||
import com.jme3.math.Transform;
|
||||
|
||||
public interface HasLocalTransform extends Savable {
|
||||
public void setLocalTransform(Transform transform);
|
||||
|
||||
public Transform getLocalTransform();
|
||||
}
|
11
jme3-core/src/main/java/com/jme3/anim/util/Weighted.java
Normal file
11
jme3-core/src/main/java/com/jme3/anim/util/Weighted.java
Normal file
@ -0,0 +1,11 @@
|
||||
package com.jme3.anim.util;
|
||||
|
||||
import com.jme3.anim.tween.action.Action;
|
||||
import com.jme3.math.Transform;
|
||||
|
||||
public interface Weighted {
|
||||
|
||||
// public void setWeight(float weight);
|
||||
|
||||
public void setParentAction(Action action);
|
||||
}
|
@ -176,7 +176,7 @@ public final class Transform implements Savable, Cloneable, java.io.Serializable
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this matrix to the interpolation between the first matrix and the second by delta amount.
|
||||
* Sets this transform to the interpolation between the first transform and the second by delta amount.
|
||||
* @param t1 The beginning transform.
|
||||
* @param t2 The ending transform.
|
||||
* @param delta An amount between 0 and 1 representing how far to interpolate from t1 to t2.
|
||||
|
@ -31,6 +31,7 @@
|
||||
*/
|
||||
package com.jme3.scene;
|
||||
|
||||
import com.jme3.anim.util.HasLocalTransform;
|
||||
import com.jme3.asset.AssetKey;
|
||||
import com.jme3.asset.CloneableSmartAsset;
|
||||
import com.jme3.bounding.BoundingVolume;
|
||||
@ -67,7 +68,7 @@ import java.util.logging.Logger;
|
||||
* @author Joshua Slack
|
||||
* @version $Revision: 4075 $, $Data$
|
||||
*/
|
||||
public abstract class Spatial implements Savable, Cloneable, Collidable, CloneableSmartAsset, JmeCloneable {
|
||||
public abstract class Spatial implements Savable, Cloneable, Collidable, CloneableSmartAsset, JmeCloneable, HasLocalTransform {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Spatial.class.getName());
|
||||
|
||||
|
@ -2,8 +2,8 @@ void main(){
|
||||
startPos.xy = (startPos * 0.5 + 0.5).xy * resolution;
|
||||
float len = distance(gl_FragCoord.xy,startPos.xy);
|
||||
outColor = inColor;
|
||||
float factor = int(len * 0.25);
|
||||
if(mod(factor, 2) > 0.0){
|
||||
float factor = float(int(len * 0.25));
|
||||
if(mod(factor, 2.0) > 0.0){
|
||||
discard;
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ public class TestOgreConvert extends SimpleApplication {
|
||||
Node ogreModelReloaded = (Node) imp.load(bais, null, null);
|
||||
|
||||
AnimComposer composer = ogreModelReloaded.getControl(AnimComposer.class);
|
||||
composer.setCurrentAnimClip("Walk");
|
||||
composer.setCurrentAction("Walk");
|
||||
|
||||
rootNode.attachChild(ogreModelReloaded);
|
||||
} catch (IOException ex){
|
||||
|
@ -116,9 +116,9 @@ public class TestGltfLoading extends SimpleApplication {
|
||||
//loadModel("Models/gltf/elephant/scene.gltf", new Vector3f(0, -1, 0), 0.01f);
|
||||
//loadModel("Models/gltf/buffalo/scene.gltf", new Vector3f(0, -1, 0), 0.1f);
|
||||
//loadModel("Models/gltf/war/scene.gltf", new Vector3f(0, -1, 0), 0.1f);
|
||||
loadModel("Models/gltf/ganjaarl/scene.gltf", new Vector3f(0, -1, 0), 0.01f);
|
||||
//loadModel("Models/gltf/ganjaarl/scene.gltf", new Vector3f(0, -1, 0), 0.01f);
|
||||
//loadModel("Models/gltf/hero/scene.gltf", new Vector3f(0, -1, 0), 0.1f);
|
||||
//loadModel("Models/gltf/mercy/scene.gltf", new Vector3f(0, -1, 0), 0.01f);
|
||||
loadModel("Models/gltf/mercy/scene.gltf", new Vector3f(0, -1, 0), 0.01f);
|
||||
//loadModel("Models/gltf/crab/scene.gltf", Vector3f.ZERO, 1);
|
||||
//loadModel("Models/gltf/manta/scene.gltf", Vector3f.ZERO, 0.2f);
|
||||
//loadModel("Models/gltf/bone/scene.gltf", Vector3f.ZERO, 0.1f);
|
||||
@ -190,7 +190,7 @@ public class TestGltfLoading extends SimpleApplication {
|
||||
if (isPressed && composer != null) {
|
||||
String anim = anims.poll();
|
||||
anims.add(anim);
|
||||
composer.setCurrentAnimClip(anim);
|
||||
composer.setCurrentAction(anim);
|
||||
}
|
||||
}
|
||||
}, "nextAnim");
|
||||
@ -262,7 +262,7 @@ public class TestGltfLoading extends SimpleApplication {
|
||||
}
|
||||
String anim = anims.poll();
|
||||
anims.add(anim);
|
||||
control.setCurrentAnimClip(anim);
|
||||
control.setCurrentAction(anim);
|
||||
composer = control;
|
||||
}
|
||||
if (s instanceof Node) {
|
||||
|
@ -2,6 +2,7 @@ package jme3test.model.anim;
|
||||
|
||||
import com.jme3.anim.AnimComposer;
|
||||
import com.jme3.anim.SkinningControl;
|
||||
import com.jme3.anim.util.AnimMigrationUtils;
|
||||
import com.jme3.app.ChaseCameraAppState;
|
||||
import com.jme3.app.SimpleApplication;
|
||||
import com.jme3.input.KeyInput;
|
||||
@ -24,8 +25,8 @@ public class TestAnimMigration extends SimpleApplication {
|
||||
|
||||
ArmatureDebugAppState debugAppState;
|
||||
AnimComposer composer;
|
||||
Queue<String> anims = new LinkedList<>();
|
||||
boolean playAnim = true;
|
||||
LinkedList<String> anims = new LinkedList<>();
|
||||
boolean playAnim = false;
|
||||
|
||||
public static void main(String... argv) {
|
||||
TestAnimMigration app = new TestAnimMigration();
|
||||
@ -40,12 +41,12 @@ public class TestAnimMigration extends SimpleApplication {
|
||||
rootNode.addLight(new DirectionalLight(new Vector3f(-1, -1, -1).normalizeLocal()));
|
||||
rootNode.addLight(new AmbientLight(ColorRGBA.DarkGray));
|
||||
|
||||
//Spatial model = assetManager.loadModel("Models/Jaime/Jaime.j3o");
|
||||
Spatial model = assetManager.loadModel("Models/Oto/Oto.mesh.xml").scale(0.2f).move(0, 1, 0);
|
||||
Spatial model = assetManager.loadModel("Models/Jaime/Jaime.j3o");
|
||||
// Spatial model = assetManager.loadModel("Models/Oto/Oto.mesh.xml").scale(0.2f).move(0, 1, 0);
|
||||
//Spatial model = assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml");
|
||||
//Spatial model = assetManager.loadModel("Models/Elephant/Elephant.mesh.xml").scale(0.02f);
|
||||
|
||||
// AnimMigrationUtils.migrate(model);
|
||||
AnimMigrationUtils.migrate(model);
|
||||
|
||||
rootNode.attachChild(model);
|
||||
|
||||
@ -87,7 +88,7 @@ public class TestAnimMigration extends SimpleApplication {
|
||||
if (playAnim) {
|
||||
String anim = anims.poll();
|
||||
anims.add(anim);
|
||||
composer.setCurrentAnimClip(anim);
|
||||
composer.setCurrentAction(anim);
|
||||
System.err.println(anim);
|
||||
} else {
|
||||
composer.reset();
|
||||
@ -102,7 +103,7 @@ public class TestAnimMigration extends SimpleApplication {
|
||||
if (isPressed && composer != null) {
|
||||
String anim = anims.poll();
|
||||
anims.add(anim);
|
||||
composer.setCurrentAnimClip(anim);
|
||||
composer.setCurrentAction(anim);
|
||||
System.err.println(anim);
|
||||
}
|
||||
}
|
||||
@ -132,13 +133,26 @@ public class TestAnimMigration extends SimpleApplication {
|
||||
for (String name : composer.getAnimClipsNames()) {
|
||||
anims.add(name);
|
||||
}
|
||||
composer.actionSequence("Sequence",
|
||||
composer.tweenFromClip("Walk"),
|
||||
composer.tweenFromClip("Run"),
|
||||
composer.tweenFromClip("Jumping"));
|
||||
|
||||
// composer.actionSequence("Sequence",
|
||||
// composer.tweenFromClip("Walk"),
|
||||
// composer.tweenFromClip("Dodge"),
|
||||
// composer.tweenFromClip("push"));
|
||||
|
||||
|
||||
anims.addFirst("Sequence");
|
||||
|
||||
if (anims.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (playAnim) {
|
||||
String anim = anims.poll();
|
||||
anims.add(anim);
|
||||
composer.setCurrentAnimClip(anim);
|
||||
composer.setCurrentAction(anim);
|
||||
System.err.println(anim);
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ public class TestAnimSerialization extends SimpleApplication {
|
||||
if (playAnim) {
|
||||
String anim = anims.poll();
|
||||
anims.add(anim);
|
||||
composer.setCurrentAnimClip(anim);
|
||||
composer.setCurrentAction(anim);
|
||||
System.err.println(anim);
|
||||
} else {
|
||||
composer.reset();
|
||||
@ -117,7 +117,7 @@ public class TestAnimSerialization extends SimpleApplication {
|
||||
if (isPressed && composer != null) {
|
||||
String anim = anims.poll();
|
||||
anims.add(anim);
|
||||
composer.setCurrentAnimClip(anim);
|
||||
composer.setCurrentAction(anim);
|
||||
System.err.println(anim);
|
||||
}
|
||||
}
|
||||
@ -144,7 +144,7 @@ public class TestAnimSerialization extends SimpleApplication {
|
||||
if (playAnim) {
|
||||
String anim = anims.poll();
|
||||
anims.add(anim);
|
||||
composer.setCurrentAnimClip(anim);
|
||||
composer.setCurrentAction(anim);
|
||||
System.err.println(anim);
|
||||
}
|
||||
|
||||
|
@ -78,10 +78,10 @@ public class TestArmature extends SimpleApplication {
|
||||
new Vector3f(1, 1, 1),
|
||||
};
|
||||
|
||||
JointTrack track1 = new JointTrack(j1, times, null, rotations, scales);
|
||||
JointTrack track2 = new JointTrack(j2, times, null, rotations, null);
|
||||
clip.addTrack(track1);
|
||||
clip.addTrack(track2);
|
||||
TransformTrack track1 = new TransformTrack(j1, times, null, rotations, scales);
|
||||
TransformTrack track2 = new TransformTrack(j2, times, null, rotations, null);
|
||||
|
||||
clip.setTracks(new TransformTrack[]{track1, track2});
|
||||
|
||||
//create the animComposer control
|
||||
final AnimComposer composer = new AnimComposer();
|
||||
@ -103,7 +103,7 @@ public class TestArmature extends SimpleApplication {
|
||||
node.addControl(composer);
|
||||
node.addControl(ac);
|
||||
|
||||
composer.setCurrentAnimClip("anim");
|
||||
composer.setCurrentAction("anim");
|
||||
|
||||
ArmatureDebugAppState debugAppState = new ArmatureDebugAppState();
|
||||
debugAppState.addArmatureFrom(ac);
|
||||
@ -134,7 +134,7 @@ public class TestArmature extends SimpleApplication {
|
||||
armature.resetToBindPose();
|
||||
|
||||
} else {
|
||||
composer.setCurrentAnimClip("anim");
|
||||
composer.setCurrentAction("anim");
|
||||
}
|
||||
}
|
||||
}, "bind");
|
||||
|
@ -85,10 +85,10 @@ public class TestBaseAnimSerialization extends SimpleApplication {
|
||||
new Vector3f(1, 1, 1),
|
||||
};
|
||||
|
||||
JointTrack track1 = new JointTrack(j1, times, null, rotations, scales);
|
||||
JointTrack track2 = new JointTrack(j2, times, null, rotations, null);
|
||||
clip.addTrack(track1);
|
||||
clip.addTrack(track2);
|
||||
TransformTrack track1 = new TransformTrack(j1, times, null, rotations, scales);
|
||||
TransformTrack track2 = new TransformTrack(j2, times, null, rotations, null);
|
||||
|
||||
clip.setTracks(new TransformTrack[]{track1, track2});
|
||||
|
||||
//create the animComposer control
|
||||
composer = new AnimComposer();
|
||||
@ -125,7 +125,7 @@ public class TestBaseAnimSerialization extends SimpleApplication {
|
||||
ac = newNode.getControl(SkinningControl.class);
|
||||
ac.setHardwareSkinningPreferred(false);
|
||||
armature = ac.getArmature();
|
||||
composer.setCurrentAnimClip("anim");
|
||||
composer.setCurrentAction("anim");
|
||||
|
||||
ArmatureDebugAppState debugAppState = new ArmatureDebugAppState();
|
||||
debugAppState.addArmatureFrom(ac);
|
||||
@ -156,7 +156,7 @@ public class TestBaseAnimSerialization extends SimpleApplication {
|
||||
armature.resetToBindPose();
|
||||
|
||||
} else {
|
||||
composer.setCurrentAnimClip("anim");
|
||||
composer.setCurrentAction("anim");
|
||||
}
|
||||
}
|
||||
}, "bind");
|
||||
|
@ -48,9 +48,9 @@ import java.util.List;
|
||||
public class TestHWSkinning extends SimpleApplication implements ActionListener{
|
||||
|
||||
|
||||
private AnimComposer composer;
|
||||
// private AnimComposer composer;
|
||||
private String[] animNames = {"Dodge", "Walk", "pull", "push"};
|
||||
private final static int SIZE = 50;
|
||||
private final static int SIZE = 40;
|
||||
private boolean hwSkinningEnable = true;
|
||||
private List<SkinningControl> skControls = new ArrayList<SkinningControl>();
|
||||
private BitmapText hwsText;
|
||||
@ -80,9 +80,9 @@ public class TestHWSkinning extends SimpleApplication implements ActionListener{
|
||||
Spatial model = (Spatial) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
|
||||
model.setLocalScale(0.1f);
|
||||
model.setLocalTranslation(i - SIZE / 2, 0, j - SIZE / 2);
|
||||
composer = model.getControl(AnimComposer.class);
|
||||
AnimComposer composer = model.getControl(AnimComposer.class);
|
||||
|
||||
composer.setCurrentAnimClip(animNames[(i + j) % 4]);
|
||||
composer.setCurrentAction(animNames[(i + j) % 4]);
|
||||
SkinningControl skinningControl = model.getControl(SkinningControl.class);
|
||||
skinningControl.setHardwareSkinningPreferred(hwSkinningEnable);
|
||||
skControls.add(skinningControl);
|
||||
|
@ -60,19 +60,19 @@ public class TestModelExportingCloning extends SimpleApplication {
|
||||
|
||||
Spatial originalModel = assetManager.loadModel("Models/Oto/Oto.mesh.xml");
|
||||
composer = originalModel.getControl(AnimComposer.class);
|
||||
composer.setCurrentAnimClip("Walk");
|
||||
composer.setCurrentAction("Walk");
|
||||
rootNode.attachChild(originalModel);
|
||||
|
||||
Spatial clonedModel = originalModel.clone();
|
||||
clonedModel.move(10, 0, 0);
|
||||
composer = clonedModel.getControl(AnimComposer.class);
|
||||
composer.setCurrentAnimClip("push");
|
||||
composer.setCurrentAction("push");
|
||||
rootNode.attachChild(clonedModel);
|
||||
|
||||
Spatial exportedModel = BinaryExporter.saveAndLoad(assetManager, originalModel);
|
||||
exportedModel.move(20, 0, 0);
|
||||
composer = exportedModel.getControl(AnimComposer.class);
|
||||
composer.setCurrentAnimClip("pull");
|
||||
composer.setCurrentAction("pull");
|
||||
rootNode.attachChild(exportedModel);
|
||||
}
|
||||
}
|
||||
|
@ -793,6 +793,7 @@ public class GltfLoader implements AssetLoader {
|
||||
|
||||
List<Spatial> spatials = new ArrayList<>();
|
||||
AnimClip anim = new AnimClip(name);
|
||||
List<TransformTrack> ttracks = new ArrayList<>();
|
||||
int skinIndex = -1;
|
||||
|
||||
List<Joint> usedJoints = new ArrayList<>();
|
||||
@ -806,8 +807,8 @@ public class GltfLoader implements AssetLoader {
|
||||
if (node instanceof Spatial) {
|
||||
Spatial s = (Spatial) node;
|
||||
spatials.add(s);
|
||||
SpatialTrack track = new SpatialTrack(s, trackData.times, trackData.translations, trackData.rotations, trackData.scales);
|
||||
anim.addTrack(track);
|
||||
TransformTrack track = new TransformTrack(s, trackData.times, trackData.translations, trackData.rotations, trackData.scales);
|
||||
ttracks.add(track);
|
||||
} else if (node instanceof JointWrapper) {
|
||||
JointWrapper jw = (JointWrapper) node;
|
||||
usedJoints.add(jw.joint);
|
||||
@ -822,8 +823,8 @@ public class GltfLoader implements AssetLoader {
|
||||
}
|
||||
}
|
||||
|
||||
JointTrack track = new JointTrack(jw.joint, trackData.times, trackData.translations, trackData.rotations, trackData.scales);
|
||||
anim.addTrack(track);
|
||||
TransformTrack track = new TransformTrack(jw.joint, trackData.times, trackData.translations, trackData.rotations, trackData.scales);
|
||||
ttracks.add(track);
|
||||
|
||||
}
|
||||
}
|
||||
@ -834,19 +835,21 @@ public class GltfLoader implements AssetLoader {
|
||||
if (skinIndex != -1) {
|
||||
SkinData skin = fetchFromCache("skins", skinIndex, SkinData.class);
|
||||
for (Joint joint : skin.joints) {
|
||||
if (!usedJoints.contains(joint)) {// && !equalBindAndLocalTransforms(joint)
|
||||
if (!usedJoints.contains(joint)) {
|
||||
//create a track
|
||||
float[] times = new float[]{0};
|
||||
|
||||
Vector3f[] translations = new Vector3f[]{joint.getLocalTranslation()};
|
||||
Quaternion[] rotations = new Quaternion[]{joint.getLocalRotation()};
|
||||
Vector3f[] scales = new Vector3f[]{joint.getLocalScale()};
|
||||
JointTrack track = new JointTrack(joint, times, translations, rotations, scales);
|
||||
anim.addTrack(track);
|
||||
TransformTrack track = new TransformTrack(joint, times, translations, rotations, scales);
|
||||
ttracks.add(track);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
anim.setTracks(ttracks.toArray(new TransformTrack[ttracks.size()]));
|
||||
|
||||
anim = customContentManager.readExtensionAndExtras("animations", animation, anim);
|
||||
|
||||
if (skinIndex != -1) {
|
||||
|
@ -54,16 +54,16 @@ public class SkeletonLoader extends DefaultHandler implements AssetLoader {
|
||||
private Stack<String> elementStack = new Stack<String>();
|
||||
private HashMap<Integer, Joint> indexToJoint = new HashMap<>();
|
||||
private HashMap<String, Joint> nameToJoint = new HashMap<>();
|
||||
private JointTrack track;
|
||||
private ArrayList<JointTrack> tracks = new ArrayList<>();
|
||||
private TransformTrack track;
|
||||
private ArrayList<TransformTrack> tracks = new ArrayList<>();
|
||||
private AnimClip animClip;
|
||||
private ArrayList<AnimClip> animClips;
|
||||
private Joint joint;
|
||||
private Armature armature;
|
||||
private ArrayList<Float> times = new ArrayList<Float>();
|
||||
private ArrayList<Vector3f> translations = new ArrayList<Vector3f>();
|
||||
private ArrayList<Quaternion> rotations = new ArrayList<Quaternion>();
|
||||
private ArrayList<Vector3f> scales = new ArrayList<Vector3f>();
|
||||
private ArrayList<Float> times = new ArrayList<>();
|
||||
private ArrayList<Vector3f> translations = new ArrayList<>();
|
||||
private ArrayList<Quaternion> rotations = new ArrayList<>();
|
||||
private ArrayList<Vector3f> scales = new ArrayList<>();
|
||||
private float time = -1;
|
||||
private Vector3f position;
|
||||
private Quaternion rotation;
|
||||
@ -92,7 +92,7 @@ public class SkeletonLoader extends DefaultHandler implements AssetLoader {
|
||||
assert elementStack.peek().equals("tracks");
|
||||
String jointName = SAXUtil.parseString(attribs.getValue("bone"));
|
||||
joint = nameToJoint.get(jointName);
|
||||
track = new JointTrack();
|
||||
track = new TransformTrack();
|
||||
track.setTarget(joint);
|
||||
} else if (qName.equals("boneparent")) {
|
||||
assert elementStack.peek().equals("bonehierarchy");
|
||||
@ -163,10 +163,6 @@ public class SkeletonLoader extends DefaultHandler implements AssetLoader {
|
||||
armature = new Armature(joints);
|
||||
armature.setBindPose();
|
||||
} else if (qName.equals("animation")) {
|
||||
//nameToJoint contains the joints with no track
|
||||
for (Joint j : unusedJoints) {
|
||||
AnimMigrationUtils.padJointTracks(animClip, j);
|
||||
}
|
||||
animClips.add(animClip);
|
||||
animClip = null;
|
||||
} else if (qName.equals("track")) {
|
||||
@ -176,7 +172,11 @@ public class SkeletonLoader extends DefaultHandler implements AssetLoader {
|
||||
track = null;
|
||||
}
|
||||
} else if (qName.equals("tracks")) {
|
||||
JointTrack[] trackList = tracks.toArray(new JointTrack[tracks.size()]);
|
||||
//nameToJoint contains the joints with no track
|
||||
for (Joint j : unusedJoints) {
|
||||
AnimMigrationUtils.padJointTracks(tracks, j);
|
||||
}
|
||||
TransformTrack[] trackList = tracks.toArray(new TransformTrack[tracks.size()]);
|
||||
animClip.setTracks(trackList);
|
||||
tracks.clear();
|
||||
} else if (qName.equals("keyframe")) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user