Browse Source

glTF: Fixed animation data interpolation, also renamed AnimData to TrackData to match JME paradigm.

Nehon 8 năm trước cách đây
mục cha
commit
54061124a9

+ 71 - 28
jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfLoader.java

@@ -19,7 +19,6 @@ import com.jme3.util.mikktspace.MikktspaceTangentGenerator;
 import javax.xml.bind.DatatypeConverter;
 import java.io.*;
 import java.nio.Buffer;
-import java.sql.Time;
 import java.util.*;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -714,7 +713,7 @@ public class GltfLoader implements AssetLoader {
         assertNotNull(samplers, "No samplers for animation " + name);
 
         //temp data storage of track data
-        AnimData[] animatedNodes = new AnimData[nodes.size()];
+        TrackData[] animatedNodes = new TrackData[nodes.size()];
 
         for (JsonElement channel : channels) {
 
@@ -733,10 +732,10 @@ public class GltfLoader implements AssetLoader {
                 logger.log(Level.WARNING, "Morph animation is not supported by JME yet, skipping animation");
                 continue;
             }
-            AnimData animData = animatedNodes[targetNode];
-            if (animData == null) {
-                animData = new AnimData();
-                animatedNodes[targetNode] = animData;
+            TrackData trackData = animatedNodes[targetNode];
+            if (trackData == null) {
+                trackData = new TrackData();
+                animatedNodes[targetNode] = trackData;
             }
 
             Integer samplerIndex = getAsInteger(channel.getAsJsonObject(), "sampler");
@@ -754,7 +753,7 @@ public class GltfLoader implements AssetLoader {
                 logger.log(Level.WARNING, "JME only supports linear interpolation for animations");
             }
 
-            animData = customContentManager.readExtensionAndExtras("animation.sampler", sampler, animData);
+            trackData = customContentManager.readExtensionAndExtras("animation.sampler", sampler, trackData);
 
             float[] times = fetchFromCache("accessors", timeIndex, float[].class);
             if (times == null) {
@@ -763,17 +762,17 @@ public class GltfLoader implements AssetLoader {
             }
 
             if (targetPath.equals("translation")) {
-                animData.timeArrays.add(new AnimData.TimeData(times, AnimData.Type.Translation));
+                trackData.timeArrays.add(new TrackData.TimeData(times, TrackData.Type.Translation));
                 Vector3f[] translations = readAccessorData(dataIndex, vector3fArrayPopulator);
-                animData.translations = translations;
+                trackData.translations = translations;
             } else if (targetPath.equals("scale")) {
-                animData.timeArrays.add(new AnimData.TimeData(times, AnimData.Type.Scale));
+                trackData.timeArrays.add(new TrackData.TimeData(times, TrackData.Type.Scale));
                 Vector3f[] scales = readAccessorData(dataIndex, vector3fArrayPopulator);
-                animData.scales = scales;
+                trackData.scales = scales;
             } else if (targetPath.equals("rotation")) {
-                animData.timeArrays.add(new AnimData.TimeData(times, AnimData.Type.Rotation));
+                trackData.timeArrays.add(new TrackData.TimeData(times, TrackData.Type.Rotation));
                 Quaternion[] rotations = readAccessorData(dataIndex, quaternionArrayPopulator);
-                animData.rotations = rotations;
+                trackData.rotations = rotations;
             } else {
                 //TODO support weights
                 logger.log(Level.WARNING, "Morph animation is not supported");
@@ -781,7 +780,7 @@ public class GltfLoader implements AssetLoader {
                 continue;
 
             }
-            animatedNodes[targetNode] = customContentManager.readExtensionAndExtras("channel", channel, animData);
+            animatedNodes[targetNode] = customContentManager.readExtensionAndExtras("channel", channel, trackData);
         }
 
         if (name == null) {
@@ -794,26 +793,26 @@ public class GltfLoader implements AssetLoader {
         int skinIndex = -1;
 
         for (int i = 0; i < animatedNodes.length; i++) {
-            AnimData animData = animatedNodes[i];
-            if (animData == null) {
+            TrackData trackData = animatedNodes[i];
+            if (trackData == null) {
                 continue;
             }
-            animData.update();
-            if (animData.length > anim.getLength()) {
-                anim.setLength(animData.length);
+            trackData.update();
+            if (trackData.length > anim.getLength()) {
+                anim.setLength(trackData.length);
             }
             Object node = fetchFromCache("nodes", i, Object.class);
             if (node instanceof Spatial) {
                 Spatial s = (Spatial) node;
                 spatials.add(s);
-                SpatialTrack track = new SpatialTrack(animData.times, animData.translations, animData.rotations, animData.scales);
+                SpatialTrack track = new SpatialTrack(trackData.times, trackData.translations, trackData.rotations, trackData.scales);
                 track.setTrackSpatial(s);
                 anim.addTrack(track);
             } else if (node instanceof BoneWrapper) {
                 BoneWrapper b = (BoneWrapper) node;
                 //apply the inverseBindMatrix to animation data.
-                b.update(animData);
-                BoneTrack track = new BoneTrack(b.boneIndex, animData.times, animData.translations, animData.rotations, animData.scales);
+                b.update(trackData);
+                BoneTrack track = new BoneTrack(b.boneIndex, trackData.times, trackData.translations, trackData.rotations, trackData.scales);
                 anim.addTrack(track);
                 if (skinIndex == -1) {
                     skinIndex = b.skinIndex;
@@ -961,6 +960,7 @@ public class GltfLoader implements AssetLoader {
         bw.bone.setLocalTranslation(bw.localTransform.getTranslation());
         bw.bone.setLocalRotation(bw.localTransform.getRotation());
         bw.bone.setLocalScale(bw.localTransform.getScale());
+        bw.bone.setUserControl(false);
     }
 
     private void computeBindTransforms(BoneWrapper boneWrapper, Skeleton skeleton) {
@@ -1159,12 +1159,17 @@ public class GltfLoader implements AssetLoader {
         /**
          * Applies the inverse Bind transforms to anim data. and the armature transforms if relevant.
          */
-        public void update(AnimData data) {
+        public void update(TrackData data) {
             Transform bindTransforms = new Transform(bone.getBindPosition(), bone.getBindRotation(), bone.getBindScale());
             SkinData skinData = fetchFromCache("skins", skinIndex, SkinData.class);
 
-            for (int i = 0; i < data.translations.length; i++) {
-                Transform t = new Transform(data.translations[i], data.rotations[i], data.scales[i]);
+            for (int i = 0; i < data.getNbKeyFrames(); i++) {
+
+                Vector3f translation = getTranslation(data, bindTransforms, i);
+                Quaternion rotation = getRotation(data, bindTransforms, i);
+                Vector3f scale = getScale(data, bindTransforms, i);
+
+                Transform t = new Transform(translation, rotation, scale);
                 if (isRoot) {
                     //Apply the armature transforms to the root bone anim track.
                     t.combineWithParent(skinData.armatureTransforms);
@@ -1180,10 +1185,48 @@ public class GltfLoader implements AssetLoader {
                 tmpQuat.set(bindTransforms.getRotation()).inverseLocal().multLocal(t.getRotation());
                 t.setRotation(tmpQuat);
 
-                data.translations[i] = t.getTranslation();
-                data.rotations[i] = t.getRotation();
-                data.scales[i] = t.getScale();
+                if(data.translations != null) {
+                    data.translations[i] = t.getTranslation();
+                }
+                if(data.rotations != null) {
+                    data.rotations[i] = t.getRotation();
+                }
+                if(data.scales != null) {
+                    data.scales[i] = t.getScale();
+                }
+            }
+
+            data.ensureTranslationRotations();
+        }
+
+        private Vector3f getTranslation(TrackData data, Transform bindTransforms, int i) {
+            Vector3f translation;
+            if(data.translations == null){
+                translation = bindTransforms.getTranslation();
+            } else {
+                translation = data.translations[i];
+            }
+            return translation;
+        }
+
+        private Quaternion getRotation(TrackData data, Transform bindTransforms, int i) {
+            Quaternion rotation;
+            if(data.rotations == null){
+                rotation = bindTransforms.getRotation();
+            } else {
+                rotation = data.rotations[i];
+            }
+            return rotation;
+        }
+
+        private Vector3f getScale(TrackData data, Transform bindTransforms, int i) {
+            Vector3f scale;
+            if(data.scales == null){
+                scale = bindTransforms.getScale();
+            } else {
+                scale = data.scales[i];
             }
+            return scale;
         }
     }
 

+ 42 - 17
jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/AnimData.java → jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/TrackData.java

@@ -4,7 +4,7 @@ import com.jme3.math.*;
 
 import java.util.*;
 
-public class AnimData {
+public class TrackData {
 
     public enum Type {
         Translation,
@@ -27,7 +27,6 @@ public class AnimData {
 
         if (equalTimes(timeArrays)) {
             times = timeArrays.get(0).times;
-            ensureArraysInit();
         } else {
             //Times array are different and contains different sampling times.
             //We have to merge them because JME needs the 3 types of transforms for each keyFrame.
@@ -69,7 +68,7 @@ public class AnimData {
             // populating transforms array from the keyframes, interpolating
             times = new float[keyFrames.size()];
 
-            ensureArraysInit();
+            ensureArraysLength();
 
             TransformIndices translationIndices = new TransformIndices();
             TransformIndices rotationIndices = new TransformIndices();
@@ -79,14 +78,18 @@ public class AnimData {
                 KeyFrame kf = keyFrames.get(i);
                 //we need Interpolate between keyframes when transforms are sparse.
                 times[i] = kf.time;
-                populateTransform(Type.Translation, i, keyFrames, kf, translationIndices);
-                populateTransform(Type.Rotation, i, keyFrames, kf, rotationIndices);
-                populateTransform(Type.Scale, i, keyFrames, kf, scaleIndices);
+                if(translations != null) {
+                    populateTransform(Type.Translation, i, keyFrames, kf, translationIndices);
+                }
+                if(rotations != null) {
+                    populateTransform(Type.Rotation, i, keyFrames, kf, rotationIndices);
+                }
+                if(scales != null) {
+                    populateTransform(Type.Scale, i, keyFrames, kf, scaleIndices);
+                }
             }
         }
 
-        ensureArraysInit();
-
         if (times[0] > 0) {
             //Anim doesn't start at 0, JME can't handle that and will interpolate transforms linearly from 0 to the first frame of the anim.
             //we need to add a frame at 0 that copies the first real frame
@@ -174,6 +177,19 @@ public class AnimData {
         return -1;
     }
 
+    public int getNbKeyFrames(){
+        if(translations != null){
+            return translations.length;
+        }
+        if(rotations != null){
+            return rotations.length;
+        }
+        if(scales != null){
+            return scales.length;
+        }
+        return 0;
+    }
+
     private void interpolate(Type type, float ratio, KeyFrame lastKeyFrame, KeyFrame nextKeyFrame, int currentIndex) {
         //TODO here we should interpolate differently according to the interpolation given in the gltf file.
         switch (type) {
@@ -217,25 +233,34 @@ public class AnimData {
         }
     }
 
-    private void ensureArraysInit() {
-        if (translations == null || translations.length < times.length) {
+    private void ensureArraysLength() {
+        if (translations != null && translations.length < times.length) {
+            translations = new Vector3f[times.length];
+        }
+        if (rotations != null && rotations.length < times.length) {
+            rotations = new Quaternion[times.length];
+        }
+        if (scales != null && scales.length < times.length) {
+            scales = new Vector3f[times.length];
+        }
+    }
+
+
+    //JME assumes there are translation and rotation track every time, so we create them with identity transforms if they don't exist
+    //TODO change this behavior in BoneTrack.
+    public void ensureTranslationRotations() {
+        if (translations == null) {
             translations = new Vector3f[times.length];
             for (int i = 0; i < translations.length; i++) {
                 translations[i] = new Vector3f();
             }
         }
-        if (rotations == null || rotations.length < times.length) {
+        if (rotations == null) {
             rotations = new Quaternion[times.length];
             for (int i = 0; i < rotations.length; i++) {
                 rotations[i] = new Quaternion();
             }
         }
-        if (scales == null || scales.length < times.length) {
-            scales = new Vector3f[times.length];
-            for (int i = 0; i < scales.length; i++) {
-                scales[i] = new Vector3f().set(Vector3f.UNIT_XYZ);
-            }
-        }
     }
 
     private void setKeyFrameTransforms(Type type, KeyFrame keyFrame, float[] transformTimes) {