private static SMVertex GetSMVertexFromTriangle(MilkShape milkShape, List <MilkShapeBoneMap> milkShapeBoneMap, ms3d_triangle_t t, int triangleVertex) { // Only focusing on one of the three triangle vertices var triVertIdx = t.VertexIndices[triangleVertex]; return(new SMVertex { // Get position of vertex Position = milkShape.Vertices[triVertIdx].Position, // Get normal of vertex (stored with triangle in Milkshape for some reason) Normal = t.VertexNormals[triangleVertex], // Texture coordinate needs "reversal" since I "reversed" it earlier // Also the (unused?) Z coordinate always appears to reflect the vertex Z, although // I don't know if that's a requirement or a quirk, but either way... TexCoord = new Vector3(t.TextureCoordinates[triangleVertex].X, 1.0f - t.TextureCoordinates[triangleVertex].Y, milkShape.Vertices[triVertIdx].Position.Z), // This uses the bone map just in case the MilkShape indexes don't line up with // the intended indexes... BoneIndices = milkShape.Vertices[triVertIdx].BoneIdsAndWeights .Where(biw => biw.BoneId != -1) .Select(biw => milkShapeBoneMap.Where(bm => bm.MilkShapeJointIndex == biw.BoneId).Single().SMBoneIndex) .ToArray(), // Finally the MilkShape weights are stored as 0-100 byte-sized values, and we // must convert back (granted with loss) Weights = milkShape.Vertices[triVertIdx].BoneIdsAndWeights .Where(biw => biw.BoneId != -1) .Select(biw => biw.Weight / 100.0f).ToArray() }); }
// Gets or generates an SMVertex for a vertex on a MilkShape triangle private static ushort GetLocalVertexForMSTriangleVertex(List <MilkShapeTempVertex> milkShapeTempVertices, MilkShape milkShape, List <MilkShapeBoneMap> milkShapeBoneMap, ms3d_triangle_t t, int triangleVertex) { // This will provide the "close enough" rating of texture coordinates // to decide that a vertex with the same MilkShape index as well as // "close enough" texture coordinates is the same overall vertex. const float texCoordEpsilon = 1.0f / 128.0f; // This is assuming that we're dealing with textures 128x128 and under, which is probably true // Get the texture coordinates used by this vertex of the triangle, // as it will be part of the consideration of "sameness" of other vertices var triangleVertexTexCoord = t.TextureCoordinates[triangleVertex]; // The primary consideration is MilkShape's own vertex index var triangleVertexIndex = t.VertexIndices[triangleVertex]; var resultVertex = milkShapeTempVertices .Where(tv => // Must come from same vertex in MilkShape's pool... tv.MilkShapeVertexIndex == triangleVertexIndex && // ... and be "close enough" with the texture coordinates Math.Abs(triangleVertexTexCoord.X - tv.SMVertex.TexCoord.X) < texCoordEpsilon && Math.Abs((1.0f - triangleVertexTexCoord.Y) - tv.SMVertex.TexCoord.Y) < texCoordEpsilon ).SingleOrDefault(); if (resultVertex == null) { // If we don't have one quite like this, then we need to create it! resultVertex = new MilkShapeTempVertex { MilkShapeVertexIndex = triangleVertexIndex, MeshLocalVertexIndex = milkShapeTempVertices.Count, SMVertex = GetSMVertexFromTriangle(milkShape, milkShapeBoneMap, t, triangleVertex) }; milkShapeTempVertices.Add(resultVertex); } return((ushort)resultVertex.MeshLocalVertexIndex); }