فهرست منبع

Proper serialisation for morph animation

Nehon 7 سال پیش
والد
کامیت
bcd97c22eb
20فایلهای تغییر یافته به همراه244 افزوده شده و 85 حذف شده
  1. 2 2
      jme3-core/src/main/java/com/jme3/anim/AnimClip.java
  2. 29 8
      jme3-core/src/main/java/com/jme3/anim/Armature.java
  3. 37 3
      jme3-core/src/main/java/com/jme3/anim/Joint.java
  4. 78 29
      jme3-core/src/main/java/com/jme3/anim/MorphControl.java
  5. 2 0
      jme3-core/src/main/java/com/jme3/anim/MorphTrack.java
  6. 1 1
      jme3-core/src/main/java/com/jme3/anim/TransformTrack.java
  7. 1 1
      jme3-core/src/main/java/com/jme3/anim/util/AnimMigrationUtils.java
  8. 0 4
      jme3-core/src/main/java/com/jme3/animation/BoneTrack.java
  9. 7 0
      jme3-core/src/main/java/com/jme3/material/MatParamOverride.java
  10. 5 3
      jme3-core/src/main/java/com/jme3/material/Material.java
  11. 1 1
      jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
  12. 43 1
      jme3-core/src/main/java/com/jme3/scene/Geometry.java
  13. 3 1
      jme3-core/src/main/java/com/jme3/scene/Mesh.java
  14. 5 4
      jme3-core/src/main/java/com/jme3/scene/VertexBuffer.java
  15. 5 5
      jme3-examples/src/main/java/jme3test/model/TestGltfLoading.java
  16. 19 17
      jme3-examples/src/main/java/jme3test/model/anim/TestAnimMorphSerialization.java
  17. 2 2
      jme3-examples/src/main/java/jme3test/model/anim/TestArmature.java
  18. 2 2
      jme3-examples/src/main/java/jme3test/model/anim/TestBaseAnimSerialization.java
  19. 1 0
      jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfLoader.java
  20. 1 1
      jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/SkeletonLoader.java

+ 2 - 2
jme3-core/src/main/java/com/jme3/anim/AnimClip.java

