public override void writer(MFileObject file, string optionsString, FileAccessMode mode) { if (mode == FileAccessMode.kExportActiveAccessMode) { string sknPath = file.expandedFullName; string sklPath = Path.ChangeExtension(sknPath, ".skl"); SKLFile skl = new SKLFile(true); SKNFile skn = new SKNFile(skl); skl.Write(sklPath); skn.Write(sknPath); } else { MGlobal.displayError("SKNExporter - Wrong File Access Mode: " + mode); } }
public override void reader(MFileObject file, string optionsString, FileAccessMode mode) { if (mode == FileAccessMode.kImportAccessMode) { string pathWithoutExtension = file.expandedFullName.Substring(0, file.expandedFullName.LastIndexOf('.')); string name = Path.GetFileNameWithoutExtension(file.expandedFullName).Replace('.', '_'); SKNFile skn = new SKNFile(file.expandedFullName); SKLFile skl = new SKLFile(pathWithoutExtension + ".skl"); MGlobal.displayInfo("SKNImporter:reader - SKN Vertex Count: " + skn.Vertices.Count); MGlobal.displayInfo("SKNImporter:reader - SKN Index Count: " + skn.Indices.Count); MGlobal.displayInfo("SKNImporter:reader - SKN Submesh Count: " + skn.Submeshes.Count); skl.Load(); skn.Load(name, skl); } else { throw new ArgumentException("SKNImporter:reader - Invalid File Access Mode: " + mode, "mode"); } }
/// <summary> /// Loads data from SKN and SKL files into OpenGL. /// </summary> /// <param name="skn">The .skn data.</param> /// <param name="skl">The .skl data.</param> /// <returns></returns> public bool Create(SKNFile skn, SKLFile skl, Dictionary <String, ANMFile> anms, Logger logger) { bool result = true; // This function converts the handedness of the DirectX style input data // into the handedness OpenGL expects. // So, vector inputs have their Z value negated and quaternion inputs have their // Z and W values negated. // Vertex Data List <float> vertexPositions = new List <float>(); List <float> vertexNormals = new List <float>(); List <float> vertexTextureCoordinates = new List <float>(); List <float> vertexBoneIndices = new List <float>(); List <float> vertexBoneWeights = new List <float>(); List <uint> indices = new List <uint>(); // Animation data. List <OpenTK.Quaternion> boneOrientations = new List <OpenTK.Quaternion>(); List <OpenTK.Vector3> bonePositions = new List <OpenTK.Vector3>(); List <float> boneScales = new List <float>(); List <int> boneParents = new List <int>(); List <String> boneNames = new List <String>(); // Bones are not always in order between the ANM and SKL files. Dictionary <String, int> boneNameToID = new Dictionary <String, int>(); Dictionary <int, String> boneIDToName = new Dictionary <int, String>(); for (int i = 0; i < skn.numVertices; ++i) { // Position Information vertexPositions.Add(skn.vertices[i].position[0]); vertexPositions.Add(skn.vertices[i].position[1]); vertexPositions.Add(-skn.vertices[i].position[2]); // Normal Information vertexNormals.Add(skn.vertices[i].normal[0]); vertexNormals.Add(skn.vertices[i].normal[1]); vertexNormals.Add(-skn.vertices[i].normal[2]); // Tex Coords Information vertexTextureCoordinates.Add(skn.vertices[i].texCoords[0]); vertexTextureCoordinates.Add(skn.vertices[i].texCoords[1]); // Bone Index Information for (int j = 0; j < SKNVertex.BONE_INDEX_SIZE; ++j) { vertexBoneIndices.Add(skn.vertices[i].boneIndex[j]); } // Bone Weight Information vertexBoneWeights.Add(skn.vertices[i].weights[0]); vertexBoneWeights.Add(skn.vertices[i].weights[1]); vertexBoneWeights.Add(skn.vertices[i].weights[2]); vertexBoneWeights.Add(skn.vertices[i].weights[3]); } // Animation data for (int i = 0; i < skl.numBones; ++i) { Quaternion orientation = Quaternion.Identity; if (skl.version == 0) { // Version 0 SKLs contain a quaternion. orientation.X = skl.bones[i].orientation[0]; orientation.Y = skl.bones[i].orientation[1]; orientation.Z = -skl.bones[i].orientation[2]; orientation.W = -skl.bones[i].orientation[3]; } else { // Other SKLs contain a rotation matrix. // Create a matrix from the orientation values. Matrix4 transform = Matrix4.Identity; transform.M11 = skl.bones[i].orientation[0]; transform.M21 = skl.bones[i].orientation[1]; transform.M31 = skl.bones[i].orientation[2]; transform.M12 = skl.bones[i].orientation[4]; transform.M22 = skl.bones[i].orientation[5]; transform.M32 = skl.bones[i].orientation[6]; transform.M13 = skl.bones[i].orientation[8]; transform.M23 = skl.bones[i].orientation[9]; transform.M33 = skl.bones[i].orientation[10]; // Convert the matrix to a quaternion. orientation = OpenTKExtras.Matrix4.CreateQuatFromMatrix(transform); orientation.Z = -orientation.Z; orientation.W = -orientation.W; } boneOrientations.Add(orientation); // Create a vector from the position values. Vector3 position = Vector3.Zero; position.X = skl.bones[i].position[0]; position.Y = skl.bones[i].position[1]; position.Z = -skl.bones[i].position[2]; bonePositions.Add(position); boneNames.Add(skl.bones[i].name); boneNameToID[skl.bones[i].name] = i; boneIDToName[i] = skl.bones[i].name; boneScales.Add(skl.bones[i].scale); boneParents.Add(skl.bones[i].parentID); } // // Version 0 SKL files are similar to the animation files. // The bone positions and orientations are relative to their parent. // So, we need to compute their absolute location by hand. // if (skl.version == 0) { // // This algorithm is a little confusing since it's indexing identical data from // the SKL file and the local variable List<>s. The indexing scheme works because // the List<>s are created in the same order as the data in the SKL files. // for (int i = 0; i < skl.numBones; ++i) { // Only update non root bones. if (skl.bones[i].parentID != -1) { // Determine the parent bone. int parentBoneID = skl.bones[i].parentID; // Update orientation. // Append quaternions for rotation transform B * A. boneOrientations[i] = boneOrientations[parentBoneID] * boneOrientations[i]; Vector3 localPosition = Vector3.Zero; localPosition.X = skl.bones[i].position[0]; localPosition.Y = skl.bones[i].position[1]; localPosition.Z = skl.bones[i].position[2]; // Update position. bonePositions[i] = bonePositions[parentBoneID] + Vector3.Transform(localPosition, boneOrientations[parentBoneID]); } } } // Depending on the version of the model, the look ups change. if (skl.version == 2 || skl.version == 0) { for (int i = 0; i < vertexBoneIndices.Count; ++i) { // I don't know why things need remapped, but they do. // Sanity if (vertexBoneIndices[i] < skl.boneIDs.Count) { vertexBoneIndices[i] = skl.boneIDs[(int)vertexBoneIndices[i]]; } } } // Add the animations. foreach (var animation in anms) { if (animations.ContainsKey(animation.Key) == false) { // Create the OpenGL animation wrapper. GLAnimation glAnimation = new GLAnimation(); glAnimation.playbackFPS = animation.Value.playbackFPS; glAnimation.numberOfBones = animation.Value.numberOfBones; glAnimation.numberOfFrames = animation.Value.numberOfFrames; // Convert ANMBone to GLBone. foreach (ANMBone bone in animation.Value.bones) { GLBone glBone = new GLBone(); if (animation.Value.version == 4 && skl.boneIDMap.Count > 0) { // Version 4 ANM files contain a hash value to represent the bone ID/name. // We need to use the map from the SKL file to match the ANM bone with the correct // SKL bone. if (skl.boneIDMap.ContainsKey(bone.id)) { int sklID = (int)skl.boneIDMap[bone.id]; glBone.name = boneIDToName[sklID]; } } else { glBone.name = bone.name; } // Convert ANMFrame to Matrix4. foreach (ANMFrame frame in bone.frames) { Matrix4 transform = Matrix4.Identity; Quaternion quat = new Quaternion(frame.orientation[0], frame.orientation[1], -frame.orientation[2], -frame.orientation[3]); transform = Matrix4.Rotate(quat); transform.M41 = frame.position[0]; transform.M42 = frame.position[1]; transform.M43 = -frame.position[2]; glBone.frames.Add(transform); } glAnimation.bones.Add(glBone); } glAnimation.timePerFrame = 1.0f / (float)animation.Value.playbackFPS; // Store the animation. animations.Add(animation.Key, glAnimation); } } // Index Information for (int i = 0; i < skn.numIndices; ++i) { indices.Add((uint)skn.indices[i]); } this.numIndices = indices.Count; // // Compute the final animation transforms. // foreach (var animation in animations) { // This is sort of a mess. // We need to make sure "parent" bones are always updated before their "children". The SKL file contains // bones ordered in this manner. However, ANM files do not always do this. So, we sort the bones in the ANM to match the ordering in // the SKL file. animation.Value.bones.Sort((a, b) => { if (boneNameToID.ContainsKey(a.name) && boneNameToID.ContainsKey(b.name)) { return(boneNameToID[a.name].CompareTo(boneNameToID[b.name])); } else if (boneNameToID.ContainsKey(a.name) == false) { return(1); } else { return(-1); } }); } // Create the binding transform. (The SKL initial transform.) GLAnimation bindingBones = new GLAnimation(); for (int i = 0; i < boneOrientations.Count; ++i) { GLBone bone = new GLBone(); bone.name = boneNames[i]; bone.parent = boneParents[i]; bone.transform = Matrix4.Rotate(boneOrientations[i]); bone.transform.M41 = bonePositions[i].X; bone.transform.M42 = bonePositions[i].Y; bone.transform.M43 = bonePositions[i].Z; bone.transform = Matrix4.Invert(bone.transform); bindingBones.bones.Add(bone); } // Convert animations into absolute space. foreach (var animation in animations) { foreach (var bone in animation.Value.bones) { // Sanity. if (boneNameToID.ContainsKey(bone.name)) { int id = boneNameToID[bone.name]; bone.parent = bindingBones.bones[id].parent; // For each frame... for (int i = 0; i < bone.frames.Count; ++i) { Matrix4 parentTransform = Matrix4.Identity; if (bone.parent >= 0) { if (bone.parent < animation.Value.bones.Count) { GLBone parent = animation.Value.bones[bone.parent]; parentTransform = parent.frames[i]; } } bone.frames[i] = bone.frames[i] * parentTransform; } } } } // Multiply the animation transforms by the binding transform. foreach (var animation in animations) { foreach (var bone in animation.Value.bones) { // Sanity. if (boneNameToID.ContainsKey(bone.name)) { int id = boneNameToID[bone.name]; GLBone bindingBone = bindingBones.bones[id]; for (int i = 0; i < bone.frames.Count; ++i) { bone.frames[i] = bindingBone.transform * bone.frames[i]; } } } } // Create the OpenGL objects. result = Create(vertexPositions, vertexNormals, vertexTextureCoordinates, vertexBoneIndices, vertexBoneWeights, indices, logger); return(result); }
public void Load(string name, SKLFile skl = null) { MIntArray polygonIndexCounts = new MIntArray((uint)this.Indices.Count / 3); MIntArray polygonIndices = new MIntArray((uint)this.Indices.Count); MFloatPointArray vertices = new MFloatPointArray((uint)this.Vertices.Count); MFloatArray arrayU = new MFloatArray((uint)this.Vertices.Count); MFloatArray arrayV = new MFloatArray((uint)this.Vertices.Count); MVectorArray normals = new MVectorArray((uint)this.Vertices.Count); MIntArray normalIndices = new MIntArray((uint)this.Vertices.Count); MFnMesh mesh = new MFnMesh(); MDagPath meshDagPath = new MDagPath(); MDGModifier modifier = new MDGModifier(); MFnSet set = new MFnSet(); for (int i = 0; i < this.Indices.Count / 3; i++) { polygonIndexCounts[i] = 3; } for (int i = 0; i < this.Indices.Count; i++) { polygonIndices[i] = this.Indices[i]; } for (int i = 0; i < this.Vertices.Count; i++) { SKNVertex vertex = this.Vertices[i]; vertices[i] = new MFloatPoint(vertex.Position.X, vertex.Position.Y, vertex.Position.Z); arrayU[i] = vertex.UV.X; arrayV[i] = 1 - vertex.UV.Y; normals[i] = new MVector(vertex.Normal.X, vertex.Normal.Y, vertex.Normal.Z); normalIndices[i] = i; } //Assign mesh data mesh.create(this.Vertices.Count, this.Indices.Count / 3, vertices, polygonIndexCounts, polygonIndices, arrayU, arrayV, MObject.kNullObj); mesh.setVertexNormals(normals, normalIndices); mesh.getPath(meshDagPath); mesh.assignUVs(polygonIndexCounts, polygonIndices); //Set names mesh.setName(name); MFnTransform transformNode = new MFnTransform(mesh.parent(0)); transformNode.setName("transform_" + name); //Get render partition MGlobal.displayInfo("SKNFile:Load - Searching for Render Partition"); MItDependencyNodes itDependencyNodes = new MItDependencyNodes(MFn.Type.kPartition); MFnPartition renderPartition = new MFnPartition(); bool foundRenderPartition = false; for (; !itDependencyNodes.isDone; itDependencyNodes.next()) { renderPartition.setObject(itDependencyNodes.thisNode); MGlobal.displayInfo("SKNFile:Load - Iterating through partition: " + renderPartition.name + " IsRenderPartition: " + renderPartition.isRenderPartition); if (renderPartition.name == "renderPartition" && renderPartition.isRenderPartition) { MGlobal.displayInfo("SKNFile:Load - Found render partition"); foundRenderPartition = true; break; } } //Create Materials for (int i = 0; i < this.Submeshes.Count; i++) { MFnDependencyNode dependencyNode = new MFnDependencyNode(); MFnLambertShader lambertShader = new MFnLambertShader(); SKNSubmesh submesh = this.Submeshes[i]; MObject shader = lambertShader.create(true); lambertShader.setName(submesh.Name); lambertShader.color = MaterialProvider.GetMayaColor(i); MObject shadingEngine = dependencyNode.create("shadingEngine", submesh.Name + "_SG"); MObject materialInfo = dependencyNode.create("materialInfo", submesh.Name + "_MaterialInfo"); if (foundRenderPartition) { MPlug partitionPlug = new MFnDependencyNode(shadingEngine).findPlug("partition"); MPlug setsPlug = MayaHelper.FindFirstNotConnectedElement(renderPartition.findPlug("sets")); modifier.connect(partitionPlug, setsPlug); } else { MGlobal.displayInfo("SKNFile:Load - Couldn't find Render Partition for mesh: " + name + "." + submesh.Name); } MPlug outColorPlug = lambertShader.findPlug("outColor"); MPlug surfaceShaderPlug = new MFnDependencyNode(shadingEngine).findPlug("surfaceShader"); modifier.connect(outColorPlug, surfaceShaderPlug); MPlug messagePlug = new MFnDependencyNode(shadingEngine).findPlug("message"); MPlug shadingGroupPlug = new MFnDependencyNode(materialInfo).findPlug("shadingGroup"); modifier.connect(messagePlug, shadingGroupPlug); modifier.doIt(); MFnSingleIndexedComponent component = new MFnSingleIndexedComponent(); MObject faceComponent = component.create(MFn.Type.kMeshPolygonComponent); MIntArray groupPolygonIndices = new MIntArray(); uint endIndex = (submesh.StartIndex + submesh.IndexCount) / 3; for (uint j = submesh.StartIndex / 3; j < endIndex; j++) { groupPolygonIndices.append((int)j); } component.addElements(groupPolygonIndices); set.setObject(shadingEngine); set.addMember(meshDagPath, faceComponent); } if (skl == null) { mesh.updateSurface(); } else { MFnSkinCluster skinCluster = new MFnSkinCluster(); MSelectionList jointPathsSelectionList = new MSelectionList(); jointPathsSelectionList.add(meshDagPath); for (int i = 0; i < skl.Influences.Count; i++) { short jointIndex = skl.Influences[i]; SKLJoint joint = skl.Joints[jointIndex]; jointPathsSelectionList.add(skl.JointDagPaths[jointIndex]); MGlobal.displayInfo(string.Format("SKNFile:Load:Bind - Added joint [{0}] {1} to binding selection", joint.ID, joint.Name)); } MGlobal.selectCommand(jointPathsSelectionList); MGlobal.executeCommand("skinCluster -mi 4 -tsb -n skinCluster_" + name); MPlug inMeshPlug = mesh.findPlug("inMesh"); MPlugArray inMeshConnections = new MPlugArray(); inMeshPlug.connectedTo(inMeshConnections, true, false); if (inMeshConnections.length == 0) { MGlobal.displayError("SKNFile:Load:Bind - Failed to find the created Skin Cluster"); throw new Exception("SKNFile:Load:Bind - Failed to find the created Skin Cluster"); } MPlug outputGeometryPlug = inMeshConnections[0]; MDagPathArray influencesDagPaths = new MDagPathArray(); skinCluster.setObject(outputGeometryPlug.node); skinCluster.influenceObjects(influencesDagPaths); MIntArray influenceIndices = new MIntArray((uint)skl.Influences.Count); for (int i = 0; i < skl.Influences.Count; i++) { MDagPath influencePath = skl.JointDagPaths[skl.Influences[i]]; for (int j = 0; j < skl.Influences.Count; j++) { if (influencesDagPaths[j].partialPathName == influencePath.partialPathName) { influenceIndices[i] = j; MGlobal.displayInfo("SKNReader:Load:Bind - Added Influence Joint: " + i + " -> " + j); break; } } } MFnSingleIndexedComponent singleIndexedComponent = new MFnSingleIndexedComponent(); MObject vertexComponent = singleIndexedComponent.create(MFn.Type.kMeshVertComponent); MIntArray groupVertexIndices = new MIntArray((uint)this.Vertices.Count); for (int i = 0; i < this.Vertices.Count; i++) { groupVertexIndices[i] = i; } singleIndexedComponent.addElements(groupVertexIndices); MGlobal.executeCommand(string.Format("setAttr {0}.normalizeWeights 0", skinCluster.name)); MDoubleArray weights = new MDoubleArray((uint)(this.Vertices.Count * skl.Influences.Count)); for (int i = 0; i < this.Vertices.Count; i++) { SKNVertex vertex = this.Vertices[i]; for (int j = 0; j < 4; j++) { double weight = vertex.Weights[j]; int influence = vertex.BoneIndices[j]; if (weight != 0) { weights[(i * skl.Influences.Count) + influence] = weight; } } } skinCluster.setWeights(meshDagPath, vertexComponent, influenceIndices, weights, false); MGlobal.executeCommand(string.Format("setAttr {0}.normalizeWeights 1", skinCluster.name)); MGlobal.executeCommand(string.Format("skinPercent -normalize true {0} {1}", skinCluster.name, mesh.name)); mesh.updateSurface(); } }
public SKNFile(SKLFile skl) { Create(skl); }
public void Create(SKLFile skl) { MSelectionList currentSelection = MGlobal.activeSelectionList; MItSelectionList currentSelectionIterator = new MItSelectionList(currentSelection, MFn.Type.kMesh); MDagPath meshDagPath = new MDagPath(); if (currentSelectionIterator.isDone) { MGlobal.displayError("SKNFile:Create - No mesh selected!"); throw new Exception("SKNFile:Create - No mesh selected!"); } else { currentSelectionIterator.getDagPath(meshDagPath); currentSelectionIterator.next(); if (!currentSelectionIterator.isDone) { MGlobal.displayError("SKNFile:Create - More than one mesh selected!"); throw new Exception("SKNFile:Create - More than one mesh selected!"); } } MFnMesh mesh = new MFnMesh(meshDagPath); //Find Skin Cluster MPlug inMeshPlug = mesh.findPlug("inMesh"); MPlugArray inMeshConnections = new MPlugArray(); inMeshPlug.connectedTo(inMeshConnections, true, false); if (inMeshConnections.length == 0) { MGlobal.displayError("SKNFile:Create - Failed to find Skin Cluster!"); throw new Exception("SKNFile:Create - Failed to find Skin Cluster!"); } MPlug outputGeometryPlug = inMeshConnections[0]; MFnSkinCluster skinCluster = new MFnSkinCluster(outputGeometryPlug.node); MDagPathArray influenceDagPaths = new MDagPathArray(); uint influenceCount = skinCluster.influenceObjects(influenceDagPaths); MGlobal.displayInfo("SKNFile:Create - Influence Count: " + influenceCount); //Get SKL Influence Indices MIntArray sklInfluenceIndices = new MIntArray(influenceCount); for (int i = 0; i < influenceCount; i++) { MDagPath jointDagPath = influenceDagPaths[i]; MGlobal.displayInfo(jointDagPath.fullPathName); //Loop through Joint DAG Paths, if we find a math for the influence, write the index for (int j = 0; j < skl.JointDagPaths.Count; j++) { if (jointDagPath.equalEqual(skl.JointDagPaths[j])) { MGlobal.displayInfo("Found coresponding DAG path"); sklInfluenceIndices[i] = j; break; } } } //Add Influence indices to SKL File MIntArray maskInfluenceIndex = new MIntArray(influenceCount); for (int i = 0; i < influenceCount; i++) { maskInfluenceIndex[i] = i; skl.Influences.Add((short)sklInfluenceIndices[i]); } MObjectArray shaders = new MObjectArray(); MIntArray polygonShaderIndices = new MIntArray(); mesh.getConnectedShaders(meshDagPath.isInstanced ? meshDagPath.instanceNumber : 0, shaders, polygonShaderIndices); uint shaderCount = shaders.length; if (shaderCount > 32) //iirc 32 is the limit of how many submeshes there can be for an SKN file { MGlobal.displayError("SKNFile:Create - You've exceeded the maximum limit of 32 shaders"); throw new Exception("SKNFile:Create - You've exceeded the maximum limit of 32 shaders"); } MIntArray vertexShaders = new MIntArray(); ValidateMeshTopology(mesh, meshDagPath, polygonShaderIndices, ref vertexShaders, shaderCount); //Get Weights MFnSingleIndexedComponent vertexIndexedComponent = new MFnSingleIndexedComponent(); MObject vertexComponent = vertexIndexedComponent.create(MFn.Type.kMeshVertComponent); MIntArray groupVertexIndices = new MIntArray((uint)mesh.numVertices); for (int i = 0; i < mesh.numVertices; i++) { groupVertexIndices[i] = i; } vertexIndexedComponent.addElements(groupVertexIndices); MDoubleArray weights = new MDoubleArray(); uint weightsInfluenceCount = 0; skinCluster.getWeights(meshDagPath, vertexComponent, weights, ref weightsInfluenceCount); //Check if vertices don't have more than 4 influences and normalize weights for (int i = 0; i < mesh.numVertices; i++) { int vertexInfluenceCount = 0; double weightSum = 0; for (int j = 0; j < weightsInfluenceCount; j++) { double weight = weights[(int)(i * weightsInfluenceCount) + j]; if (weight != 0) { vertexInfluenceCount++; weightSum += weight; } } if (vertexInfluenceCount > 4) { MGlobal.displayError("SKNFile:Create - Mesh contains a vertex with more than 4 influences"); throw new Exception("SKNFile:Create - Mesh contains a vertex with more than 4 influences"); } //Normalize weights for (int j = 0; j < weightsInfluenceCount; j++) { weights[(int)(i * influenceCount) + j] /= weightSum; } } List <MIntArray> shaderVertexIndices = new List <MIntArray>(); List <List <SKNVertex> > shaderVertices = new List <List <SKNVertex> >(); List <MIntArray> shaderIndices = new List <MIntArray>(); for (int i = 0; i < shaderCount; i++) { shaderVertexIndices.Add(new MIntArray()); shaderVertices.Add(new List <SKNVertex>()); shaderIndices.Add(new MIntArray()); } MItMeshVertex meshVertexIterator = new MItMeshVertex(meshDagPath); for (meshVertexIterator.reset(); !meshVertexIterator.isDone; meshVertexIterator.next()) { int index = meshVertexIterator.index(); int shader = vertexShaders[index]; if (shader == -1) { MGlobal.displayWarning("SKNFile:Create - Mesh contains a vertex with no shader"); continue; } MPoint pointPosition = meshVertexIterator.position(MSpace.Space.kWorld); Vector3 position = new Vector3((float)pointPosition.x, (float)pointPosition.y, (float)pointPosition.z); MVectorArray normals = new MVectorArray(); MIntArray uvIndices = new MIntArray(); Vector3 normal = new Vector3(); byte[] weightIndices = new byte[4]; float[] vertexWeights = new float[4]; meshVertexIterator.getNormals(normals); //Normalize normals for (int i = 0; i < normals.length; i++) { normal.X += (float)normals[i].x; normal.Y += (float)normals[i].y; normal.Z += (float)normals[i].z; } normal.X /= normals.length; normal.Y /= normals.length; normal.Z /= normals.length; //Get Weight Influences and Weights int weightsFound = 0; for (int j = 0; j < weightsInfluenceCount && weightsFound < 4; j++) { double weight = weights[(int)(index * weightsInfluenceCount) + j]; if (weight != 0) { weightIndices[weightsFound] = (byte)maskInfluenceIndex[j]; vertexWeights[weightsFound] = (float)weight; weightsFound++; } } //Get unique UVs meshVertexIterator.getUVIndices(uvIndices); if (uvIndices.length != 0) { List <int> seen = new List <int>(); for (int j = 0; j < uvIndices.length; j++) { int uvIndex = uvIndices[j]; if (!seen.Contains(uvIndex)) { seen.Add(uvIndex); float u = 0; float v = 0; mesh.getUV(uvIndex, ref u, ref v); SKNVertex vertex = new SKNVertex(position, weightIndices, vertexWeights, normal, new Vector2(u, 1 - v)); vertex.UVIndex = uvIndex; shaderVertices[shader].Add(vertex); shaderVertexIndices[shader].append(index); } } } else { MGlobal.displayError("SKNFile:Create - Mesh contains a vertex with no UVs"); throw new Exception("SKNFile:Create - Mesh contains a vertex with no UVs"); } } //Convert from Maya indices to data indices int currentIndex = 0; MIntArray dataIndices = new MIntArray((uint)mesh.numVertices, -1); for (int i = 0; i < shaderCount; i++) { for (int j = 0; j < shaderVertexIndices[i].length; j++) { int index = shaderVertexIndices[i][j]; if (dataIndices[index] == -1) { dataIndices[index] = currentIndex; shaderVertices[i][j].DataIndex = currentIndex; } else { shaderVertices[i][j].DataIndex = dataIndices[index]; } currentIndex++; } this.Vertices.AddRange(shaderVertices[i]); } MItMeshPolygon polygonIterator = new MItMeshPolygon(meshDagPath); for (polygonIterator.reset(); !polygonIterator.isDone; polygonIterator.next()) { int polygonIndex = (int)polygonIterator.index(); int shaderIndex = polygonShaderIndices[polygonIndex]; MIntArray indices = new MIntArray(); MPointArray points = new MPointArray(); polygonIterator.getTriangles(points, indices); if (polygonIterator.hasUVsProperty) { MIntArray vertices = new MIntArray(); MIntArray newIndices = new MIntArray(indices.length, -1); polygonIterator.getVertices(vertices); for (int i = 0; i < vertices.length; i++) { int dataIndex = dataIndices[vertices[i]]; int uvIndex; polygonIterator.getUVIndex(i, out uvIndex); if (dataIndex == -1 || dataIndex >= this.Vertices.Count) { MGlobal.displayError("SKNFIle:Create - Data Index outside of range"); throw new Exception("SKNFIle:Create - Data Index outside of range"); } for (int j = dataIndex; j < this.Vertices.Count; j++) { if (this.Vertices[j].DataIndex != dataIndex) { MGlobal.displayError("SKNFIle:Create - Can't find corresponding face vertex in data"); throw new Exception("SKNFIle:Create - Can't find corresponding face vertex in data"); } else if (this.Vertices[j].UVIndex == uvIndex) { for (int k = 0; k < indices.length; k++) { if (indices[k] == vertices[i]) { newIndices[k] = j; } } break; } } } for (int i = 0; i < newIndices.length; i++) { shaderIndices[shaderIndex].append(newIndices[i]); } } else { for (int i = 0; i < indices.length; i++) { shaderIndices[shaderIndex].append(dataIndices[indices[i]]); } } } uint startIndex = 0; uint startVertex = 0; for (int i = 0; i < shaderCount; i++) { MPlug shaderPlug = new MFnDependencyNode(shaders[i]).findPlug("surfaceShader"); MPlugArray plugArray = new MPlugArray(); shaderPlug.connectedTo(plugArray, true, false); string name = new MFnDependencyNode(plugArray[0].node).name; uint indexCount = shaderIndices[i].length; uint vertexCount = shaderVertexIndices[i].length; //Copy indices to SKLFile for (int j = 0; j < indexCount; j++) { this.Indices.Add((ushort)shaderIndices[i][j]); } this.Submeshes.Add(new SKNSubmesh(name, startVertex, vertexCount, startIndex, indexCount)); startIndex += indexCount; startVertex += vertexCount; } MGlobal.displayInfo("SKNFile:Create - Created SKN File"); }
private bool CreateRiggedModel(LOLModel model, Logger logger) { bool result = true; logger.Event("Creating rigged model."); // Open the skn file. SKNFile sknFile = new SKNFile(); if (result == true) { result = SKNReader.Read(model.skn, ref sknFile, logger); } // Open the skl file. SKLFile sklFile = new SKLFile(); if (result == true) { result = SKLReader.Read(model.skl, ref sklFile, logger); } // Open the anm files. Dictionary <String, ANMFile> anmFiles = new Dictionary <String, ANMFile>(); if (result == true) { foreach (var a in model.animations) { ANMFile anmFile = new ANMFile(); bool anmResult = ANMReader.Read(a.Value, ref anmFile, logger); if (anmResult == true) { anmFiles.Add(a.Key, anmFile); } } } // Create the model. riggedModel = new GLRiggedModel(); if (result == true) { result = riggedModel.Create(sknFile, sklFile, anmFiles, logger); } // Set up an initial animation. if (result == true) { if (anmFiles.Count > 0) { riggedModel.SetCurrentAnimation(anmFiles.First().Key); riggedModel.SetCurrentFrame(0, 0); } } // // Create Model Texture. // if (result == true) { // Texture stored in RAF file. result = CreateTexture(model.texture, TextureTarget.Texture2D, GLTexture.SupportedImageEncodings.DDS, logger); // Store it in our new model file. if (result == true) { String name = model.texture.FileName; int pos = name.LastIndexOf("/"); name = name.Substring(pos + 1); riggedModel.TextureName = name; } } if (result == false) { logger.Error("Failed to create rigged model."); } return(result); }