public static StringsToIntegers ( String s ) : List |
||
s | String | |
return | List |
private void ImportFaces() { foreach (var item in Mesh.Items) { if (item is triangles) { var tris = item as triangles; TriangleCount = (int)tris.count; Inputs = tris.input; Indices = ColladaHelpers.StringsToIntegers(tris.p); } else if (item is polylist) { var plist = item as polylist; TriangleCount = (int)plist.count; Inputs = plist.input; Indices = ColladaHelpers.StringsToIntegers(plist.p); var vertexCounts = ColladaHelpers.StringsToIntegers(plist.vcount); foreach (var count in vertexCounts) { if (count != 3) { throw new ParsingException("Non-triangle found in COLLADA polylist. Make sure that all geometries are triangulated."); } } } else if (item is lines) { throw new ParsingException("Lines found in input geometry. Make sure that all geometries are triangulated."); } } if (Indices == null || Inputs == null) { throw new ParsingException("No valid triangle source found, expected <triangles> or <polylist>"); } InputOffsetCount = 0; foreach (var input in Inputs) { if ((int)input.offset >= InputOffsetCount) { InputOffsetCount = (int)input.offset + 1; } } if (Indices.Count % (InputOffsetCount * 3) != 0 || Indices.Count / InputOffsetCount / 3 != TriangleCount) { throw new ParsingException("Triangle input stride / vertex count mismatch."); } }
private void ImportSkin(Root root, skin skin) { if (skin.source1[0] != '#') { throw new ParsingException("Only ID references are supported for skin geometries"); } Mesh mesh = null; if (!ColladaGeometries.TryGetValue(skin.source1.Substring(1), out mesh)) { throw new ParsingException("Skin references nonexistent mesh: " + skin.source1); } if (!mesh.VertexFormat.HasBoneWeights) { var msg = String.Format("Tried to apply skin to mesh ({0}) with non-skinned vertices", mesh.Name); throw new ParsingException(msg); } var sources = new Dictionary <String, ColladaSource>(); foreach (var source in skin.source) { var src = ColladaSource.FromCollada(source); sources.Add(src.id, src); } List <Bone> joints = null; List <Matrix4> invBindMatrices = null; foreach (var input in skin.joints.input) { if (input.source[0] != '#') { throw new ParsingException("Only ID references are supported for joint input sources"); } ColladaSource inputSource = null; if (!sources.TryGetValue(input.source.Substring(1), out inputSource)) { throw new ParsingException("Joint input source does not exist: " + input.source); } if (input.semantic == "JOINT") { List <string> jointNames = inputSource.NameParams.Values.SingleOrDefault(); if (jointNames == null) { throw new ParsingException("Joint input source 'JOINT' must contain array of names."); } var skeleton = root.Skeletons[0]; joints = new List <Bone>(); foreach (var name in jointNames) { Bone bone = null; var lookupName = name.Replace("_x0020_", " "); if (!skeleton.BonesBySID.TryGetValue(lookupName, out bone)) { throw new ParsingException("Joint name list references nonexistent bone: " + lookupName); } joints.Add(bone); } } else if (input.semantic == "INV_BIND_MATRIX") { invBindMatrices = inputSource.MatrixParams.Values.SingleOrDefault(); if (invBindMatrices == null) { throw new ParsingException("Joint input source 'INV_BIND_MATRIX' must contain a single array of matrices."); } } else { throw new ParsingException("Unsupported joint semantic: " + input.semantic); } } if (joints == null) { throw new ParsingException("Required joint input semantic missing: JOINT"); } if (invBindMatrices == null) { throw new ParsingException("Required joint input semantic missing: INV_BIND_MATRIX"); } var influenceCounts = ColladaHelpers.StringsToIntegers(skin.vertex_weights.vcount); var influences = ColladaHelpers.StringsToIntegers(skin.vertex_weights.v); foreach (var count in influenceCounts) { if (count > 4) { throw new ParsingException("GR2 only supports at most 4 vertex influences"); } } // TODO if (influenceCounts.Count != mesh.OriginalToConsolidatedVertexIndexMap.Count) { Utils.Warn(String.Format("Vertex influence count ({0}) differs from vertex count ({1})", influenceCounts.Count, mesh.OriginalToConsolidatedVertexIndexMap.Count)); } List <Single> weights = null; int jointInputIndex = -1, weightInputIndex = -1; foreach (var input in skin.vertex_weights.input) { if (input.semantic == "JOINT") { jointInputIndex = (int)input.offset; } else if (input.semantic == "WEIGHT") { weightInputIndex = (int)input.offset; if (input.source[0] != '#') { throw new ParsingException("Only ID references are supported for weight input sources"); } ColladaSource inputSource = null; if (!sources.TryGetValue(input.source.Substring(1), out inputSource)) { throw new ParsingException("Weight input source does not exist: " + input.source); } if (!inputSource.FloatParams.TryGetValue("WEIGHT", out weights)) { weights = inputSource.FloatParams.Values.SingleOrDefault(); } if (weights == null) { throw new ParsingException("Weight input source " + input.source + " must have WEIGHT float attribute"); } } else { throw new ParsingException("Unsupported skin input semantic: " + input.semantic); } } if (jointInputIndex == -1) { throw new ParsingException("Required vertex weight input semantic missing: JOINT"); } if (weightInputIndex == -1) { throw new ParsingException("Required vertex weight input semantic missing: WEIGHT"); } // Remove bones that are not actually influenced from the binding list var boundBones = new HashSet <Bone>(); int offset = 0; int stride = skin.vertex_weights.input.Length; while (offset < influences.Count) { var jointIndex = influences[offset + jointInputIndex]; var weightIndex = influences[offset + weightInputIndex]; var joint = joints[jointIndex]; var weight = weights[weightIndex]; if (!boundBones.Contains(joint)) { boundBones.Add(joint); } offset += stride; } if (boundBones.Count > 127) { throw new ParsingException("D:OS supports at most 127 bound bones per mesh."); } mesh.BoneBindings = new List <BoneBinding>(); var boneToIndexMaps = new Dictionary <Bone, int>(); for (var i = 0; i < joints.Count; i++) { if (boundBones.Contains(joints[i])) { // Collada allows one inverse bind matrix for each skin, however Granny // only has one matrix for one bone, even if said bone is used from multiple meshes. // Hopefully the Collada ones are all equal ... var iwt = invBindMatrices[i]; // iwt.Transpose(); joints[i].InverseWorldTransform = new float[] { iwt[0, 0], iwt[1, 0], iwt[2, 0], iwt[3, 0], iwt[0, 1], iwt[1, 1], iwt[2, 1], iwt[3, 1], iwt[0, 2], iwt[1, 2], iwt[2, 2], iwt[3, 2], iwt[0, 3], iwt[1, 3], iwt[2, 3], iwt[3, 3] }; // Bind all bones that affect vertices to the mesh, so we can reference them // later from the vertexes BoneIndices. var binding = new BoneBinding(); binding.BoneName = joints[i].Name; // TODO // Use small bounding box values, as it interferes with object placement // in D:OS 2 (after the Gift Bag 2 update) binding.OBBMin = new float[] { -0.1f, -0.1f, -0.1f }; binding.OBBMax = new float[] { 0.1f, 0.1f, 0.1f }; mesh.BoneBindings.Add(binding); boneToIndexMaps.Add(joints[i], boneToIndexMaps.Count); } } offset = 0; for (var vertexIndex = 0; vertexIndex < influenceCounts.Count; vertexIndex++) { var influenceCount = influenceCounts[vertexIndex]; float influenceSum = 0.0f; for (var i = 0; i < influenceCount; i++) { var weightIndex = influences[offset + i * stride + weightInputIndex]; influenceSum += weights[weightIndex]; } for (var i = 0; i < influenceCount; i++) { var jointIndex = influences[offset + jointInputIndex]; var weightIndex = influences[offset + weightInputIndex]; var joint = joints[jointIndex]; var weight = weights[weightIndex] / influenceSum; // Not all vertices are actually used in triangles, we may have unused verts in the // source list (though this is rare) which won't show up in the consolidated vertex map. if (mesh.OriginalToConsolidatedVertexIndexMap.TryGetValue(vertexIndex, out List <int> consolidatedIndices)) { foreach (var consolidatedIndex in consolidatedIndices) { var vertex = mesh.PrimaryVertexData.Vertices[consolidatedIndex]; vertex.AddInfluence((byte)boneToIndexMaps[joint], weight); } } offset += stride; } } foreach (var vertex in mesh.PrimaryVertexData.Vertices) { vertex.FinalizeInfluences(); } // Warn if we have vertices that are not influenced by any bone int notInfluenced = 0; foreach (var vertex in mesh.PrimaryVertexData.Vertices) { if (vertex.BoneWeights[0] == 0) { notInfluenced++; } } if (notInfluenced > 0) { Utils.Warn(String.Format("{0} vertices are not influenced by any bone", notInfluenced)); } if (skin.bind_shape_matrix != null) { var bindShapeFloats = skin.bind_shape_matrix.Trim().Split(new char[] { ' ' }).Select(s => Single.Parse(s)).ToArray(); var bindShapeMat = ColladaHelpers.FloatsToMatrix(bindShapeFloats); bindShapeMat.Transpose(); // Deform geometries that were affected by our bind shape matrix mesh.PrimaryVertexData.Transform(bindShapeMat); } if (Options.RecalculateOBBs) { UpdateOBBs(root.Skeletons.Single(), mesh); } }