Explanation about ColladaImporter is needed

I'm getting model from COLLADA file which is exported from Feeling ColladaMax v3.05B.

For previous version of ColladaMax, ColladaImporter works well for importing bone/skin/animations.

But for v3.05B, skins are not imported correctly.

The reason was that node's id and sid is not the same for the newer version.



v3.05B


 <node id="Bip01_Pelvis-node" name="Bip01_Pelvis" sid="Bone1" type="JOINT">



previous version


<node id="Bip01_Pelvis-node" name="Bip01_Pelvis" sid="Bip01_Pelvis-node" type="JOINT">



So I made some fix using sid to id mapping.
It works well for both old & new versions.
(I have no idea this approach is compliant to COLLADA spec.)


Index: src/com/jmex/model/collada/ColladaImporter.java
===================================================================
--- src/com/jmex/model/collada/ColladaImporter.java   (revision 4059)
+++ src/com/jmex/model/collada/ColladaImporter.java   (working copy)
@@ -161,6 +161,8 @@
 import com.jmex.model.collada.schema.trianglesType;
 import com.jmex.model.collada.schema.vertex_weightsType;
 import com.jmex.model.collada.schema.visual_sceneType;
+import com.jmex.xml.types.SchemaID;
+import com.jmex.xml.types.SchemaNCName;
 
 /**
  * <code>ColladaNode</code> provides a mechanism to parse and load a COLLADA
@@ -194,6 +196,7 @@
     public static OptimizeCallback optimizeCallBack = null;
 
     private Map<String, Object> resourceLibrary;
+    private Map<String, String> sid2id;
     private ArrayList<String> controllerNames;
     private ArrayList<String> uvControllerNames;
     private ArrayList<String> skinNodeNames;
@@ -277,10 +280,12 @@
     private void load(InputStream source) {
         model = new Node(name);
         resourceLibrary = new HashMap<String, Object>();
+        sid2id = new HashMap<String, String>();
         subMaterialLibrary = new HashMap<TriMesh, String>();
         collada_schema_1_4_1Doc doc = new collada_schema_1_4_1Doc();
         try {
             COLLADAType root = new COLLADAType(doc.load(source));
+            generateSid2IdMap(root);
             logger.info("Version: " + root.getversion().getValue());
             processCollada(root);
         } catch (Exception ex) {
@@ -289,7 +294,35 @@
         }
     }
 
-    /**
+
+   private void generateSid2IdMap(COLLADAType root) {
+      try {
+         library_visual_scenesType scenes = root.getlibrary_visual_scenes();
+         if (scenes == null)
+            return;
+         for (int i = 0; i < scenes.getvisual_sceneCount(); i++) {
+            visual_sceneType scene = scenes.getvisual_sceneAt(i);
+            for (int j = 0; j < scene.getnodeCount(); j++) {
+               generateSid2IdMap(scene.getnodeAt(j));
+            }
+            
+         }
+      } catch (Exception e) {
+      }
+   }
+
+   private void generateSid2IdMap(nodeType2 node) throws Exception {
+      if (node.hasid() && node.hassid()) {
+         SchemaID id = node.getid();
+         SchemaNCName sid = node.getsid();
+         sid2id.put(sid.toString(), id.toString());
+      }
+      for (int i = 0; i < node.getnodeCount(); i++) {
+         generateSid2IdMap(node.getnodeAt(i));
+      }
+   }
+
+   /**
      * returns the names of the controllers that affect this imported model.
      *
      * @return the list of string values for each controller name.
@@ -2729,14 +2762,16 @@
                         MeshVertPair bvp = target.get(j);
                         // Bone b =
                         // (Bone)resourceLibrary.get(boneIds[idIndex]);
+                        String id = boneIds[idIndex];
                         skinNode.addBoneInfluence(bvp.mesh, bvp.index,
-                                boneIds[idIndex], weight);
+                                id, weight);
                     }
                 }
             }
             count++;
         }
     }
+   
 
     /**
      * processControllerSource will process the source types that define how a
@@ -2755,34 +2790,34 @@
         if (key.equalsIgnoreCase("IDREF")) {
             if (source.hasIDREF_array()) {
                 IDREF_arrayType idrefs = source.getIDREF_array();
-                Bone[] bones = new Bone[idrefs.getcount().intValue()];
-                boneIds = new String[bones.length];
+                final int size = idrefs.getcount().intValue();
+                boneIds = new String[size];
                 StringTokenizer st = new StringTokenizer(idrefs.getValue()
                         .toString());
-                for (int i = 0; i < bones.length; i++) {
+                for (int i = 0; i < size; i++) {
                     // this skin has a number of bones assigned to it.
                     // Create a Bone for each entry.
-                    bones[i] = new Bone(st.nextToken());
-                    boneIds[i] = bones[i].getName();
-                    put(boneIds[i], bones[i]);
+                   boneIds[i] = st.nextToken();
+                   Bone bone = new Bone(boneIds[i]);
+                    put(boneIds[i], bone);
                 }
                 put(source.getid().toString(), boneIds);
             }
         } else if (key.equalsIgnoreCase("Name")) {
             if (source.hasName_array()) {
                 Name_arrayType names = source.getName_array();
-                Bone[] bones = new Bone[names.getcount().intValue()];
-                boneIds = new String[bones.length];
+                final int size = names.getcount().intValue();
+                boneIds = new String[size];
                 StringTokenizer st = new StringTokenizer(names.getValue()
                         .toString());
-                for (int i = 0; i < bones.length; i++) {
+                for (int i = 0; i < size; i++) {
                     // this skin has a number of bones assigned to it.
                     // Create a Bone for each entry.
-                    bones[i] = new Bone(st.nextToken());
-                    boneIds[i] = bones[i].getName();
-                    put(boneIds[i], bones[i]);
-                    put(source.getid().toString(), boneIds);
+                   boneIds[i] = getId(st.nextToken());
+                    Bone bone = new Bone(boneIds[i]);
+                    put(boneIds[i], bone);
                 }
+                put(source.getid().toString(), boneIds);
             }
         } else if (key.equalsIgnoreCase("float4x4")) {
             StringTokenizer st = new StringTokenizer(source.getfloat_array()
@@ -2811,6 +2846,14 @@
         }
     }
 
+   
+    private String getId(String sid) {
+       String id = sid2id.get(sid);
+       if (id != null)
+          return id;
+       return sid;
+    }
+
     /**
      * processBindShapeMatrix sets the initial transform of the skinned mesh.
      * The 4x4 matrix is converted to a 3x3 matrix and a vector, then passed to
@@ -3868,16 +3911,19 @@
         Node child = null;
         if (xmlNode.hastype() && "JOINT".equals(xmlNode.gettype().toString())
                 && (xmlNode.hassid() || xmlNode.hasid())) {
-            String key = (xmlNode.hassid() ? xmlNode.getsid() : xmlNode.getid())
-                    .toString();
+//            String key = (xmlNode.hassid() ? xmlNode.getsid() : xmlNode.getid())
+//                    .toString();
+            String key = getId(xmlNode.getid().toString());
             child = (Bone) resourceLibrary.get(key);
             if (child == null) {
-                child = new Bone(key);
+                child = new Bone(xmlNode.getid().toString());
                 put(key, child);
                 if (!squelch) {
                     logger.warning("Bone " + key
                             + " is not attached to any vertices.");
                 }
+            } else {
+               child.setName(xmlNode.getid().toString());
             }
             if (!(parent instanceof Bone)) {
                 if (skeletonNames == null) {
@@ -4085,7 +4131,7 @@
         if (controller.hasskeleton()) {
             if (controller.getskeletonCount() > 1) {
                 if (!squelch) {
-                    logger.warning("Controller has more than one skeleton.");
+                    logger.warning("instance_controller "+ controller.geturl().toString() +" has more than one skeleton.");
                 }
             }
             String url = controller.getskeleton().getValue();



And I have some other problems now using ColladaImporter.
Extra-bone added skin is twisted.
Comparing model data and imported skin source,
I doubt the imported skin data (BoneInfluences) seems to be incorrect.

I would like to know about skin building process in ColladaImporter.
VertMap, ColladaImporter.MeshVertPair is so confusing to me.
Especially, I can't understand why calling
    new MeshVertPair(triangleIndex, j)
instead of
    new MeshVertPair(triangleIndex, vertKey)

in source below (ColladaImporter.processTriMesh)


StringTokenizer st = new StringTokenizer(tri.getp()
                            .getValue());
                    int vertCount = tri.getcount().intValue() * 3;
                    FloatBuffer vertBuffer = BufferUtils
                            .createVector3Buffer(vertCount);
                    triMesh.setVertexCount(vertCount);
                    for (int j = 0; j < vertCount; j++) {
                        // need to store the index in p to what j is for later
                        // processing the index to the vert for bones
                        int vertKey = Integer.parseInt(st.nextToken());
                        ArrayList<MeshVertPair> storage = vertMap.get(Integer
                                .valueOf(vertKey));
                        if (storage == null) {
                            storage = new ArrayList<MeshVertPair>();
                            storage.add(new MeshVertPair(triangleIndex, j));
                            vertMap.put(Integer.valueOf(vertKey), storage);
                        } else {
                            storage.add(new MeshVertPair(triangleIndex, j));
                        }
                        BufferUtils.setInBuffer(v[vertKey], vertBuffer, j);
                        for (int k = 0; k < maxOffset; k++) {
                            st.nextToken();
                        }
                    }



Any help would be greatly appreciated.
Have a nice day!

Solved.  :slight_smile:

Extra-bone problem was caused by MAX.