public ColladaMeshOud(ColladaModelOud parentModel) { model = parentModel; game = model.Game; }
public void LoadSkinData(XmlNode colladaFile, XmlNode meshNode) { XmlNode library_controllers = XmlHelper.GetChildNode(colladaFile, "library_controllers"); if (library_controllers == null) { return; } XmlNode skinNode = null; foreach (XmlNode controller in library_controllers) { if (controller.Name != "controller") { continue; } skinNode = XmlHelper.GetChildNode(controller, "skin"); if (skinNode == null) { continue; } if (XmlHelper.GetXmlAttribute(skinNode, "source").Substring(1) == Name) { break; } else { skinNode = null; continue; } } if (skinNode == null) { return; } // Load helper matrixes (bind shape and all bind poses matrices) // We only support 1 skinning, so just load the first skin node! /*XmlNode skinNode = XmlHelper.GetChildNode( * XmlHelper.GetChildNode( * XmlHelper.GetChildNode( colladaFile, "library_controllers" ), * "controller" ), "skin" );*/ objectMatrix = ColladaModelOud.LoadColladaMatrix( StringHelper.ConvertStringToFloatArray( XmlHelper.GetChildNode(skinNode, "bind_shape_matrix").InnerText), 0); // Get the order of the bones used in collada (can be different than ours) int[] boneArrayOrder = new int[model.bones.Count]; int[] invBoneArrayOrder = new int[model.bones.Count]; string boneNameArray = XmlHelper.GetChildNode(skinNode, "Name_array").InnerText; int arrayIndex = 0; foreach (string boneName in boneNameArray.Split(' ')) { boneArrayOrder[arrayIndex] = -1; foreach (ColladaBone bone in model.bones) { if (bone.sid == boneName) { boneArrayOrder[arrayIndex] = bone.num; invBoneArrayOrder[bone.num] = arrayIndex; break; } // foreach } if (boneArrayOrder[arrayIndex] == -1) { throw new InvalidOperationException( "Unable to find boneName=" + boneName + " in our bones array for skinning!"); } arrayIndex++; } // foreach // // Load weights float[] weights = null; foreach (XmlNode sourceNode in skinNode) { // Get all inv bone skin matrices if (sourceNode.Name == "source" && XmlHelper.GetXmlAttribute(sourceNode, "id").Contains("bind_poses")) { // Get inner float array float[] mat = StringHelper.ConvertStringToFloatArray( XmlHelper.GetChildNode(sourceNode, "float_array").InnerText); for (int boneNum = 0; boneNum < model.bones.Count; boneNum++) { if (mat.Length / 16 > boneNum) { model.bones[boneArrayOrder[boneNum]].invBoneSkinMatrix = ColladaModelOud.LoadColladaMatrix(mat, boneNum * 16); } // for if } } // if // Get all weights if (sourceNode.Name == "source" && XmlHelper.GetXmlAttribute(sourceNode, "id").Contains("skin-weights")) { // Get inner float array weights = StringHelper.ConvertStringToFloatArray( XmlHelper.GetChildNode(sourceNode, "float_array").InnerText); } // if } // foreach if (weights == null) { throw new InvalidOperationException( "No weights were found in our skin, unable to continue!"); } // // Prepare weights and joint indices, we only want the top 3! // Helper to access the bones (first index) and weights (second index). // If we got more than 2 indices for an entry here, there are multiple // weights used (usually 1 to 3, if more, we only use the strongest). XmlNode vertexWeightsNode = XmlHelper.GetChildNode(skinNode, "vertex_weights"); int[] vcountArray = StringHelper.ConvertStringToIntArray( XmlHelper.GetChildNode(skinNode, "vcount").InnerText); int[] vArray = StringHelper.ConvertStringToIntArray( XmlHelper.GetChildNode(skinNode, "v").InnerText); // Build vertexSkinJoints and vertexSkinWeights for easier access. int vArrayIndex = 0; for (int num = 0; num < vcountArray.Length; num++) { int vcount = vcountArray[num]; List <int> jointIndices = new List <int>(); List <int> weightIndices = new List <int>(); for (int i = 0; i < vcount; i++) { // Make sure we convert the internal number to our bone numbers! jointIndices.Add(boneArrayOrder[vArray[vArrayIndex]]); weightIndices.Add(vArray[vArrayIndex + 1]); vArrayIndex += 2; } // for // If we got less than 3 values, add until we have enough, // this makes the computation easier below while (jointIndices.Count < 3) { jointIndices.Add(0); } while (weightIndices.Count < 3) { weightIndices.Add(-1); } // Find out top 3 weights float[] weightValues = new float[weightIndices.Count]; int[] bestWeights = { 0, 1, 2 }; for (int i = 0; i < weightIndices.Count; i++) { // Use weight of zero for invalid indices. if (weightIndices[i] < 0 || weightValues[i] >= weights.Length) { weightValues[i] = 0; } else { weightValues[i] = weights[weightIndices[i]]; } // Got 4 or more weights? Then just select the top 3! if (i >= 3) { float lowestWeight = 1.0f; int lowestWeightOverride = 2; for (int b = 0; b < bestWeights.Length; b++) { if (lowestWeight > weightValues[bestWeights[b]]) { lowestWeight = weightValues[bestWeights[b]]; lowestWeightOverride = b; } // for if } // Replace lowest weight bestWeights[lowestWeightOverride] = i; } // if } // for // Now build 2 vectors from the best weights Vector3 boneIndicesVec = new Vector3( jointIndices[bestWeights[0]], jointIndices[bestWeights[1]], jointIndices[bestWeights[2]]); Vector3 weightsVec = new Vector3( weightValues[bestWeights[0]], weightValues[bestWeights[1]], weightValues[bestWeights[2]]); // Renormalize weight, important if we got more entries before // and always good to do! float totalWeights = weightsVec.X + weightsVec.Y + weightsVec.Z; if (totalWeights == 0) { weightsVec.X = 1.0f; } else { weightsVec.X /= totalWeights; weightsVec.Y /= totalWeights; weightsVec.Z /= totalWeights; } // else vertexSkinJoints.Add(boneIndicesVec); vertexSkinWeights.Add(weightsVec); } // for // }
public ColladaTextureOud(ColladaModelOud nModel) { game = nModel.Game; }