New anim system proper serialization
This commit is contained in:
parent
a4267393e1
commit
a1a9486424
@ -105,7 +105,7 @@ public class AnimClip implements Tween, JmeCloneable, Savable {
|
|||||||
if (arr != null) {
|
if (arr != null) {
|
||||||
tracks = new SafeArrayList<>(Tween.class);
|
tracks = new SafeArrayList<>(Tween.class);
|
||||||
for (Savable savable : arr) {
|
for (Savable savable : arr) {
|
||||||
tracks.add((Tween) savable);
|
addTrack((Tween) savable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package com.jme3.anim;
|
package com.jme3.anim;
|
||||||
|
|
||||||
|
import com.jme3.export.*;
|
||||||
import com.jme3.renderer.RenderManager;
|
import com.jme3.renderer.RenderManager;
|
||||||
import com.jme3.renderer.ViewPort;
|
import com.jme3.renderer.ViewPort;
|
||||||
import com.jme3.scene.control.AbstractControl;
|
import com.jme3.scene.control.AbstractControl;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -87,4 +90,38 @@ public class AnimComposer extends AbstractControl {
|
|||||||
protected void controlRender(RenderManager rm, ViewPort vp) {
|
protected void controlRender(RenderManager rm, ViewPort vp) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
try {
|
||||||
|
AnimComposer clone = (AnimComposer) super.clone();
|
||||||
|
return clone;
|
||||||
|
} catch (CloneNotSupportedException ex) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields(Cloner cloner, Object original) {
|
||||||
|
super.cloneFields(cloner, original);
|
||||||
|
Map<String, AnimClip> clips = new HashMap<>();
|
||||||
|
for (String key : animClipMap.keySet()) {
|
||||||
|
clips.put(key, cloner.clone(animClipMap.get(key)));
|
||||||
|
}
|
||||||
|
animClipMap = clips;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(JmeImporter im) throws IOException {
|
||||||
|
super.read(im);
|
||||||
|
InputCapsule ic = im.getCapsule(this);
|
||||||
|
animClipMap = (Map<String, AnimClip>) ic.readStringSavableMap("animClipMap", new HashMap<String, AnimClip>());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(JmeExporter ex) throws IOException {
|
||||||
|
super.write(ex);
|
||||||
|
OutputCapsule oc = ex.getCapsule(this);
|
||||||
|
oc.writeStringSavableMap(animClipMap, "animClipMap", new HashMap<String, AnimClip>());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.jme3.anim;
|
package com.jme3.anim;
|
||||||
|
|
||||||
import com.jme3.anim.util.JointModelTransform;
|
import com.jme3.anim.util.JointModelTransform;
|
||||||
|
import com.jme3.asset.AssetLoadException;
|
||||||
import com.jme3.export.*;
|
import com.jme3.export.*;
|
||||||
import com.jme3.math.Matrix4f;
|
import com.jme3.math.Matrix4f;
|
||||||
import com.jme3.util.clone.Cloner;
|
import com.jme3.util.clone.Cloner;
|
||||||
@ -46,11 +47,7 @@ public class Armature implements JmeCloneable, Savable {
|
|||||||
List<Joint> rootJointList = new ArrayList<>();
|
List<Joint> rootJointList = new ArrayList<>();
|
||||||
for (int i = jointList.length - 1; i >= 0; i--) {
|
for (int i = jointList.length - 1; i >= 0; i--) {
|
||||||
Joint joint = jointList[i];
|
Joint joint = jointList[i];
|
||||||
try {
|
instanciateJointModelTransform(joint);
|
||||||
joint.setJointModelTransform(modelTransformClass.newInstance());
|
|
||||||
} catch (InstantiationException | IllegalAccessException e) {
|
|
||||||
throw new IllegalArgumentException(e);
|
|
||||||
}
|
|
||||||
if (joint.getParent() == null) {
|
if (joint.getParent() == null) {
|
||||||
rootJointList.add(joint);
|
rootJointList.add(joint);
|
||||||
}
|
}
|
||||||
@ -94,11 +91,15 @@ public class Armature implements JmeCloneable, Savable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (Joint joint : jointList) {
|
for (Joint joint : jointList) {
|
||||||
try {
|
instanciateJointModelTransform(joint);
|
||||||
joint.setJointModelTransform(modelTransformClass.newInstance());
|
}
|
||||||
} catch (InstantiationException | IllegalAccessException e) {
|
}
|
||||||
throw new IllegalArgumentException(e);
|
|
||||||
}
|
private void instanciateJointModelTransform(Joint joint) {
|
||||||
|
try {
|
||||||
|
joint.setJointModelTransform(modelTransformClass.newInstance());
|
||||||
|
} catch (InstantiationException | IllegalAccessException e) {
|
||||||
|
throw new IllegalArgumentException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,6 +227,9 @@ public class Armature implements JmeCloneable, Savable {
|
|||||||
this.rootJoints = cloner.clone(rootJoints);
|
this.rootJoints = cloner.clone(rootJoints);
|
||||||
this.jointList = cloner.clone(jointList);
|
this.jointList = cloner.clone(jointList);
|
||||||
this.skinningMatrixes = cloner.clone(skinningMatrixes);
|
this.skinningMatrixes = cloner.clone(skinningMatrixes);
|
||||||
|
for (Joint joint : jointList) {
|
||||||
|
instanciateJointModelTransform(joint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -241,11 +245,22 @@ public class Armature implements JmeCloneable, Savable {
|
|||||||
jointList = new Joint[jointListAsSavable.length];
|
jointList = new Joint[jointListAsSavable.length];
|
||||||
System.arraycopy(jointListAsSavable, 0, jointList, 0, jointListAsSavable.length);
|
System.arraycopy(jointListAsSavable, 0, jointList, 0, jointListAsSavable.length);
|
||||||
|
|
||||||
|
String className = input.readString("modelTransformClass", MatrixJointModelTransform.class.getCanonicalName());
|
||||||
|
try {
|
||||||
|
modelTransformClass = (Class<? extends JointModelTransform>) Class.forName(className);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new AssetLoadException("Cannnot find class for name " + className);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Joint joint : jointList) {
|
||||||
|
instanciateJointModelTransform(joint);
|
||||||
|
}
|
||||||
createSkinningMatrices();
|
createSkinningMatrices();
|
||||||
|
|
||||||
for (Joint rootJoint : rootJoints) {
|
for (Joint rootJoint : rootJoints) {
|
||||||
rootJoint.update();
|
rootJoint.update();
|
||||||
}
|
}
|
||||||
|
resetToBindPose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -253,5 +268,6 @@ public class Armature implements JmeCloneable, Savable {
|
|||||||
OutputCapsule output = ex.getCapsule(this);
|
OutputCapsule output = ex.getCapsule(this);
|
||||||
output.write(rootJoints, "rootJoints", null);
|
output.write(rootJoints, "rootJoints", null);
|
||||||
output.write(jointList, "jointList", null);
|
output.write(jointList, "jointList", null);
|
||||||
|
output.write(modelTransformClass.getCanonicalName(), "modelTransformClass", MatrixJointModelTransform.class.getCanonicalName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -259,10 +259,10 @@ public class Joint implements Savable, JmeCloneable {
|
|||||||
@Override
|
@Override
|
||||||
public void cloneFields(Cloner cloner, Object original) {
|
public void cloneFields(Cloner cloner, Object original) {
|
||||||
this.children = cloner.clone(children);
|
this.children = cloner.clone(children);
|
||||||
|
this.parent = cloner.clone(parent);
|
||||||
this.attachedNode = cloner.clone(attachedNode);
|
this.attachedNode = cloner.clone(attachedNode);
|
||||||
this.targetGeometry = cloner.clone(targetGeometry);
|
this.targetGeometry = cloner.clone(targetGeometry);
|
||||||
this.localTransform = cloner.clone(localTransform);
|
this.localTransform = cloner.clone(localTransform);
|
||||||
this.jointModelTransform = cloner.clone(jointModelTransform);
|
|
||||||
this.inverseModelBindMatrix = cloner.clone(inverseModelBindMatrix);
|
this.inverseModelBindMatrix = cloner.clone(inverseModelBindMatrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,7 +276,6 @@ public class Joint implements Savable, JmeCloneable {
|
|||||||
attachedNode = (Node) input.readSavable("attachedNode", null);
|
attachedNode = (Node) input.readSavable("attachedNode", null);
|
||||||
targetGeometry = (Geometry) input.readSavable("targetGeometry", null);
|
targetGeometry = (Geometry) input.readSavable("targetGeometry", null);
|
||||||
inverseModelBindMatrix = (Matrix4f) input.readSavable("inverseModelBindMatrix", inverseModelBindMatrix);
|
inverseModelBindMatrix = (Matrix4f) input.readSavable("inverseModelBindMatrix", inverseModelBindMatrix);
|
||||||
jointModelTransform = (JointModelTransform) input.readSavable("jointModelTransform", null);
|
|
||||||
|
|
||||||
ArrayList<Joint> childList = input.readSavableArrayList("children", null);
|
ArrayList<Joint> childList = input.readSavableArrayList("children", null);
|
||||||
for (int i = childList.size() - 1; i >= 0; i--) {
|
for (int i = childList.size() - 1; i >= 0; i--) {
|
||||||
@ -293,7 +292,6 @@ public class Joint implements Savable, JmeCloneable {
|
|||||||
output.write(targetGeometry, "targetGeometry", null);
|
output.write(targetGeometry, "targetGeometry", null);
|
||||||
output.write(inverseModelBindMatrix, "inverseModelBindMatrix", new Matrix4f());
|
output.write(inverseModelBindMatrix, "inverseModelBindMatrix", new Matrix4f());
|
||||||
output.writeSavableArrayList(children, "children", null);
|
output.writeSavableArrayList(children, "children", null);
|
||||||
output.write(jointModelTransform, "jointModelTransform", null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
package com.jme3.anim;
|
package com.jme3.anim;
|
||||||
|
|
||||||
import com.jme3.anim.util.JointModelTransform;
|
import com.jme3.anim.util.JointModelTransform;
|
||||||
import com.jme3.export.*;
|
|
||||||
import com.jme3.math.Matrix4f;
|
import com.jme3.math.Matrix4f;
|
||||||
import com.jme3.math.Transform;
|
import com.jme3.math.Transform;
|
||||||
import com.jme3.util.clone.Cloner;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This JointModelTransform implementation accumulate joints transforms in a Matrix4f to properly
|
* This JointModelTransform implementation accumulate joints transforms in a Matrix4f to properly
|
||||||
@ -47,32 +43,4 @@ public class MatrixJointModelTransform implements JointModelTransform {
|
|||||||
public Transform getModelTransform() {
|
public Transform getModelTransform() {
|
||||||
return modelTransform;
|
return modelTransform;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(JmeExporter ex) throws IOException {
|
|
||||||
OutputCapsule oc = ex.getCapsule(this);
|
|
||||||
oc.write(modelTransformMatrix, "modelTransformMatrix", new Matrix4f());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void read(JmeImporter im) throws IOException {
|
|
||||||
InputCapsule ic = im.getCapsule(this);
|
|
||||||
modelTransformMatrix = (Matrix4f) ic.readSavable("modelTransformMatrix", new Matrix4f());
|
|
||||||
modelTransform.fromTransformMatrix(modelTransformMatrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object jmeClone() {
|
|
||||||
try {
|
|
||||||
MatrixJointModelTransform clone = (MatrixJointModelTransform) super.clone();
|
|
||||||
return clone;
|
|
||||||
} catch (CloneNotSupportedException ex) {
|
|
||||||
throw new AssertionError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cloneFields(Cloner cloner, Object original) {
|
|
||||||
modelTransformMatrix = modelTransformMatrix.clone();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
package com.jme3.anim;
|
package com.jme3.anim;
|
||||||
|
|
||||||
import com.jme3.anim.util.JointModelTransform;
|
import com.jme3.anim.util.JointModelTransform;
|
||||||
import com.jme3.export.*;
|
|
||||||
import com.jme3.math.Matrix4f;
|
import com.jme3.math.Matrix4f;
|
||||||
import com.jme3.math.Transform;
|
import com.jme3.math.Transform;
|
||||||
import com.jme3.util.clone.Cloner;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This JointModelTransform implementation accumulates model transform in a Transform class
|
* This JointModelTransform implementation accumulates model transform in a Transform class
|
||||||
@ -33,8 +29,7 @@ public class SeparateJointModelTransform implements JointModelTransform {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyBindPose(Transform localTransform, Matrix4f inverseModelBindMatrix, Joint parent) {
|
public void applyBindPose(Transform localTransform, Matrix4f inverseModelBindMatrix, Joint parent) {
|
||||||
localTransform.fromTransformMatrix(inverseModelBindMatrix);
|
localTransform.fromTransformMatrix(inverseModelBindMatrix.invert());
|
||||||
localTransform.invert(); //model transform
|
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
localTransform.combineWithParent(parent.getModelTransform().invert());
|
localTransform.combineWithParent(parent.getModelTransform().invert());
|
||||||
}
|
}
|
||||||
@ -45,30 +40,4 @@ public class SeparateJointModelTransform implements JointModelTransform {
|
|||||||
return modelTransform;
|
return modelTransform;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(JmeExporter ex) throws IOException {
|
|
||||||
OutputCapsule oc = ex.getCapsule(this);
|
|
||||||
oc.write(modelTransform, "modelTransform", new Transform());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void read(JmeImporter im) throws IOException {
|
|
||||||
InputCapsule ic = im.getCapsule(this);
|
|
||||||
modelTransform = (Transform) ic.readSavable("modelTransform", new Transform());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object jmeClone() {
|
|
||||||
try {
|
|
||||||
SeparateJointModelTransform clone = (SeparateJointModelTransform) super.clone();
|
|
||||||
return clone;
|
|
||||||
} catch (CloneNotSupportedException ex) {
|
|
||||||
throw new AssertionError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cloneFields(Cloner cloner, Object original) {
|
|
||||||
modelTransform = modelTransform.clone();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -307,6 +307,7 @@ public abstract class TransformTrack implements Tween, JmeCloneable, Savable {
|
|||||||
rotations = (CompactQuaternionArray) ic.readSavable("rotations", null);
|
rotations = (CompactQuaternionArray) ic.readSavable("rotations", null);
|
||||||
times = ic.readFloatArray("times", null);
|
times = ic.readFloatArray("times", null);
|
||||||
scales = (CompactVector3Array) ic.readSavable("scales", null);
|
scales = (CompactVector3Array) ic.readSavable("scales", null);
|
||||||
|
setTimes(times);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -322,23 +323,33 @@ public abstract class TransformTrack implements Tween, JmeCloneable, Savable {
|
|||||||
public void cloneFields(Cloner cloner, Object original) {
|
public void cloneFields(Cloner cloner, Object original) {
|
||||||
int tablesLength = times.length;
|
int tablesLength = times.length;
|
||||||
|
|
||||||
times = this.times.clone();
|
setTimes(this.times.clone());
|
||||||
Vector3f[] sourceTranslations = this.getTranslations();
|
if (translations != null) {
|
||||||
Quaternion[] sourceRotations = this.getRotations();
|
Vector3f[] sourceTranslations = this.getTranslations();
|
||||||
Vector3f[] sourceScales = this.getScales();
|
Vector3f[] translations = new Vector3f[tablesLength];
|
||||||
|
for (int i = 0; i < tablesLength; ++i) {
|
||||||
Vector3f[] translations = new Vector3f[tablesLength];
|
translations[i] = sourceTranslations[i].clone();
|
||||||
Quaternion[] rotations = new Quaternion[tablesLength];
|
}
|
||||||
Vector3f[] scales = new Vector3f[tablesLength];
|
setKeyframesTranslation(translations);
|
||||||
for (int i = 0; i < tablesLength; ++i) {
|
}
|
||||||
translations[i] = sourceTranslations[i].clone();
|
if (rotations != null) {
|
||||||
rotations[i] = sourceRotations[i].clone();
|
Quaternion[] sourceRotations = this.getRotations();
|
||||||
scales[i] = sourceScales != null ? sourceScales[i].clone() : new Vector3f(1.0f, 1.0f, 1.0f);
|
Quaternion[] rotations = new Quaternion[tablesLength];
|
||||||
|
for (int i = 0; i < tablesLength; ++i) {
|
||||||
|
rotations[i] = sourceRotations[i].clone();
|
||||||
|
}
|
||||||
|
setKeyframesRotation(rotations);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scales != null) {
|
||||||
|
Vector3f[] sourceScales = this.getScales();
|
||||||
|
Vector3f[] scales = new Vector3f[tablesLength];
|
||||||
|
for (int i = 0; i < tablesLength; ++i) {
|
||||||
|
scales[i] = sourceScales[i].clone();
|
||||||
|
}
|
||||||
|
setKeyframesScale(scales);
|
||||||
}
|
}
|
||||||
|
|
||||||
setKeyframesTranslation(translations);
|
|
||||||
setKeyframesScale(scales);
|
|
||||||
setKeyframesRotation(rotations);
|
|
||||||
setFrameInterpolator(this.interpolator);
|
setFrameInterpolator(this.interpolator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
package com.jme3.anim.util;
|
package com.jme3.anim.util;
|
||||||
|
|
||||||
import com.jme3.anim.Joint;
|
import com.jme3.anim.Joint;
|
||||||
import com.jme3.export.Savable;
|
|
||||||
import com.jme3.math.Matrix4f;
|
import com.jme3.math.Matrix4f;
|
||||||
import com.jme3.math.Transform;
|
import com.jme3.math.Transform;
|
||||||
import com.jme3.util.clone.JmeCloneable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementations of this interface holds accumulated model transform of a Joint.
|
* Implementations of this interface holds accumulated model transform of a Joint.
|
||||||
* Implementation might choose different accumulation strategy.
|
* Implementation might choose different accumulation strategy.
|
||||||
*/
|
*/
|
||||||
public interface JointModelTransform extends JmeCloneable, Savable {
|
public interface JointModelTransform {
|
||||||
|
|
||||||
void updateModelTransform(Transform localTransform, Joint parent);
|
void updateModelTransform(Transform localTransform, Joint parent);
|
||||||
|
|
||||||
|
@ -41,9 +41,9 @@ public class TestAnimMigration extends SimpleApplication {
|
|||||||
rootNode.addLight(new DirectionalLight(new Vector3f(-1, -1, -1).normalizeLocal()));
|
rootNode.addLight(new DirectionalLight(new Vector3f(-1, -1, -1).normalizeLocal()));
|
||||||
rootNode.addLight(new AmbientLight(ColorRGBA.DarkGray));
|
rootNode.addLight(new AmbientLight(ColorRGBA.DarkGray));
|
||||||
|
|
||||||
Spatial model = assetManager.loadModel("Models/Jaime/Jaime.j3o");
|
//Spatial model = assetManager.loadModel("Models/Jaime/Jaime.j3o");
|
||||||
//Spatial model = assetManager.loadModel("Models/Oto/Oto.mesh.xml");
|
//Spatial model = assetManager.loadModel("Models/Oto/Oto.mesh.xml");
|
||||||
//Spatial model = assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml");
|
Spatial model = assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml");
|
||||||
//Spatial model = assetManager.loadModel("Models/Elephant/Elephant.mesh.xml");
|
//Spatial model = assetManager.loadModel("Models/Elephant/Elephant.mesh.xml");
|
||||||
|
|
||||||
AnimMigrationUtils.migrate(model);
|
AnimMigrationUtils.migrate(model);
|
||||||
@ -52,7 +52,7 @@ public class TestAnimMigration extends SimpleApplication {
|
|||||||
|
|
||||||
|
|
||||||
debugAppState = new ArmatureDebugAppState();
|
debugAppState = new ArmatureDebugAppState();
|
||||||
stateManager.attach(debugAppState);
|
//stateManager.attach(debugAppState);
|
||||||
|
|
||||||
setupModel(model);
|
setupModel(model);
|
||||||
|
|
||||||
|
@ -0,0 +1,168 @@
|
|||||||
|
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.asset.plugins.FileLocator;
|
||||||
|
import com.jme3.export.binary.BinaryExporter;
|
||||||
|
import com.jme3.input.KeyInput;
|
||||||
|
import com.jme3.input.controls.ActionListener;
|
||||||
|
import com.jme3.input.controls.KeyTrigger;
|
||||||
|
import com.jme3.light.AmbientLight;
|
||||||
|
import com.jme3.light.DirectionalLight;
|
||||||
|
import com.jme3.math.*;
|
||||||
|
import com.jme3.scene.Node;
|
||||||
|
import com.jme3.scene.Spatial;
|
||||||
|
import com.jme3.scene.debug.custom.ArmatureDebugAppState;
|
||||||
|
import com.jme3.system.JmeSystem;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Queue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Nehon on 18/12/2017.
|
||||||
|
*/
|
||||||
|
public class TestAnimSerialization extends SimpleApplication {
|
||||||
|
|
||||||
|
ArmatureDebugAppState debugAppState;
|
||||||
|
AnimComposer composer;
|
||||||
|
Queue<String> anims = new LinkedList<>();
|
||||||
|
boolean playAnim = true;
|
||||||
|
File file;
|
||||||
|
|
||||||
|
public static void main(String... argv) {
|
||||||
|
TestAnimSerialization app = new TestAnimSerialization();
|
||||||
|
app.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void simpleInitApp() {
|
||||||
|
setTimer(new EraseTimer());
|
||||||
|
//cam.setFrustumPerspective(90f, (float) cam.getWidth() / cam.getHeight(), 0.01f, 10f);
|
||||||
|
viewPort.setBackgroundColor(ColorRGBA.DarkGray);
|
||||||
|
rootNode.addLight(new DirectionalLight(new Vector3f(-1, -1, -1).normalizeLocal()));
|
||||||
|
rootNode.addLight(new AmbientLight(ColorRGBA.DarkGray));
|
||||||
|
|
||||||
|
Spatial model = assetManager.loadModel("Models/Jaime/Jaime.j3o");
|
||||||
|
|
||||||
|
AnimMigrationUtils.migrate(model);
|
||||||
|
|
||||||
|
File storageFolder = JmeSystem.getStorageFolder();
|
||||||
|
file = new File(storageFolder.getPath() + File.separator + "newJaime.j3o");
|
||||||
|
BinaryExporter be = new BinaryExporter();
|
||||||
|
try {
|
||||||
|
be.save(model, file);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
assetManager.registerLocator(storageFolder.getPath(), FileLocator.class);
|
||||||
|
model = assetManager.loadModel("newJaime.j3o");
|
||||||
|
|
||||||
|
rootNode.attachChild(model);
|
||||||
|
|
||||||
|
debugAppState = new ArmatureDebugAppState();
|
||||||
|
stateManager.attach(debugAppState);
|
||||||
|
|
||||||
|
setupModel(model);
|
||||||
|
|
||||||
|
flyCam.setEnabled(false);
|
||||||
|
|
||||||
|
Node target = new Node("CamTarget");
|
||||||
|
//target.setLocalTransform(model.getLocalTransform());
|
||||||
|
target.move(0, 1, 0);
|
||||||
|
ChaseCameraAppState chaseCam = new ChaseCameraAppState();
|
||||||
|
chaseCam.setTarget(target);
|
||||||
|
getStateManager().attach(chaseCam);
|
||||||
|
chaseCam.setInvertHorizontalAxis(true);
|
||||||
|
chaseCam.setInvertVerticalAxis(true);
|
||||||
|
chaseCam.setZoomSpeed(0.5f);
|
||||||
|
chaseCam.setMinVerticalRotation(-FastMath.HALF_PI);
|
||||||
|
chaseCam.setRotationSpeed(3);
|
||||||
|
chaseCam.setDefaultDistance(3);
|
||||||
|
chaseCam.setMinDistance(0.01f);
|
||||||
|
chaseCam.setZoomSpeed(0.01f);
|
||||||
|
chaseCam.setDefaultVerticalRotation(0.3f);
|
||||||
|
|
||||||
|
initInputs();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initInputs() {
|
||||||
|
inputManager.addMapping("toggleAnim", new KeyTrigger(KeyInput.KEY_RETURN));
|
||||||
|
|
||||||
|
inputManager.addListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void onAction(String name, boolean isPressed, float tpf) {
|
||||||
|
if (isPressed) {
|
||||||
|
playAnim = !playAnim;
|
||||||
|
if (playAnim) {
|
||||||
|
String anim = anims.poll();
|
||||||
|
anims.add(anim);
|
||||||
|
composer.setCurrentAnimClip(anim);
|
||||||
|
System.err.println(anim);
|
||||||
|
} else {
|
||||||
|
composer.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, "toggleAnim");
|
||||||
|
inputManager.addMapping("nextAnim", new KeyTrigger(KeyInput.KEY_RIGHT));
|
||||||
|
inputManager.addListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void onAction(String name, boolean isPressed, float tpf) {
|
||||||
|
if (isPressed && composer != null) {
|
||||||
|
String anim = anims.poll();
|
||||||
|
anims.add(anim);
|
||||||
|
composer.setCurrentAnimClip(anim);
|
||||||
|
System.err.println(anim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, "nextAnim");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupModel(Spatial model) {
|
||||||
|
if (composer != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
composer = model.getControl(AnimComposer.class);
|
||||||
|
if (composer != null) {
|
||||||
|
|
||||||
|
SkinningControl sc = model.getControl(SkinningControl.class);
|
||||||
|
|
||||||
|
debugAppState.addArmatureFrom(sc);
|
||||||
|
anims.clear();
|
||||||
|
for (String name : composer.getAnimClipsNames()) {
|
||||||
|
anims.add(name);
|
||||||
|
}
|
||||||
|
if (anims.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (playAnim) {
|
||||||
|
String anim = anims.poll();
|
||||||
|
anims.add(anim);
|
||||||
|
composer.setCurrentAnimClip(anim);
|
||||||
|
System.err.println(anim);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (model instanceof Node) {
|
||||||
|
Node n = (Node) model;
|
||||||
|
for (Spatial child : n.getChildren()) {
|
||||||
|
setupModel(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
super.destroy();
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
}
|
@ -51,7 +51,7 @@ public class TestArmature extends SimpleApplication {
|
|||||||
Joint[] joints = new Joint[]{root, j1, j2, j3};
|
Joint[] joints = new Joint[]{root, j1, j2, j3};
|
||||||
|
|
||||||
final Armature armature = new Armature(joints);
|
final Armature armature = new Armature(joints);
|
||||||
// armature.setModelTransformClass(SeparateJointModelTransform.class);
|
//armature.setModelTransformClass(SeparateJointModelTransform.class);
|
||||||
armature.setBindPose();
|
armature.setBindPose();
|
||||||
|
|
||||||
//create animations
|
//create animations
|
||||||
|
@ -0,0 +1,217 @@
|
|||||||
|
package jme3test.model.anim;
|
||||||
|
|
||||||
|
import com.jme3.anim.*;
|
||||||
|
import com.jme3.app.ChaseCameraAppState;
|
||||||
|
import com.jme3.app.SimpleApplication;
|
||||||
|
import com.jme3.asset.plugins.FileLocator;
|
||||||
|
import com.jme3.export.binary.BinaryExporter;
|
||||||
|
import com.jme3.input.KeyInput;
|
||||||
|
import com.jme3.input.controls.ActionListener;
|
||||||
|
import com.jme3.input.controls.KeyTrigger;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.math.*;
|
||||||
|
import com.jme3.scene.*;
|
||||||
|
import com.jme3.scene.debug.custom.ArmatureDebugAppState;
|
||||||
|
import com.jme3.scene.shape.Cylinder;
|
||||||
|
import com.jme3.system.JmeSystem;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.nio.ShortBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Nehon on 18/12/2017.
|
||||||
|
*/
|
||||||
|
public class TestBaseAnimSerialization extends SimpleApplication {
|
||||||
|
|
||||||
|
Joint j1;
|
||||||
|
Joint j2;
|
||||||
|
AnimComposer composer;
|
||||||
|
Armature armature;
|
||||||
|
File file;
|
||||||
|
|
||||||
|
public static void main(String... argv) {
|
||||||
|
TestBaseAnimSerialization app = new TestBaseAnimSerialization();
|
||||||
|
app.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void simpleInitApp() {
|
||||||
|
setTimer(new EraseTimer());
|
||||||
|
renderManager.setSinglePassLightBatchSize(2);
|
||||||
|
//cam.setFrustumPerspective(90f, (float) cam.getWidth() / cam.getHeight(), 0.01f, 10f);
|
||||||
|
viewPort.setBackgroundColor(ColorRGBA.DarkGray);
|
||||||
|
|
||||||
|
//create armature
|
||||||
|
Joint root = new Joint("Root_Joint");
|
||||||
|
j1 = new Joint("Joint_1");
|
||||||
|
j2 = new Joint("Joint_2");
|
||||||
|
Joint j3 = new Joint("Joint_3");
|
||||||
|
root.addChild(j1);
|
||||||
|
j1.addChild(j2);
|
||||||
|
j2.addChild(j3);
|
||||||
|
root.setLocalTranslation(new Vector3f(0, 0, 0.5f));
|
||||||
|
j1.setLocalTranslation(new Vector3f(0, 0.0f, -0.5f));
|
||||||
|
j2.setLocalTranslation(new Vector3f(0, 0.0f, -0.3f));
|
||||||
|
j3.setLocalTranslation(new Vector3f(0, 0, -0.2f));
|
||||||
|
Joint[] joints = new Joint[]{root, j1, j2, j3};
|
||||||
|
|
||||||
|
armature = new Armature(joints);
|
||||||
|
//armature.setModelTransformClass(SeparateJointModelTransform.class);
|
||||||
|
armature.setBindPose();
|
||||||
|
|
||||||
|
//create animations
|
||||||
|
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(1, 1, 2),
|
||||||
|
new Vector3f(1, 1, 1),
|
||||||
|
};
|
||||||
|
Vector3f[] scales2 = new Vector3f[]{
|
||||||
|
new Vector3f(1, 1, 1),
|
||||||
|
new Vector3f(1, 1, 0.5f),
|
||||||
|
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);
|
||||||
|
|
||||||
|
//create the animComposer control
|
||||||
|
composer = new AnimComposer();
|
||||||
|
composer.addAnimClip(clip);
|
||||||
|
|
||||||
|
//create the SkinningControl
|
||||||
|
SkinningControl ac = new SkinningControl(armature);
|
||||||
|
Node node = new Node("Test Armature");
|
||||||
|
|
||||||
|
//Create the mesh to deform.
|
||||||
|
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);
|
||||||
|
|
||||||
|
File storageFolder = JmeSystem.getStorageFolder();
|
||||||
|
file = new File(storageFolder.getPath() + File.separator + "test.j3o");
|
||||||
|
BinaryExporter be = new BinaryExporter();
|
||||||
|
try {
|
||||||
|
be.save(node, file);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
assetManager.registerLocator(storageFolder.getPath(), FileLocator.class);
|
||||||
|
Node newNode = (Node) assetManager.loadModel("test.j3o");
|
||||||
|
|
||||||
|
rootNode.attachChild(newNode);
|
||||||
|
|
||||||
|
composer = newNode.getControl(AnimComposer.class);
|
||||||
|
ac = newNode.getControl(SkinningControl.class);
|
||||||
|
ac.setHardwareSkinningPreferred(false);
|
||||||
|
armature = ac.getArmature();
|
||||||
|
composer.setCurrentAnimClip("anim");
|
||||||
|
|
||||||
|
ArmatureDebugAppState debugAppState = new ArmatureDebugAppState();
|
||||||
|
debugAppState.addArmatureFrom(ac);
|
||||||
|
stateManager.attach(debugAppState);
|
||||||
|
|
||||||
|
flyCam.setEnabled(false);
|
||||||
|
|
||||||
|
ChaseCameraAppState chaseCam = new ChaseCameraAppState();
|
||||||
|
chaseCam.setTarget(node);
|
||||||
|
getStateManager().attach(chaseCam);
|
||||||
|
chaseCam.setInvertHorizontalAxis(true);
|
||||||
|
chaseCam.setInvertVerticalAxis(true);
|
||||||
|
chaseCam.setZoomSpeed(0.5f);
|
||||||
|
chaseCam.setMinVerticalRotation(-FastMath.HALF_PI);
|
||||||
|
chaseCam.setRotationSpeed(3);
|
||||||
|
chaseCam.setDefaultDistance(3);
|
||||||
|
chaseCam.setMinDistance(0.01f);
|
||||||
|
chaseCam.setZoomSpeed(0.01f);
|
||||||
|
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) {
|
||||||
|
composer.reset();
|
||||||
|
armature.resetToBindPose();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
composer.setCurrentAnimClip("anim");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, "bind");
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
VertexBuffer weightsHW = new VertexBuffer(VertexBuffer.Type.HWBoneWeight);
|
||||||
|
VertexBuffer indicesHW = new VertexBuffer(VertexBuffer.Type.HWBoneIndex);
|
||||||
|
|
||||||
|
indicesHW.setUsage(VertexBuffer.Usage.CpuOnly);
|
||||||
|
weightsHW.setUsage(VertexBuffer.Usage.CpuOnly);
|
||||||
|
c.setBuffer(weightsHW);
|
||||||
|
c.setBuffer(indicesHW);
|
||||||
|
c.generateBindPose();
|
||||||
|
|
||||||
|
c.prepareForAnim(false);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
super.destroy();
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user