Selaa lähdekoodia

FBX: more work on importing skeletal animation

Kirill Vainer 10 vuotta sitten
vanhempi
commit
2ced7653a7

+ 5 - 2
jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java

@@ -108,8 +108,8 @@ public class SkeletonControl extends AbstractControl implements Cloneable {
     /**
      * Material references used for hardware skinning
      */
-    private Set<Material> materials = new HashSet<Material>();
-
+    private final HashSet<Material> materials = new HashSet<Material>();
+    
     /**
      * Serialization only. Do not use.
      */
@@ -202,6 +202,9 @@ public class SkeletonControl extends AbstractControl implements Cloneable {
      * @param skeleton the skeleton
      */
     public SkeletonControl(Skeleton skeleton) {
+        if (skeleton == null) {
+            throw new IllegalArgumentException("skeleton cannot be null");
+        }
         this.skeleton = skeleton;
     }
 

+ 2 - 2
jme3-core/src/main/resources/com/jme3/asset/General.cfg

@@ -22,5 +22,5 @@ LOADER com.jme3.scene.plugins.ogre.MaterialLoader : material
 LOADER com.jme3.scene.plugins.ogre.SceneLoader : scene
 LOADER com.jme3.scene.plugins.blender.BlenderModelLoader : blend
 LOADER com.jme3.shader.plugins.GLSLLoader : vert, frag, geom, tsctrl, tseval, glsl, glsllib
-LOADER com.jme3.scene.plugins.fbx.SceneLoader : fbx
-LOADER com.jme3.scene.plugins.fbx.SceneWithAnimationLoader : fba
+LOADER com.jme3.scene.plugins.fbx.FbxLoader : fbx
+# LOADER com.jme3.scene.plugins.fbx.SceneWithAnimationLoader : fba

+ 28 - 28
jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/FbxLoader.java

@@ -150,7 +150,7 @@ public class FbxLoader implements AssetLoader {
     private void loadData(InputStream stream) throws IOException {
         FbxFile scene = FbxReader.readFBX(stream);
 
-        FbxDump.dumpFile(scene);
+//        FbxDump.dumpFile(scene);
 
         // TODO: Load FBX object templates
         
@@ -346,33 +346,33 @@ public class FbxLoader implements AssetLoader {
             duration = pair.getDuration();
             
             if (pair.node instanceof FbxLimbNode) {
-                // Find the spatial that has the skeleton for this limb.
-                FbxLimbNode limbNode = (FbxLimbNode) pair.node;
-                Bone bone = limbNode.getJmeBone();
-                Spatial jmeSpatial = limbNode.getSkeletonHolder().getJmeObject();
-                Skeleton skeleton = limbNode.getSkeletonHolder().getJmeSkeleton();
-                
-                // Get the animation control (create if missing).
-                AnimControl animControl = jmeSpatial.getControl(AnimControl.class);
-                if (animControl.getSkeleton() != skeleton) {
-                    throw new UnsupportedOperationException();
-                }
-                
-                // Get the animation (create if missing).
-                Animation anim = animControl.getAnim(animName);
-                if (anim == null) { 
-                    anim = new Animation(animName, duration);
-                    animControl.addAnim(anim);
-                }
-                
-                // Find the bone index from the spatial's skeleton.
-                int boneIndex = skeleton.getBoneIndex(bone);
-                
-                // Generate the bone track.
-                BoneTrack bt = pair.toJmeBoneTrack(boneIndex, bone.getBindInverseTransform());
-                
-                // Add the bone track to the animation.
-                anim.addTrack(bt);
+//                // Find the spatial that has the skeleton for this limb.
+//                FbxLimbNode limbNode = (FbxLimbNode) pair.node;
+//                Bone bone = limbNode.getJmeBone();
+//                Spatial jmeSpatial = limbNode.getSkeletonRoot().getJmeObject();
+//                Skeleton skeleton = limbNode.getSkeletonRoot().getJmeSkeleton();
+//                
+//                // Get the animation control (create if missing).
+//                AnimControl animControl = jmeSpatial.getControl(AnimControl.class);
+//                if (animControl.getSkeleton() != skeleton) {
+//                    throw new UnsupportedOperationException();
+//                }
+//                
+//                // Get the animation (create if missing).
+//                Animation anim = animControl.getAnim(animName);
+//                if (anim == null) { 
+//                    anim = new Animation(animName, duration);
+//                    animControl.addAnim(anim);
+//                }
+//                
+//                // Find the bone index from the spatial's skeleton.
+//                int boneIndex = skeleton.getBoneIndex(bone);
+//                
+//                // Generate the bone track.
+//                BoneTrack bt = pair.toJmeBoneTrack(boneIndex, bone.getBindInverseTransform());
+//                
+//                // Add the bone track to the animation.
+//                anim.addTrack(bt);
             } else {
                 // Create the spatial animation
                 Animation anim = new Animation(animName, duration);

+ 10 - 0
jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/anim/FbxAnimUtil.java

@@ -31,6 +31,8 @@
  */
 package com.jme3.scene.plugins.fbx.anim;
 
+import com.jme3.math.Matrix4f;
+
 public class FbxAnimUtil {
     /**
      * Conversion factor from FBX animation time unit to seconds.
@@ -41,4 +43,12 @@ public class FbxAnimUtil {
     public static final String CURVE_NODE_PROPERTY_Y          = "d|Y";
     public static final String CURVE_NODE_PROPERTY_Z          = "d|Z";
     public static final String CURVE_NODE_PROPERTY_VISIBILITY = "d|Visibility";
+    
+    public static Matrix4f toMatrix4(double[] matrixData) {
+        float[] matrixDataFloat = new float[16];
+        for (int i = 0; i < matrixData.length; i++) {
+            matrixDataFloat[i] = (float) matrixData[i];
+        }
+        return new Matrix4f(matrixDataFloat);
+    }
 }

+ 5 - 11
jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/anim/FbxBindPose.java

@@ -56,31 +56,25 @@ public class FbxBindPose extends FbxObject<Map<FbxId, Matrix4f>> {
             }
             
             FbxId node = null;
-            float[] matData = null;
+            double[] matData = null;
             
             for (FbxElement e : child.children) {
                 if (e.id.equals("Node")) {
                     node = FbxId.create(e.properties.get(0));
                 } else if (e.id.equals("Matrix")) {
-                    double[] matDataDoubles = (double[]) e.properties.get(0);
+                    matData = (double[]) e.properties.get(0);
                     
-                    if (matDataDoubles.length != 16) {
+                    if (matData.length != 16) {
                         // corrupt
                         throw new UnsupportedOperationException("Bind pose matrix "
                                 + "must have 16 doubles, but it has " 
-                                + matDataDoubles.length + ". Data is corrupt");
-                    }
-                    
-                    matData = new float[16];
-                    for (int i = 0; i < matDataDoubles.length; i++) {
-                        matData[i] = (float) matDataDoubles[i];
+                                + matData.length + ". Data is corrupt");
                     }
                 }
             }
             
             if (node != null && matData != null) {
-                Matrix4f matrix = new Matrix4f(matData);
-                bindPose.put(node, matrix);
+                bindPose.put(node, FbxAnimUtil.toMatrix4(matData));
             }
         }
     }

+ 26 - 0
jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/anim/FbxCluster.java

@@ -32,6 +32,7 @@
 package com.jme3.scene.plugins.fbx.anim;
 
 import com.jme3.asset.AssetManager;
+import com.jme3.math.Matrix4f;
 import com.jme3.scene.plugins.fbx.file.FbxElement;
 import com.jme3.scene.plugins.fbx.obj.FbxObject;
 import java.util.logging.Level;
@@ -45,6 +46,10 @@ public class FbxCluster extends FbxObject {
     private double[] weights;
     private FbxLimbNode limb;
     
+    private Matrix4f transformMatrix;
+    private Matrix4f transformLinkMatrix;
+    private Matrix4f transformAssociateModelMatrix;
+    
     public FbxCluster(AssetManager assetManager, String sceneFolderName) {
         super(assetManager, sceneFolderName);
     }
@@ -57,6 +62,15 @@ public class FbxCluster extends FbxObject {
                 indexes = (int[]) e.properties.get(0);
             } else if (e.id.equals("Weights")) {
                 weights = (double[]) e.properties.get(0);
+            } else if (e.id.equals("Transform")) {
+                double[] data = (double[]) e.properties.get(0);
+                transformMatrix = FbxAnimUtil.toMatrix4(data);
+            } else if (e.id.equals("TransformLink")) {
+                double[] data = (double[]) e.properties.get(0);
+                transformLinkMatrix = FbxAnimUtil.toMatrix4(data);
+            } else if (e.id.equals("TransformAssociateModel")) {
+                double[] data = (double[]) e.properties.get(0);
+                transformAssociateModelMatrix = FbxAnimUtil.toMatrix4(data);
             }
         }
     }
@@ -86,6 +100,18 @@ public class FbxCluster extends FbxObject {
                 return;
             }
             limb = (FbxLimbNode) object;
+            
+            System.out.println(" ----- for limb: " + limb.getName());
+            System.out.println(" transform : " + transformMatrix);
+            System.out.println(" transform link : " + transformLinkMatrix);
+            System.out.println(" transform associate model : " + transformAssociateModelMatrix);
+            
+            //  Invert(Invert(TransformLinkMatrix) * TransformMatrix * Geometry)
+            Matrix4f accumMatrix = transformLinkMatrix.invert();
+            accumMatrix.multLocal(transformMatrix);
+            accumMatrix.invertLocal();
+            
+            System.out.println(" limb bind pose : " + accumMatrix);
         } else {
             unsupportedConnectObject(object);
         }

+ 6 - 48
jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/anim/FbxLimbNode.java

@@ -31,64 +31,22 @@
  */
 package com.jme3.scene.plugins.fbx.anim;
 
-import com.jme3.animation.Bone;
-import com.jme3.animation.Skeleton;
 import com.jme3.asset.AssetManager;
 import com.jme3.scene.plugins.fbx.node.FbxNode;
-import java.util.ArrayList;
-import java.util.List;
 
 public class FbxLimbNode extends FbxNode {
     
-    protected FbxNode skeletonHolder;
-    protected Bone bone;
+    protected FbxNode skeletonRoot;
     
     public FbxLimbNode(AssetManager assetManager, String sceneFolderName) {
         super(assetManager, sceneFolderName);
     }
     
-    private static void createBones(FbxNode skeletonHolderNode, FbxLimbNode limb, List<Bone> bones) {
-        limb.skeletonHolder = skeletonHolderNode;
-        
-        Bone parentBone = limb.getJmeBone();
-        bones.add(parentBone);
-        
-        for (FbxNode child : limb.children) {
-            if (child instanceof FbxLimbNode) {
-                FbxLimbNode childLimb = (FbxLimbNode) child;
-                createBones(skeletonHolderNode, childLimb, bones);
-                parentBone.addChild(childLimb.getJmeBone());
-            }
-        }
+    public FbxNode getSkeletonRoot() {
+        return skeletonRoot;
     }
-    
-    public static Skeleton createSkeleton(FbxNode skeletonHolderNode) {
-        if (skeletonHolderNode instanceof FbxLimbNode) {
-            throw new UnsupportedOperationException("Limb nodes cannot be skeleton holders");
-        }
-        
-        List<Bone> bones = new ArrayList<Bone>();
-        
-        for (FbxNode child : skeletonHolderNode.getChildren()) {
-            if (child instanceof FbxLimbNode) {
-                createBones(skeletonHolderNode, (FbxLimbNode) child, bones);
-            }
-        }
-        
-        return new Skeleton(bones.toArray(new Bone[0]));
-    }
-    
-    public FbxNode getSkeletonHolder() {
-        return skeletonHolder;
-    }
-    
-    public Bone getJmeBone() {
-        if (bone == null) {
-            bone = new Bone(name);
-            bone.setBindTransforms(jmeLocalBindPose.getTranslation(),
-                                   jmeLocalBindPose.getRotation(),
-                                   jmeLocalBindPose.getScale());
-        }
-        return bone;
+
+    public void setSkeletonRoot(FbxNode skeletonRoot) {
+        this.skeletonRoot = skeletonRoot;
     }
 }

+ 112 - 0
jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/anim/FbxSkeleton.java

@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2009-2015 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.scene.plugins.fbx.anim;
+
+import com.jme3.animation.Bone;
+import com.jme3.animation.Skeleton;
+import com.jme3.scene.plugins.fbx.node.FbxNode;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Similar to {@link Skeleton jME skeleton} except 
+ * contains {@link FbxLimbNode limb nodes}.
+ * 
+ * This is used to determine the bone indices (for assigning clusters to meshes)
+ * as well as the limb hierarchy when creating the jME3 Skeleton.
+ * 
+ * @author Kirill Vainer
+ */
+public class FbxSkeleton {
+    
+    FbxLimbNode[] rootLimbs;
+    FbxLimbNode[] allLimbs;
+    HashMap<FbxLimbNode, Integer> limbToIndexMap = new HashMap<FbxLimbNode, Integer>();
+
+    private FbxSkeleton() {
+    }
+    
+    public static void populateSkeletonData(FbxNode skeletonRoot) {
+//        if (skeletonRoot instanceof FbxLimbNode) {
+//            throw new UnsupportedOperationException("Limb node cannot be a skeleton root");
+//        }
+//        
+//        FbxSkeleton skeleton = new FbxSkeleton();
+//        skeleton.scanLimbs(skeletonRoot);
+//        skeletonRoot.setFbxSkeleton(skeleton);
+    }
+    
+    private void scanLimbs(FbxNode skeletonRoot, FbxLimbNode limb, List<FbxLimbNode> limbList) {
+//        limb.skeletonRoot = skeletonRoot;
+//        limbList.add(limb);
+//        for (FbxNode child : limb.getChildren()) {
+//            if (child instanceof FbxLimbNode) {
+//                FbxLimbNode childLimb = (FbxLimbNode) child;
+//                scanLimbs(skeletonRoot, childLimb, limbList);
+//            }
+//        }
+    }
+    
+    private void scanLimbs(FbxNode skeletonRoot) {
+        List<FbxLimbNode> limbList = new ArrayList<FbxLimbNode>();
+        List<FbxLimbNode> rootList = new ArrayList<FbxLimbNode>();
+        
+        for (FbxNode child : skeletonRoot.getChildren()) {
+            if (child instanceof FbxLimbNode) {
+                FbxLimbNode limb = (FbxLimbNode) child;
+                rootList.add(limb);
+                scanLimbs(skeletonRoot, limb, limbList);
+            }
+        }
+        
+        allLimbs = limbList.toArray(new FbxLimbNode[0]);
+        rootLimbs = rootList.toArray(new FbxLimbNode[0]);
+        
+        for (int i = 0; i < allLimbs.length; i++) {
+            limbToIndexMap.put(allLimbs[i], i);
+        }
+    }
+    
+    public int getLimbIndex(FbxLimbNode limbNode) {
+        return limbToIndexMap.get(limbNode);
+    }
+    
+    public FbxLimbNode getLimb(int index) {
+        return allLimbs[index];
+    }
+    
+    public FbxLimbNode[] getRootLimbs() {
+        return rootLimbs;
+    }
+    
+}

+ 74 - 4
jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/anim/FbxSkinDeformer.java

@@ -31,24 +31,94 @@
  */
 package com.jme3.scene.plugins.fbx.anim;
 
+import com.jme3.animation.Bone;
+import com.jme3.animation.Skeleton;
 import com.jme3.asset.AssetManager;
+import com.jme3.math.Transform;
+import com.jme3.scene.plugins.fbx.node.FbxNode;
 import com.jme3.scene.plugins.fbx.obj.FbxObject;
 import java.util.ArrayList;
 import java.util.List;
 
-public class FbxSkinDeformer extends FbxObject<List<FbxCluster>> {
+public class FbxSkinDeformer extends FbxObject<Skeleton> {
 
+    private FbxNode skeletonRoot;
     private final List<FbxCluster> clusters = new ArrayList<FbxCluster>();
     
     public FbxSkinDeformer(AssetManager assetManager, String sceneFolderName) {
         super(assetManager, sceneFolderName);
     }
     
+    private boolean isHierarchyCompatible(Bone thisBone, Bone otherBone) {
+        Transform thisTransform = thisBone.getBindInverseTransform();
+        Transform otherTransform = otherBone.getBindInverseTransform();
+        throw new UnsupportedOperationException();
+    }
+    
+    /** 
+     * Determine if both skin deformers can share the same 
+     * Skeleton object and hence the same SkeletonControl / AnimControl. 
+     * 
+     * @param skinDeformer The skin deformer to test compatibility against.
+     * @return True if the skeletons are identical and can be shared, false
+     * otherwise.
+     */
+    public boolean isCompatible(FbxSkinDeformer skinDeformer) {
+        Skeleton thisSkeleton = this.getJmeObject();
+        Skeleton otherSkeleton = skinDeformer.getJmeObject();
+        Bone[] thisRoots = thisSkeleton.getRoots();
+        Bone[] otherRoots = otherSkeleton.getRoots();
+        for (int i = 0; i < thisRoots.length; i++) {
+            
+        }
+        throw new UnsupportedOperationException();
+    }
+    
+    /** 
+     * Get the root FbxNode containing the skeleton.
+     * 
+     * The node should have one or more FbxLimbNodes which are
+     * the root limbs of the skeleton structure.
+     * 
+     * This is null until prepareSkeletonData() is called.
+     * 
+     * @return The root node containing the skeleton.
+     */
+    public FbxNode getSkeletonRoot() {
+        return skeletonRoot;
+    }
+    
+    /** 
+     * Derives the skeleton from the skin deformer. 
+     * 
+     * The Skeleton hierarchy is derived via the {@link #getSkeletonRoot() skeleton root}
+     *  whereas the bind poses for the bones is derived from the 
+     * {@link #getClusters() clusters}.
+     * 
+     * FbxLimbNode.prepareSkeletonData() must have been called first
+     * The bone's bind pose depends on each cluster's TransformLinkMatrix 
+     * and TransformMatrix.
+     * The bone's bind pose is derived as follows:
+     * <code><pre>
+     * Invert(Invert(TransformLinkMatrix) * TransformMatrix * Geometry)
+     * </code></pre>
+     * 
+     * @return The skeleton as described by this skin deformer.
+     */
     @Override
-    protected List<FbxCluster> toJmeObject() {
+    protected Skeleton toJmeObject() {
+        throw new UnsupportedOperationException();
+    }
+    
+    /**
+     * Get the clusters attached to this skin deformer.
+     * 
+     * @return The skin deformer's clusters.
+     */
+    public List<FbxCluster> getClusters() {
         return clusters;
     }
-
+    
     @Override
     public void connectObject(FbxObject object) {
         if (object instanceof FbxCluster) {
@@ -62,5 +132,5 @@ public class FbxSkinDeformer extends FbxObject<List<FbxCluster>> {
     public void connectObjectProperty(FbxObject object, String property) {
         unsupportedConnectObjectProperty(object, property);
     }
-    
+
 }

+ 21 - 1
jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/anim/FbxToJmeTrack.java

@@ -34,6 +34,7 @@ package com.jme3.scene.plugins.fbx.anim;
 import com.jme3.animation.BoneTrack;
 import com.jme3.animation.SpatialTrack;
 import com.jme3.animation.Track;
+import com.jme3.math.Matrix4f;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Transform;
 import com.jme3.math.Vector3f;
@@ -98,6 +99,7 @@ public final class FbxToJmeTrack {
     }
     
     private static void applyInverse(Vector3f translation, Quaternion rotation, Vector3f scale, Transform inverseBindPose) {
+        /*
         Transform t = new Transform();
         t.setTranslation(translation);
         t.setRotation(rotation);
@@ -111,6 +113,24 @@ public final class FbxToJmeTrack {
         if (scale != null) {
             t.getScale(scale);
         }
+        */
+        
+        Matrix4f mat = new Matrix4f();
+        mat.setTranslation(translation);
+        mat.setRotationQuaternion(rotation);
+        if (scale != null) {
+            mat.setScale(scale);
+        }
+        
+        Matrix4f mat2 = inverseBindPose.toTransformMatrix();
+        mat2.multLocal(mat);
+        mat = mat2;
+        
+        mat.toTranslationVector(translation);
+        mat.toRotationQuat(rotation);
+        if (scale != null) { 
+            mat.toScaleVector(scale);
+        }
     }
     
     private Track toJmeTrackInternal(int boneIndex, Transform inverseBindPose) {
@@ -154,7 +174,7 @@ public final class FbxToJmeTrack {
                 if (i > 0) {
                     if (rotations[i - 1].dot(rotations[i]) < 0) {
                         System.out.println("rotation will go the long way, oh noes");
-                        rotations[i - 1].negate();
+                        rotations[i].negate();
                     }
                 }
             } else {

+ 5 - 1
jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/material/FbxMaterial.java

@@ -307,7 +307,11 @@ public class FbxMaterial extends FbxObject<Material> {
         if (useAlphaBlend) {
             // No idea if this is a transparent or translucent model, gotta guess..
             mat.setTransparent(true);
-            mat.setFloat("AlphaDiscardThreshold", 0.01f);
+            
+            // Commenting this out for now. It causes extra shaders to be 
+            // used and is less efficient due to usage of "discard".
+            // mat.setFloat("AlphaDiscardThreshold", 0.01f);
+            
             mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
         }
         

+ 31 - 31
jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/mesh/FbxMesh.java

@@ -111,36 +111,36 @@ public final class FbxMesh extends FbxNodeAttribute<IntMap<Mesh>> {
     }
     
     public void applyCluster(FbxCluster cluster) {
-        if (boneIndices == null) {
-            boneIndices = new ArrayList[positions.length];
-            boneWeights = new ArrayList[positions.length];
-        }
-        
-        FbxLimbNode limb = cluster.getLimb();
-        Bone bone = limb.getJmeBone();
-        Skeleton skeleton = limb.getSkeletonHolder().getJmeSkeleton();
-        int boneIndex = skeleton.getBoneIndex(bone);
-        
-        int[] positionIndices = cluster.getVertexIndices();
-        double[] weights = cluster.getWeights();
-        
-        for (int i = 0; i < positionIndices.length; i++) {
-            int positionIndex = positionIndices[i];
-            float boneWeight = (float)weights[i];
-            
-            ArrayList<Integer> boneIndicesForVertex = boneIndices[positionIndex];
-            ArrayList<Float>  boneWeightsForVertex = boneWeights[positionIndex];
-            
-            if (boneIndicesForVertex == null) {
-                boneIndicesForVertex = new ArrayList<Integer>();
-                boneWeightsForVertex = new ArrayList<Float>();
-                boneIndices[positionIndex] = boneIndicesForVertex;
-                boneWeights[positionIndex] = boneWeightsForVertex;
-            }
-            
-            boneIndicesForVertex.add(boneIndex);
-            boneWeightsForVertex.add(boneWeight);
-        }
+//        if (boneIndices == null) {
+//            boneIndices = new ArrayList[positions.length];
+//            boneWeights = new ArrayList[positions.length];
+//        }
+//        
+//        FbxLimbNode limb = cluster.getLimb();
+//        Bone bone = limb.getJmeBone();
+//        Skeleton skeleton = limb.getSkeletonRoot().getJmeSkeleton();
+//        int boneIndex = skeleton.getBoneIndex(bone);
+//        
+//        int[] positionIndices = cluster.getVertexIndices();
+//        double[] weights = cluster.getWeights();
+//        
+//        for (int i = 0; i < positionIndices.length; i++) {
+//            int positionIndex = positionIndices[i];
+//            float boneWeight = (float)weights[i];
+//            
+//            ArrayList<Integer> boneIndicesForVertex = boneIndices[positionIndex];
+//            ArrayList<Float>  boneWeightsForVertex = boneWeights[positionIndex];
+//            
+//            if (boneIndicesForVertex == null) {
+//                boneIndicesForVertex = new ArrayList<Integer>();
+//                boneWeightsForVertex = new ArrayList<Float>();
+//                boneIndices[positionIndex] = boneIndicesForVertex;
+//                boneWeights[positionIndex] = boneWeightsForVertex;
+//            }
+//            
+//            boneIndicesForVertex.add(boneIndex);
+//            boneWeightsForVertex.add(boneWeight);
+//        }
     }
     
     @Override
@@ -209,7 +209,7 @@ public final class FbxMesh extends FbxNodeAttribute<IntMap<Mesh>> {
     protected IntMap<Mesh> toJmeObject() {
         // Load clusters from SkinDeformer
         if (skinDeformer != null) {
-            for (FbxCluster cluster : skinDeformer.getJmeObject()) {
+            for (FbxCluster cluster : skinDeformer.getClusters()) {
                 applyCluster(cluster);
             }
         }

+ 29 - 20
jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/node/FbxNode.java

@@ -53,6 +53,7 @@ import com.jme3.scene.debug.SkeletonDebugger;
 import com.jme3.scene.plugins.fbx.anim.FbxAnimCurveNode;
 import com.jme3.scene.plugins.fbx.anim.FbxCluster;
 import com.jme3.scene.plugins.fbx.anim.FbxLimbNode;
+import com.jme3.scene.plugins.fbx.anim.FbxSkeleton;
 import com.jme3.scene.plugins.fbx.anim.FbxSkinDeformer;
 import com.jme3.scene.plugins.fbx.file.FbxElement;
 import com.jme3.scene.plugins.fbx.material.FbxImage;
@@ -108,7 +109,7 @@ public class FbxNode extends FbxObject<Spatial> {
     /**
      * For FBX nodes that contain a skeleton (i.e. FBX limbs).
      */
-    protected Skeleton skeleton;
+    protected FbxSkeleton skeleton;
     
     protected final Transform jmeWorldNodeTransform = new Transform();
     protected final Transform jmeLocalNodeTransform = new Transform();
@@ -376,11 +377,11 @@ public class FbxNode extends FbxObject<Spatial> {
         FbxNode preferredParent = null;
         
         if (deformer != null) {
-            for (FbxCluster cluster : deformer.getJmeObject()) {
+            for (FbxCluster cluster : deformer.getClusters()) {
                 FbxLimbNode limb = cluster.getLimb();
                 if (preferredParent == null) {
-                    preferredParent = limb.getSkeletonHolder();
-                } else if (preferredParent != limb.getSkeletonHolder()) {
+                    preferredParent = limb.getSkeletonRoot();
+                } else if (preferredParent != limb.getSkeletonRoot()) {
                     logger.log(Level.WARNING, "A mesh is being deformed by multiple skeletons. "
                                             + "Only one skeleton will work, ignoring other skeletons.");
                 }
@@ -479,8 +480,8 @@ public class FbxNode extends FbxObject<Spatial> {
             if (fbxNode.skeleton != null) {
                 throw new UnsupportedOperationException();
             }
-            fbxNode.skeleton = FbxLimbNode.createSkeleton(fbxNode);
-            System.out.println("created skeleton: " + fbxNode.skeleton);
+//            fbxNode.skeleton = FbxLimbNode.createSkeleton(fbxNode);
+//            System.out.println("created skeleton: " + fbxNode.skeleton);
         }
     }
     
@@ -518,19 +519,19 @@ public class FbxNode extends FbxObject<Spatial> {
             }
         }
         
-        if (fbxNode.skeleton != null) { 
-            jmeSpatial.addControl(new AnimControl(fbxNode.skeleton));
-            jmeSpatial.addControl(new SkeletonControl(fbxNode.skeleton));
-            
-            SkeletonDebugger sd = new SkeletonDebugger("debug", fbxNode.skeleton);
-            Material mat = new Material(fbxNode.assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
-            mat.getAdditionalRenderState().setWireframe(true);
-            mat.getAdditionalRenderState().setDepthTest(false);
-            mat.setColor("Color", ColorRGBA.Green);
-            sd.setMaterial(mat);
-            
-            ((Node)jmeSpatial).attachChild(sd);
-        }
+//        if (fbxNode.skeleton != null) { 
+//            jmeSpatial.addControl(new AnimControl(fbxNode.skeleton));
+//            jmeSpatial.addControl(new SkeletonControl(fbxNode.skeleton));
+//            
+//            SkeletonDebugger sd = new SkeletonDebugger("debug", fbxNode.skeleton);
+//            Material mat = new Material(fbxNode.assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+//            mat.getAdditionalRenderState().setWireframe(true);
+//            mat.getAdditionalRenderState().setDepthTest(false);
+//            mat.setColor("Color", ColorRGBA.Green);
+//            sd.setMaterial(mat);
+//            
+//            ((Node)jmeSpatial).attachChild(sd);
+//        }
         
         return jmeSpatial;
     }
@@ -543,10 +544,18 @@ public class FbxNode extends FbxObject<Spatial> {
 //        return limb;
 //    }
     
-    public Skeleton getJmeSkeleton() {
+//    public Skeleton getJmeSkeleton() {
+//        return skeleton;
+//    }
+    
+    public FbxSkeleton getFbxSkeleton() {
         return skeleton;
     }
     
+    public void setFbxSkeleton(FbxSkeleton skeleton) {
+        this.skeleton = skeleton;
+    }
+    
     public List<FbxNode> getChildren() { 
         return children;
     }