/// <summary> /// Extract geometry (position, normal, UVs...) for a specific vertex /// </summary> /// <param name="mFnMesh"></param> /// <param name="polygonId">The polygon (face) to examine</param> /// <param name="vertexIndexGlobal">The object-relative (mesh-relative/global) vertex index</param> /// <param name="vertexIndexLocal">The face-relative (local) vertex id to examine</param> /// <param name="hasUV"></param> /// <returns></returns> private GlobalVertex ExtractVertex(MFnMesh mFnMesh, int polygonId, int vertexIndexGlobal, int vertexIndexLocal, bool hasUV) { MPoint point = new MPoint(); mFnMesh.getPoint(vertexIndexGlobal, point); MVector normal = new MVector(); mFnMesh.getFaceVertexNormal(polygonId, vertexIndexGlobal, normal); // Switch coordinate system at object level point.z *= -1; normal.z *= -1; var vertex = new GlobalVertex { BaseIndex = vertexIndexGlobal, Position = point.toArray(), Normal = normal.toArray() }; // UV if (hasUV) { float u = 0, v = 0; mFnMesh.getPolygonUV(polygonId, vertexIndexLocal, ref u, ref v); vertex.UV = new float[] { u, v }; } return(vertex); }
/// <summary> /// Extract ordered indices on a triangle basis /// Extract position and normal of each vertex per face /// </summary> /// <param name="mFnMesh"></param> /// <param name="vertices"></param> /// <param name="indices"></param> /// <param name="subMeshes"></param> /// <param name="optimizeVertices"></param> private void ExtractGeometry(MFnMesh mFnMesh, List <GlobalVertex> vertices, List <int> indices, List <BabylonSubMesh> subMeshes, bool optimizeVertices) { // TODO - Multimaterials: create a BabylonSubMesh per submaterial // TODO - optimizeVertices MIntArray triangleCounts = new MIntArray(); MIntArray trianglesVertices = new MIntArray(); mFnMesh.getTriangles(triangleCounts, trianglesVertices); // For each polygon of this mesh for (int polygonId = 0; polygonId < mFnMesh.numPolygons; polygonId++) { MIntArray verticesId = new MIntArray(); int nbTriangles = triangleCounts[polygonId]; // For each triangle of this polygon for (int triangleIndex = 0; triangleIndex < triangleCounts[polygonId]; triangleIndex++) { int[] triangleVertices = new int[3]; mFnMesh.getPolygonTriangleVertices(polygonId, triangleIndex, triangleVertices); // Inverse winding order var tmp = triangleVertices[1]; triangleVertices[1] = triangleVertices[2]; triangleVertices[2] = tmp; // For each vertex of this triangle (3 vertices per triangle) foreach (int vertexId in triangleVertices) { MPoint point = new MPoint(); mFnMesh.getPoint(vertexId, point); MVector normal = new MVector(); mFnMesh.getFaceVertexNormal(polygonId, vertexId, normal); var vertex = new GlobalVertex { BaseIndex = vertexId, Position = point.toArray(), Normal = normal.toArray() }; indices.Add(vertices.Count); vertices.Add(vertex); } } } // BabylonSubMesh var subMesh = new BabylonSubMesh { indexStart = 0, materialIndex = 0 }; subMeshes.Add(subMesh); subMesh.indexCount = indices.Count; subMesh.verticesStart = 0; subMesh.verticesCount = vertices.Count; }
/// <summary> /// Extract geometry (position, normal, UVs...) for a specific vertex /// </summary> /// <param name="mFnMesh"></param> /// <param name="polygonId">The polygon (face) to examine</param> /// <param name="vertexIndexGlobal">The object-relative (mesh-relative/global) vertex index</param> /// <param name="vertexIndexLocal">The face-relative (local) vertex id to examine</param> /// <param name="uvSetNames"></param> /// <param name="isUVExportSuccess"></param> /// <returns></returns> private GlobalVertex ExtractVertex(MFnMesh mFnMesh, int polygonId, int vertexIndexGlobal, int vertexIndexLocal, MStringArray uvSetNames, ref bool[] isUVExportSuccess) { MPoint point = new MPoint(); mFnMesh.getPoint(vertexIndexGlobal, point); MVector normal = new MVector(); mFnMesh.getFaceVertexNormal(polygonId, vertexIndexGlobal, normal); // Switch coordinate system at object level point.z *= -1; normal.z *= -1; var vertex = new GlobalVertex { BaseIndex = vertexIndexGlobal, Position = point.toArray(), Normal = normal.toArray(), }; // TODO - Export colors ? //// Color //int colorIndex; //string colorSetName; //float[] defaultColor = new float[] { 0.5f, 0.5f, 0.5f, 1 }; //MColor color = new MColor(); //mFnMesh.getCurrentColorSetName(out colorSetName); //if (mFnMesh.numColors(colorSetName) > 0) //{ // //Get the color index // mFnMesh.getColorIndex(polygonId, vertexIndexLocal, out colorIndex); // //if a color is set // if (colorIndex != -1) // { // mFnMesh.getColor(colorIndex, color); // vertex.Color = color.toArray(); // } // //else set the color to the default one of Maya // else // { // vertex.Color = defaultColor; // } //} //else //{ // vertex.Color = defaultColor; //} // UV int indexUVSet = 0; if (uvSetNames.Count > indexUVSet && isUVExportSuccess[indexUVSet]) { try { float u = 0, v = 0; mFnMesh.getPolygonUV(polygonId, vertexIndexLocal, ref u, ref v, uvSetNames[indexUVSet]); vertex.UV = new float[] { u, v }; } catch (Exception e) { // An exception is raised when a vertex isn't mapped to an UV coordinate isUVExportSuccess[indexUVSet] = false; } } indexUVSet = 1; if (uvSetNames.Count > indexUVSet && isUVExportSuccess[indexUVSet]) { try { float u = 0, v = 0; mFnMesh.getPolygonUV(polygonId, vertexIndexLocal, ref u, ref v, uvSetNames[indexUVSet]); vertex.UV2 = new float[] { u, v }; } catch (Exception e) { // An exception is raised when a vertex isn't mapped to an UV coordinate isUVExportSuccess[indexUVSet] = false; } } return(vertex); }
/// <summary> /// Extract geometry (position, normal, UVs...) for a specific vertex /// </summary> /// <param name="mFnMesh"></param> /// <param name="polygonId">The polygon (face) to examine</param> /// <param name="vertexIndexGlobal">The object-relative (mesh-relative/global) vertex index</param> /// <param name="vertexIndexLocal">The face-relative (local) vertex id to examine</param> /// <param name="uvSetNames"></param> /// <param name="isUVExportSuccess"></param> /// <returns></returns> private GlobalVertex ExtractVertex(MFnMesh mFnMesh, int polygonId, int vertexIndexGlobal, int vertexIndexLocal, MStringArray uvSetNames, ref bool[] isUVExportSuccess, ref bool isTangentExportSuccess) { MPoint point = new MPoint(); mFnMesh.getPoint(vertexIndexGlobal, point); MVector normal = new MVector(); mFnMesh.getFaceVertexNormal(polygonId, vertexIndexGlobal, normal); // Switch coordinate system at object level point.z *= -1; normal.z *= -1; var vertex = new GlobalVertex { BaseIndex = vertexIndexGlobal, Position = point.toArray(), Normal = normal.toArray() }; // Tangent if (isTangentExportSuccess) { try { MVector tangent = new MVector(); mFnMesh.getFaceVertexTangent(polygonId, vertexIndexGlobal, tangent); // Switch coordinate system at object level tangent.z *= -1; int tangentId = mFnMesh.getTangentId(polygonId, vertexIndexGlobal); bool isRightHandedTangent = mFnMesh.isRightHandedTangent(tangentId); // Invert W to switch to left handed system vertex.Tangent = new float[] { (float)tangent.x, (float)tangent.y, (float)tangent.z, isRightHandedTangent ? -1 : 1 }; } catch { // Exception raised when mesh don't have tangents isTangentExportSuccess = false; } } // Color int colorIndex; string colorSetName; float[] defaultColor = new float[] { 1, 1, 1, 0 }; MColor color = new MColor(); mFnMesh.getCurrentColorSetName(out colorSetName); if (mFnMesh.numColors(colorSetName) > 0) { //Get the color index mFnMesh.getColorIndex(polygonId, vertexIndexLocal, out colorIndex); //if a color is set if (colorIndex != -1) { mFnMesh.getColor(colorIndex, color); vertex.Color = color.toArray(); } //else set the default color else { vertex.Color = defaultColor; } } // UV int indexUVSet = 0; if (uvSetNames.Count > indexUVSet && isUVExportSuccess[indexUVSet]) { try { float u = 0, v = 0; mFnMesh.getPolygonUV(polygonId, vertexIndexLocal, ref u, ref v, uvSetNames[indexUVSet]); vertex.UV = new float[] { u, v }; } catch { // An exception is raised when a vertex isn't mapped to an UV coordinate isUVExportSuccess[indexUVSet] = false; } } indexUVSet = 1; if (uvSetNames.Count > indexUVSet && isUVExportSuccess[indexUVSet]) { try { float u = 0, v = 0; mFnMesh.getPolygonUV(polygonId, vertexIndexLocal, ref u, ref v, uvSetNames[indexUVSet]); vertex.UV2 = new float[] { u, v }; } catch { // An exception is raised when a vertex isn't mapped to an UV coordinate isUVExportSuccess[indexUVSet] = false; } } // skin if (mFnSkinCluster != null) { // Filter null weights Dictionary <int, double> weightByInfluenceIndex = new Dictionary <int, double>(); // contains the influence indices with weight > 0 // Export Weights and BonesIndices for the vertex // Get the weight values of all the influences for this vertex allMayaInfluenceWeights = new MDoubleArray(); MGlobal.executeCommand($"skinPercent -query -value {mFnSkinCluster.name} {mFnTransform.name}.vtx[{vertexIndexGlobal}]", allMayaInfluenceWeights); allMayaInfluenceWeights.get(out double[] allInfluenceWeights); for (int influenceIndex = 0; influenceIndex < allInfluenceWeights.Length; influenceIndex++) { double weight = allInfluenceWeights[influenceIndex]; if (weight > 0) { try { // add indice and weight in the local lists weightByInfluenceIndex.Add(indexByNodeName[allMayaInfluenceNames[influenceIndex]], weight); } catch (Exception e) { RaiseError(e.Message, 2); RaiseError(e.StackTrace, 3); } } } // normalize weights => Sum weights == 1 Normalize(ref weightByInfluenceIndex); // decreasing sort OrderByDescending(ref weightByInfluenceIndex); int bonesCount = indexByNodeName.Count; // number total of bones/influences for the mesh float weight0 = 0; float weight1 = 0; float weight2 = 0; float weight3 = 0; int bone0 = bonesCount; int bone1 = bonesCount; int bone2 = bonesCount; int bone3 = bonesCount; int nbBones = weightByInfluenceIndex.Count; // number of bones/influences for this vertex if (nbBones == 0) { weight0 = 1.0f; bone0 = bonesCount; } if (nbBones > 0) { bone0 = weightByInfluenceIndex.ElementAt(0).Key; weight0 = (float)weightByInfluenceIndex.ElementAt(0).Value; if (nbBones > 1) { bone1 = weightByInfluenceIndex.ElementAt(1).Key; weight1 = (float)weightByInfluenceIndex.ElementAt(1).Value; if (nbBones > 2) { bone2 = weightByInfluenceIndex.ElementAt(2).Key; weight2 = (float)weightByInfluenceIndex.ElementAt(2).Value; if (nbBones > 3) { bone3 = weightByInfluenceIndex.ElementAt(3).Key; weight3 = (float)weightByInfluenceIndex.ElementAt(3).Value; } } } } float[] weights = { weight0, weight1, weight2, weight3 }; vertex.Weights = weights; vertex.BonesIndices = (bone3 << 24) | (bone2 << 16) | (bone1 << 8) | bone0; if (nbBones > 4) { bone0 = weightByInfluenceIndex.ElementAt(4).Key; weight0 = (float)weightByInfluenceIndex.ElementAt(4).Value; weight1 = 0; weight2 = 0; weight3 = 0; if (nbBones > 5) { bone1 = weightByInfluenceIndex.ElementAt(5).Key; weight1 = (float)weightByInfluenceIndex.ElementAt(4).Value; if (nbBones > 6) { bone2 = weightByInfluenceIndex.ElementAt(6).Key; weight2 = (float)weightByInfluenceIndex.ElementAt(4).Value; if (nbBones > 7) { bone3 = weightByInfluenceIndex.ElementAt(7).Key; weight3 = (float)weightByInfluenceIndex.ElementAt(7).Value; } } } float[] weightsExtra = { weight0, weight1, weight2, weight3 }; vertex.WeightsExtra = weightsExtra; vertex.BonesIndicesExtra = (bone3 << 24) | (bone2 << 16) | (bone1 << 8) | bone0; } } return(vertex); }
/// <summary> /// Extract geometry (position, normal, UVs...) for a specific vertex /// </summary> /// <param name="mFnMesh"></param> /// <param name="polygonId">The polygon (face) to examine</param> /// <param name="vertexIndexGlobal">The object-relative (mesh-relative/global) vertex index</param> /// <param name="vertexIndexLocal">The face-relative (local) vertex id to examine</param> /// <param name="uvSetNames"></param> /// <param name="isUVExportSuccess"></param> /// <returns></returns> private GlobalVertex ExtractVertex(MFnMesh mFnMesh, int polygonId, int vertexIndexGlobal, int vertexIndexLocal, MStringArray uvSetNames, ref bool[] isUVExportSuccess) { MPoint point = new MPoint(); mFnMesh.getPoint(vertexIndexGlobal, point); MVector normal = new MVector(); mFnMesh.getFaceVertexNormal(polygonId, vertexIndexGlobal, normal); MVector tangent = new MVector(); mFnMesh.getFaceVertexTangent(polygonId, vertexIndexGlobal, tangent); // Switch coordinate system at object level point.z *= -1; normal.z *= -1; tangent.z *= -1; float[] tangentVec4 = new float[] { (float)tangent.x, (float)tangent.y, (float)tangent.z, -1 }; var vertex = new GlobalVertex { BaseIndex = vertexIndexGlobal, Position = point.toArray(), Normal = normal.toArray(), Tangent = tangentVec4, }; // Color int colorIndex; string colorSetName; float[] defaultColor = new float[] { 1, 1, 1, 0 }; MColor color = new MColor(); mFnMesh.getCurrentColorSetName(out colorSetName); if (mFnMesh.numColors(colorSetName) > 0) { //Get the color index mFnMesh.getColorIndex(polygonId, vertexIndexLocal, out colorIndex); //if a color is set if (colorIndex != -1) { mFnMesh.getColor(colorIndex, color); vertex.Color = color.toArray(); } //else set the default color else { vertex.Color = defaultColor; } } // UV int indexUVSet = 0; if (uvSetNames.Count > indexUVSet && isUVExportSuccess[indexUVSet]) { try { float u = 0, v = 0; mFnMesh.getPolygonUV(polygonId, vertexIndexLocal, ref u, ref v, uvSetNames[indexUVSet]); vertex.UV = new float[] { u, v }; } catch (Exception e) { // An exception is raised when a vertex isn't mapped to an UV coordinate isUVExportSuccess[indexUVSet] = false; } } indexUVSet = 1; if (uvSetNames.Count > indexUVSet && isUVExportSuccess[indexUVSet]) { try { float u = 0, v = 0; mFnMesh.getPolygonUV(polygonId, vertexIndexLocal, ref u, ref v, uvSetNames[indexUVSet]); vertex.UV2 = new float[] { u, v }; } catch (Exception e) { // An exception is raised when a vertex isn't mapped to an UV coordinate isUVExportSuccess[indexUVSet] = false; } } return(vertex); }
public static string toString(this MPoint mPoint) { return(mPoint == null ? "" : mPoint.toArray().toString()); }