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!