@@ -80,9 +80,9 @@ public class AnimClip implements JmeCloneable, Savable {
         name = ic.readString("name", null);
         Savable[] arr = ic.readSavableArray("tracks", null);
         if (arr != null) {
-            tracks = new TransformTrack[arr.length];
+            tracks = new AnimTrack[arr.length];
             for (int i = 0; i < arr.length; i++) {
-                TransformTrack t = (TransformTrack) arr[i];
+                AnimTrack t = (AnimTrack) arr[i];
                 tracks[i] = t;
                 if (t.getLength() > length) {
                     length = t.getLength();

+ 29 - 8
jme3-core/src/main/java/com/jme3/anim/Armature.java

@@ -174,28 +174,49 @@ public class Armature implements JmeCloneable, Savable {
 
     /**
      * Saves the current Armature state as its bind pose.
+     * Note that the bind pose is supposed to be the one where the armature is aligned with the mesh to deform.
+     * Saving this pose will affect how skinning works.
      */
-    public void setBindPose() {
+    public void saveBindPose() {
         //make sure all bones are updated
         update();
         //Save the current pose as bind pose
         for (Joint joint : jointList) {
-            joint.setBindPose();
+            joint.saveBindPose();
         }
     }
 
     /**
-     * This methods sets this armature in its bind pose (aligned with the undeformed mesh)
-     * Note that this is only useful for debugging porpose.
+     * This methods sets this armature in its bind pose (aligned with the mesh to deform)
+     * Note that this is only useful for debugging purpose.
      */
-    public void resetToBindPose() {
+    public void applyBindPose() {
         for (Joint joint : rootJoints) {
-            joint.resetToBindPose();
+            joint.applyBindPose();
         }
     }
 
     /**
-     * Compute the skining matrices for each bone of the armature that would be used to transform vertices of associated meshes
+     * Saves the current local transform as the initial transform.
+     * Initial transform is the one applied to the armature when loaded.
+     */
+    public void saveInitialPose() {
+        for (Joint joint : jointList) {
+            joint.saveInitialPose();
+        }
+    }
+
+    /**
+     * Applies the initial pose to this armature
+     */
+    public void applyInitialPose() {
+        for (Joint rootJoint : rootJoints) {
+            rootJoint.applyInitialPose();
+        }
+    }
+
+    /**
+     * Compute the skinning matrices for each bone of the armature that would be used to transform vertices of associated meshes
      *
      * @return
      */
@@ -263,7 +284,7 @@ public class Armature implements JmeCloneable, Savable {
         for (Joint rootJoint : rootJoints) {
             rootJoint.update();
         }
-        resetToBindPose();
+        applyInitialPose();
     }
 
     @Override

+ 37 - 3
jme3-core/src/main/java/com/jme3/anim/Joint.java

@@ -37,6 +37,13 @@ public class Joint implements Savable, JmeCloneable, HasLocalTransform {
      */
     private Transform localTransform = new Transform();
 
+    /**
+     * The initial transform of the joint in local space. Relative to its parent.
+     * Or relative to the model's origin for the root joint.
+     * this transform is the transform applied when the armature is loaded.
+     */
+    private Transform initialTransform = new Transform();
+
     /**
      * The transform of the joint in model space. Relative to the origin of the model.
      * this is either a MatrixJointModelTransform or a SeparateJointModelTransform
@@ -127,18 +134,43 @@ public class Joint implements Savable, JmeCloneable, HasLocalTransform {
         jointModelTransform.getOffsetTransform(outTransform, inverseModelBindMatrix);
     }
 
-    protected void setBindPose() {
+    /**
+     * Sets the current localTransform as the Bind transform.
+     */
+    protected void saveBindPose() {
         //Note that the whole Armature must be updated before calling this method.
         getModelTransform().toTransformMatrix(inverseModelBindMatrix);
         inverseModelBindMatrix.invertLocal();
     }
 
-    protected void resetToBindPose() {
+    /**
+     * Sets the current local transforms as the initial transform.
+     */
+    protected void saveInitialPose() {
+        initialTransform.set(localTransform);
+    }
+
+    /**
+     * Sets the local transform with the bind transforms
+     */
+    protected void applyBindPose() {
         jointModelTransform.applyBindPose(localTransform, inverseModelBindMatrix, parent);
         updateModelTransforms();
 
         for (Joint child : children.getArray()) {
-            child.resetToBindPose();
+            child.applyBindPose();
+        }
+    }
+
+    /**
+     * Sets the local transform with the initial transform
+     */
+    protected void applyInitialPose() {
+        setLocalTransform(initialTransform);
+        updateModelTransforms();
+
+        for (Joint child : children.getArray()) {
+            child.applyInitialPose();
         }
     }
 
@@ -277,6 +309,7 @@ public class Joint implements Savable, JmeCloneable, HasLocalTransform {
         name = input.readString("name", null);
         attachedNode = (Node) input.readSavable("attachedNode", null);
         targetGeometry = (Geometry) input.readSavable("targetGeometry", null);
+        initialTransform = (Transform) input.readSavable("initialTransform", new Transform());
         inverseModelBindMatrix = (Matrix4f) input.readSavable("inverseModelBindMatrix", inverseModelBindMatrix);
 
         ArrayList<Joint> childList = input.readSavableArrayList("children", null);
@@ -292,6 +325,7 @@ public class Joint implements Savable, JmeCloneable, HasLocalTransform {
         output.write(name, "name", null);
         output.write(attachedNode, "attachedNode", null);
         output.write(targetGeometry, "targetGeometry", null);
+        output.write(initialTransform, "initialTransform", new Transform());
         output.write(inverseModelBindMatrix, "inverseModelBindMatrix", new Matrix4f());
         output.writeSavableArrayList(new ArrayList(children), "children", null);
     }

+ 78 - 29
jme3-core/src/main/java/com/jme3/anim/MorphControl.java

@@ -1,11 +1,9 @@
 package com.jme3.anim;
 
+import com.jme3.export.*;
 import com.jme3.material.*;
 import com.jme3.renderer.*;
-import com.jme3.scene.Geometry;
-import com.jme3.scene.Mesh;
-import com.jme3.scene.SceneGraphVisitorAdapter;
-import com.jme3.scene.VertexBuffer;
+import com.jme3.scene.*;
 import com.jme3.scene.control.AbstractControl;
 import com.jme3.scene.mesh.MorphTarget;
 import com.jme3.shader.VarType;
@@ -13,7 +11,10 @@ import com.jme3.util.BufferUtils;
 import com.jme3.util.SafeArrayList;
 import javafx.geometry.Pos;
 
+import java.io.IOException;
 import java.nio.FloatBuffer;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 /**
  * A control that handle morph animation for Position, Normal and Tangent buffers.
@@ -22,7 +23,9 @@ import java.nio.FloatBuffer;
  *
  * @author Rémy Bouquet
  */
-public class MorphControl extends AbstractControl {
+public class MorphControl extends AbstractControl implements Savable {
+
+    private static final Logger logger = Logger.getLogger(MorphControl.class.getName());
 
     private static final int MAX_MORPH_BUFFERS = 14;
     private final static float MIN_WEIGHT = 0.005f;
@@ -55,33 +58,23 @@ public class MorphControl extends AbstractControl {
         if (!enabled) {
             return;
         }
-        for (Geometry target : targets) {
-            Mesh mesh = target.getMesh();
-            if (!target.isDirtyMorph()) {
+        for (Geometry geom : targets) {
+            Mesh mesh = geom.getMesh();
+            if (!geom.isDirtyMorph()) {
                 continue;
             }
-            int nbMaxBuffers = getRemainingBuffers(mesh, rm.getRenderer());
-            Material m = target.getMaterial();
 
-            float weights[] = target.getMorphState();
+            Material m = geom.getMaterial();
+            float weights[] = geom.getMorphState();
             MorphTarget morphTargets[] = mesh.getMorphTargets();
             float matWeights[];
-            MatParam param = m.getParam("MorphWeights");
-
             //Number of buffer to handle for each morph target
             int targetNumBuffers = getTargetNumBuffers(morphTargets[0]);
-            // compute the max number of targets to send to the GPU
-            int maxGPUTargets = Math.min(nbMaxBuffers, MAX_MORPH_BUFFERS) / targetNumBuffers;
-            if (param == null) {
-                matWeights = new float[maxGPUTargets];
-                m.setParam("MorphWeights", VarType.FloatArray, matWeights);
-            } else {
-                matWeights = (float[]) param.getValue();
-            }
 
-            // setting the maximum number as the real number may change every frame and trigger a shader recompilation since it's bound to a define.
-            m.setInt("NumberOfMorphTargets", maxGPUTargets);
-            m.setInt("NumberOfTargetsBuffers", targetNumBuffers);
+            int maxGPUTargets = getMaxGPUTargets(rm, geom, m, targetNumBuffers);
+
+            MatParam param2 = m.getParam("MorphWeights");
+            matWeights = (float[]) param2.getValue();
 
             int nbGPUTargets = 0;
             int lastGpuTargetIndex = 0;
@@ -115,14 +108,14 @@ public class MorphControl extends AbstractControl {
             } else if (cpuWeightSum > 0) {
                 // we have more simultaneous morph targets than available gpu slots,
                 // we merge the additional morph targets and bind them to the last gpu slot
-                MorphTarget mt = target.getFallbackMorphTarget();
+                MorphTarget mt = geom.getFallbackMorphTarget();
                 if (mt == null) {
-                    mt = initCpuMorphTarget(target);
-                    target.setFallbackMorphTarget(mt);
+                    mt = initCpuMorphTarget(geom);
+                    geom.setFallbackMorphTarget(mt);
                 }
                 // adding the last Gpu target weight
                 cpuWeightSum += matWeights[nbGPUTargets - 1];
-                ensureTmpArraysCapacity(target.getVertexCount() * 3, targetNumBuffers);
+                ensureTmpArraysCapacity(geom.getVertexCount() * 3, targetNumBuffers);
 
                 // merging all remaining targets in tmp arrays
                 for (int i = lastGpuTargetIndex; i < morphTargets.length; i++) {
@@ -130,7 +123,7 @@ public class MorphControl extends AbstractControl {
                         continue;
                     }
                     float weight = weights[i] / cpuWeightSum;
-                    MorphTarget t = target.getMesh().getMorphTargets()[i];
+                    MorphTarget t = geom.getMesh().getMorphTargets()[i];
                     mergeMorphTargets(targetNumBuffers, weight, t, i == lastGpuTargetIndex);
                 }
 
@@ -143,7 +136,52 @@ public class MorphControl extends AbstractControl {
                 // setting the eight of the merged targets
                 matWeights[nbGPUTargets - 1] = cpuWeightSum;
             }
+            geom.setDirtyMorph(false);
+        }
+    }
+
+    private int getMaxGPUTargets(RenderManager rm, Geometry geom, Material mat, int targetNumBuffers) {
+        if (geom.getNbSimultaneousGPUMorph() > -1) {
+            return geom.getNbSimultaneousGPUMorph();
+        }
+
+        // Evaluate the number of CPU slots remaining for morph buffers.
+        int nbMaxBuffers = getRemainingBuffers(geom.getMesh(), rm.getRenderer());
+
+        int realNumTargetsBuffers = geom.getMesh().getMorphTargets().length * targetNumBuffers;
+
+        // compute the max number of targets to send to the GPU
+        int maxGPUTargets = Math.min(realNumTargetsBuffers, Math.min(nbMaxBuffers, MAX_MORPH_BUFFERS)) / targetNumBuffers;
+
+        MatParam param = mat.getParam("MorphWeights");
+        if (param == null) {
+            // init the mat param if it doesn't exists.
+            float[] wts = new float[maxGPUTargets];
+            mat.setParam("MorphWeights", VarType.FloatArray, wts);
+        }
+
+        mat.setInt("NumberOfTargetsBuffers", targetNumBuffers);
+
+        // test compile the shader to find the accurate number of remaining attributes slots
+        boolean compilationOk = false;
+        // Note that if ever the shader has an unrelated issue we want to break at some point, hence the maxGPUTargets > 0
+        while (!compilationOk && maxGPUTargets > 0) {
+            // setting the maximum number as the real number may change every frame and trigger a shader recompilation since it's bound to a define.
+            mat.setInt("NumberOfMorphTargets", maxGPUTargets);
+            try {
+                // preload the spatial. this will trigger a shader compilation that will fail if the number of attributes is over the limit.
+                rm.preloadScene(spatial);
+                compilationOk = true;
+            } catch (RendererException e) {
+                logger.log(Level.FINE, geom.getName() + ": failed at " + maxGPUTargets);
+                // the compilation failed let's decrement the number of targets an try again.
+                maxGPUTargets--;
+            }
         }
+        logger.log(Level.FINE, geom.getName() + ": " + maxGPUTargets);
+        // set the number of GPU morph on the geom to not have to recompute it next frame.
+        geom.setNbSimultaneousGPUMorph(maxGPUTargets);
+        return maxGPUTargets;
     }
 
     private int bindMorphtargetBuffer(Mesh mesh, int targetNumBuffers, int boundBufferIdx, MorphTarget t) {
@@ -263,6 +301,17 @@ public class MorphControl extends AbstractControl {
         return num;
     }
 
+    /**
+     * Computes the number of remaining buffers on this mesh.
+     * This is supposed to give a hint on how many attributes will be used in the material and computes the remaining available slots for the morph attributes.
+     * However, the shader can declare attributes that are not used and not bound to a real buffer.
+     * That's why we attempt to compile the shader later on to avoid any compilation crash.
+     * This method is here to avoid too much render test iteration.
+     *
+     * @param mesh
+     * @param renderer
+     * @return
+     */
     private int getRemainingBuffers(Mesh mesh, Renderer renderer) {
         int nbUsedBuffers = 0;
         for (VertexBuffer vb : mesh.getBufferList().getArray()) {

+ 2 - 0
jme3-core/src/main/java/com/jme3/anim/MorphTrack.java

@@ -187,6 +187,7 @@ public class MorphTrack implements AnimTrack<float[]> {
         oc.write(weights, "weights", null);
         oc.write(times, "times", null);
         oc.write(target, "target", null);
+        oc.write(nbMorphTargets, "nbMorphTargets", 0);
     }
 
     @Override
@@ -195,6 +196,7 @@ public class MorphTrack implements AnimTrack<float[]> {
         weights = ic.readFloatArray("weights", null);
         times = ic.readFloatArray("times", null);
         target = (Geometry) ic.readSavable("target", null);
+        nbMorphTargets = ic.readInt("nbMorphTargets", 0);
         setTimes(times);
     }
 

+ 1 - 1
jme3-core/src/main/java/com/jme3/anim/TransformTrack.java

@@ -294,7 +294,7 @@ public class TransformTrack implements AnimTrack<Transform> {
         rotations = (CompactQuaternionArray) ic.readSavable("rotations", null);
         times = ic.readFloatArray("times", null);
         scales = (CompactVector3Array) ic.readSavable("scales", null);
-        target = (Joint) ic.readSavable("target", null);
+        target = (HasLocalTransform) ic.readSavable("target", null);
         setTimes(times);
     }
 

+ 1 - 1
jme3-core/src/main/java/com/jme3/anim/util/AnimMigrationUtils.java

@@ -58,7 +58,7 @@ public class AnimMigrationUtils {
                 }
 
                 Armature armature = new Armature(joints);
-                armature.setBindPose();
+                armature.saveBindPose();
                 skeletonArmatureMap.put(skeleton, armature);
 
                 List<TransformTrack> tracks = new ArrayList<>();

+ 0 - 4
jme3-core/src/main/java/com/jme3/animation/BoneTrack.java

@@ -35,12 +35,8 @@ import com.jme3.export.*;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Vector3f;
 import com.jme3.util.TempVars;
-<<<<<<< HEAD
 import com.jme3.util.clone.Cloner;
 import com.jme3.util.clone.JmeCloneable;
-=======
-
->>>>>>> Draft of the new animation system
 import java.io.IOException;
 import java.util.BitSet;
 

+ 7 - 0
jme3-core/src/main/java/com/jme3/material/MatParamOverride.java

@@ -140,6 +140,9 @@ public final class MatParamOverride extends MatParam {
         super.write(ex);
         OutputCapsule oc = ex.getCapsule(this);
         oc.write(enabled, "enabled", true);
+        if (value == null) {
+            oc.write(true, "isNull", false);
+        }
     }
 
     @Override
@@ -147,5 +150,9 @@ public final class MatParamOverride extends MatParam {
         super.read(im);
         InputCapsule ic = im.getCapsule(this);
         enabled = ic.readBoolean("enabled", true);
+        boolean isNull = ic.readBoolean("isNull", false);
+        if (isNull) {
+            setValue(null);
+        }
     }
 }

+ 5 - 3
jme3-core/src/main/java/com/jme3/material/Material.java

@@ -836,7 +836,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
      *
      * @param renderManager The render manager to preload for
      */
-    public void preload(RenderManager renderManager) {
+    public void preload(RenderManager renderManager, Geometry geometry) {
         if (technique == null) {
             selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager);
         }
@@ -847,9 +847,11 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
         if (techniqueDef.isNoRender()) {
             return;
         }
+        // Get world overrides
+        SafeArrayList<MatParamOverride> overrides = geometry.getWorldMatParamOverrides();
 
-        Shader shader = technique.makeCurrent(renderManager, null, null, null, rendererCaps);
-        updateShaderMaterialParameters(renderer, shader, null, null);
+        Shader shader = technique.makeCurrent(renderManager, overrides, null, null, rendererCaps);
+        updateShaderMaterialParameters(renderer, shader, overrides, null);
         renderManager.getRenderer().setShader(shader);
     }
 

+ 1 - 1
jme3-core/src/main/java/com/jme3/renderer/RenderManager.java

@@ -660,7 +660,7 @@ public class RenderManager {
                 throw new IllegalStateException("No material is set for Geometry: " + gm.getName());
             }
 
-            gm.getMaterial().preload(this);
+            gm.getMaterial().preload(this, gm);
             Mesh mesh = gm.getMesh();
             if (mesh != null
                     && mesh.getVertexCount() != 0

+ 43 - 1
jme3-core/src/main/java/com/jme3/scene/Geometry.java

@@ -95,6 +95,7 @@ public class Geometry extends Spatial {
     // a Morph target that will be used to merge all targets that
     // can't be handled on the cpu on each frame.
     private MorphTarget fallbackMorphTarget;
+    private int nbSimultaneousGPUMorph = -1;
 
     /**
      * Serialization only. Do not use.
@@ -258,7 +259,7 @@ public class Geometry extends Spatial {
     @Override
     public void setMaterial(Material material) {
         this.material = material;
-
+        nbSimultaneousGPUMorph = -1;
         if (isGrouped()) {
             groupNode.onMaterialChange(this);
         }
@@ -600,10 +601,28 @@ public class Geometry extends Spatial {
         this.dirtyMorph = true;
     }
 
+    /**
+     * returns true if the morph state has changed on the last frame.
+     * @return
+     */
     public boolean isDirtyMorph() {
         return dirtyMorph;
     }
 
+    /**
+     * Seting this to true will stop this geometry morph buffer to be updated,
+     * unless the morph state changes
+     * @param dirtyMorph
+     */
+    public void setDirtyMorph(boolean dirtyMorph) {
+        this.dirtyMorph = dirtyMorph;
+    }
+
+    /**
+     * returns the morph state of this Geometry.
+     * Used internally by the MorphControl.
+     * @return
+     */
     public float[] getMorphState() {
         if (morphState == null) {
             morphState = new float[mesh.getMorphTargets().length];
@@ -611,6 +630,29 @@ public class Geometry extends Spatial {
         return morphState;
     }
 
+    /**
+     * Return the number of morph targets that can be handled on the GPU simultaneously for this geometry.
+     * Note that it depends on the material set on this geometry.
+     * This number is computed and set by the MorphControl, so it might be available only after the first frame.
+     * Else it's set to -1.
+     * @return the number of simultaneous morph targets handled on the GPU
+     */
+    public int getNbSimultaneousGPUMorph() {
+        return nbSimultaneousGPUMorph;
+    }
+
+    /**
+     * Sets the number of morph targets that can be handled on the GPU simultaneously for this geometry.
+     * Note that it depends on the material set on this geometry.
+     * This number is computed and set by the MorphControl, so it might be available only after the first frame.
+     * Else it's set to -1.
+     * WARNING: setting this manually might crash the shader compilation if set too high. Do it at your own risk.
+     * @param nbSimultaneousGPUMorph the number of simultaneous morph targets to be handled on the GPU.
+     */
+    public void setNbSimultaneousGPUMorph(int nbSimultaneousGPUMorph) {
+        this.nbSimultaneousGPUMorph = nbSimultaneousGPUMorph;
+    }
+
     public MorphTarget getFallbackMorphTarget() {
         return fallbackMorphTarget;
     }

+ 3 - 1
jme3-core/src/main/java/com/jme3/scene/Mesh.java

@@ -1573,7 +1573,9 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
         }
 
         out.write(lodLevels, "lodLevels", null);
-        out.writeSavableArrayList(new ArrayList(morphTargets), "morphTargets", null);
+        if (morphTargets != null) {
+            out.writeSavableArrayList(new ArrayList(morphTargets), "morphTargets", null);
+        }
     }
 
     @Override

+ 5 - 4
jme3-core/src/main/java/com/jme3/scene/VertexBuffer.java

@@ -216,15 +216,16 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
 
         /**
          * Morph animations targets.
-         * Supports up tp 8 morph target buffers at the same time
+         * Supports up tp 14 morph target buffers at the same time
          * Limited due to the limited number of attributes you can bind to a vertex shader usually 16
          * <p>
          * MorphTarget buffers are either POSITION, NORMAL or TANGENT buffers.
          * So we can support up to
-         * 10 simultaneous POSITION targets
-         * 5 simultaneous POSITION and NORMAL targets
-         * 3 simultaneous POSTION, NORMAL and TANGENT targets.
+         * 14 simultaneous POSITION targets
+         * 7 simultaneous POSITION and NORMAL targets
+         * 4 simultaneous POSTION, NORMAL and TANGENT targets.
          * <p>
+         * Note that the MorphControl will find how many buffers can be supported for each mesh/material combination.
          * Note that all buffers have 3 components (Vector3f) even the Tangent buffer that
          * does not contain the w (handedness) component that will not be interpolated for morph animation.
          * <p>

+ 5 - 5
jme3-examples/src/main/java/jme3test/model/TestGltfLoading.java

@@ -116,15 +116,15 @@ public class TestGltfLoading extends SimpleApplication {
 //        rootNode.addLight(pl1);
 
         //loadModel("Models/gltf/polly/project_polly.gltf", new Vector3f(0, 0, 0), 0.5f);
-        loadModel("Models/gltf/zophrac/scene.gltf", new Vector3f(0, 0, 0), 0.1f);
+        //loadModel("Models/gltf/zophrac/scene.gltf", new Vector3f(0, 0, 0), 0.1f);
     //    loadModel("Models/gltf/scifigirl/scene.gltf", new Vector3f(0, -1, 0), 0.1f);
         //loadModel("Models/gltf/man/scene.gltf", new Vector3f(0, -1, 0), 0.1f);
        //loadModel("Models/gltf/torus/scene.gltf", new Vector3f(0, -1, 0), 0.1f);
         //loadModel("Models/gltf/morph/scene.gltf", new Vector3f(0, 0, 0), 0.2f);
         //loadModel("Models/gltf/morphCube/AnimatedMorphCube.gltf", new Vector3f(0, 0, 0), 1f);
-       // loadModel("Models/gltf/morph/SimpleMorph.gltf", new Vector3f(0, 0, 0), 0.1f);
+     //   loadModel("Models/gltf/morph/SimpleMorph.gltf", new Vector3f(0, 0, 0), 0.1f);
         //loadModel("Models/gltf/nier/scene.gltf", new Vector3f(0, -1.5f, 0), 0.01f);
-        //loadModel("Models/gltf/izzy/scene.gltf", new Vector3f(0, -1, 0), 0.01f);
+        loadModel("Models/gltf/izzy/scene.gltf", new Vector3f(0, -1, 0), 0.01f);
         //loadModel("Models/gltf/darth/scene.gltf", new Vector3f(0, -1, 0), 0.01f);
         //loadModel("Models/gltf/mech/scene.gltf", new Vector3f(0, -1, 0), 0.01f);
         //loadModel("Models/gltf/elephant/scene.gltf", new Vector3f(0, -1, 0), 0.01f);
@@ -132,7 +132,7 @@ public class TestGltfLoading extends SimpleApplication {
         //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/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);
@@ -213,7 +213,7 @@ public class TestGltfLoading extends SimpleApplication {
 
         dumpScene(rootNode, 0);
 
-        stateManager.attach(new DetailedProfilerState());
+      //  stateManager.attach(new DetailedProfilerState());
     }
 
     private <T extends Control> T findControl(Spatial s, Class<T> controlClass) {

+ 19 - 17
jme3-examples/src/main/java/jme3test/model/anim/TestAnimMorphSerialization.java

@@ -1,7 +1,6 @@
 package jme3test.model.anim;
 
-import com.jme3.anim.AnimComposer;
-import com.jme3.anim.SkinningControl;
+import com.jme3.anim.*;
 import com.jme3.anim.util.AnimMigrationUtils;
 import com.jme3.app.ChaseCameraAppState;
 import com.jme3.app.SimpleApplication;
@@ -26,7 +25,7 @@ import java.util.Queue;
 /**
  * Created by Nehon on 18/12/2017.
  */
-public class TestAnimSerialization extends SimpleApplication {
+public class TestAnimMorphSerialization extends SimpleApplication {
 
     ArmatureDebugAppState debugAppState;
     AnimComposer composer;
@@ -35,7 +34,7 @@ public class TestAnimSerialization extends SimpleApplication {
     File file;
 
     public static void main(String... argv) {
-        TestAnimSerialization app = new TestAnimSerialization();
+        TestAnimMorphSerialization app = new TestAnimMorphSerialization();
         app.start();
     }
 
@@ -44,15 +43,14 @@ public class TestAnimSerialization extends SimpleApplication {
         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);
+        //rootNode.addLight(new DirectionalLight(new Vector3f(-1, -1, -1).normalizeLocal()));
+        //rootNode.addLight(new AmbientLight(ColorRGBA.DarkGray));
+        Node probeNode = (Node) assetManager.loadModel("Scenes/defaultProbe.j3o");
+        rootNode.attachChild(probeNode);
+        Spatial model = assetManager.loadModel("Models/gltf/zophrac/scene.gltf");
 
         File storageFolder = JmeSystem.getStorageFolder();
-        file = new File(storageFolder.getPath() + File.separator + "newJaime.j3o");
+        file = new File(storageFolder.getPath() + File.separator + "zophrac.j3o");
         BinaryExporter be = new BinaryExporter();
         try {
             be.save(model, file);
@@ -61,20 +59,20 @@ public class TestAnimSerialization extends SimpleApplication {
         }
 
         assetManager.registerLocator(storageFolder.getPath(), FileLocator.class);
-        model = assetManager.loadModel("newJaime.j3o");
-
-        rootNode.attachChild(model);
+        Spatial model2 = assetManager.loadModel("zophrac.j3o");
+        model2.setLocalScale(0.1f);
+        probeNode.attachChild(model2);
 
         debugAppState = new ArmatureDebugAppState();
         stateManager.attach(debugAppState);
 
-        setupModel(model);
+        setupModel(model2);
 
         flyCam.setEnabled(false);
 
         Node target = new Node("CamTarget");
         //target.setLocalTransform(model.getLocalTransform());
-        target.move(0, 1, 0);
+        target.move(0, 0, 0);
         ChaseCameraAppState chaseCam = new ChaseCameraAppState();
         chaseCam.setTarget(target);
         getStateManager().attach(chaseCam);
@@ -130,10 +128,14 @@ public class TestAnimSerialization extends SimpleApplication {
         }
         composer = model.getControl(AnimComposer.class);
         if (composer != null) {
+//            model.getControl(SkinningControl.class).setEnabled(false);
+//            model.getControl(MorphControl.class).setEnabled(false);
+//            composer.setEnabled(false);
 
-            SkinningControl sc = model.getControl(SkinningControl.class);
 
+            SkinningControl sc = model.getControl(SkinningControl.class);
             debugAppState.addArmatureFrom(sc);
+
             anims.clear();
             for (String name : composer.getAnimClipsNames()) {
                 anims.add(name);

+ 2 - 2
jme3-examples/src/main/java/jme3test/model/anim/TestArmature.java

@@ -52,7 +52,7 @@ public class TestArmature extends SimpleApplication {
 
         final Armature armature = new Armature(joints);
         //armature.setModelTransformClass(SeparateJointModelTransform.class);
-        armature.setBindPose();
+        armature.saveBindPose();
 
         //create animations
         AnimClip clip = new AnimClip("anim");
@@ -131,7 +131,7 @@ public class TestArmature extends SimpleApplication {
             public void onAction(String name, boolean isPressed, float tpf) {
                 if (isPressed) {
                     composer.reset();
-                    armature.resetToBindPose();
+                    armature.applyBindPose();
 
                 } else {
                     composer.setCurrentAction("anim");

+ 2 - 2
jme3-examples/src/main/java/jme3test/model/anim/TestBaseAnimSerialization.java

@@ -59,7 +59,7 @@ public class TestBaseAnimSerialization extends SimpleApplication {
 
         armature = new Armature(joints);
         //armature.setModelTransformClass(SeparateJointModelTransform.class);
-        armature.setBindPose();
+        armature.saveBindPose();
 
         //create animations
         AnimClip clip = new AnimClip("anim");
@@ -153,7 +153,7 @@ public class TestBaseAnimSerialization extends SimpleApplication {
             public void onAction(String name, boolean isPressed, float tpf) {
                 if (isPressed) {
                     composer.reset();
-                    armature.resetToBindPose();
+                    armature.applyBindPose();
 
                 } else {
                     composer.setCurrentAction("anim");

+ 1 - 0
jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfLoader.java

@@ -1009,6 +1009,7 @@ public class GltfLoader implements AssetLoader {
             skinnedSpatials.put(skinData, new ArrayList<Spatial>());
 
             armature.update();
+            armature.saveInitialPose();
         }
     }
 

+ 1 - 1
jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/SkeletonLoader.java

@@ -161,7 +161,7 @@ public class SkeletonLoader extends DefaultHandler implements AssetLoader {
             }
             indexToJoint.clear();
             armature = new Armature(joints);
-            armature.setBindPose();
+            armature.saveBindPose();
         } else if (qName.equals("animation")) {
             animClips.add(animClip);
             animClip = null;