/// <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;
        }
Esempio n. 3
0
        /// <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);
        }
Esempio n. 4
0
        /// <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="uvSetNames"></param>
        /// <param name="isUVExportSuccess"></param>
        /// <param name="optimizeVertices"></param>
        private void ExtractGeometry(MFnMesh mFnMesh, List <GlobalVertex> vertices, List <int> indices, List <BabylonSubMesh> subMeshes, MStringArray uvSetNames, ref bool[] isUVExportSuccess, bool optimizeVertices)
        {
            // TODO - optimizeVertices
            MIntArray triangleCounts    = new MIntArray();
            MIntArray trianglesVertices = new MIntArray();

            mFnMesh.getTriangles(triangleCounts, trianglesVertices);

            MObjectArray shaders        = new MObjectArray();
            MIntArray    faceMatIndices = new MIntArray(); // given a face index => get a shader index

            mFnMesh.getConnectedShaders(0, shaders, faceMatIndices);

            // Export geometry even if an error occured with shaders
            // This is a fix for Maya test files
            // TODO - Find the reason why shaders.count = 0
            int  nbShaders   = Math.Max(1, shaders.Count);
            bool checkShader = nbShaders == shaders.Count;

            RaiseVerbose("shaders.Count=" + shaders.Count, 2);

            // For each material of this mesh
            for (int indexShader = 0; indexShader < nbShaders; indexShader++)
            {
                var nbIndicesSubMesh      = 0;
                var minVertexIndexSubMesh = int.MaxValue;
                var maxVertexIndexSubMesh = int.MinValue;
                var subMesh = new BabylonSubMesh {
                    indexStart = indices.Count, materialIndex = indexShader
                };

                // For each polygon of this mesh
                for (int polygonId = 0; polygonId < faceMatIndices.Count; polygonId++)
                {
                    if (checkShader && faceMatIndices[polygonId] != indexShader)
                    {
                        continue;
                    }

                    // The object-relative (mesh-relative/global) vertex indices for this face
                    MIntArray polygonVertices = new MIntArray();
                    mFnMesh.getPolygonVertices(polygonId, polygonVertices);

                    // For each triangle of this polygon
                    for (int triangleId = 0; triangleId < triangleCounts[polygonId]; triangleId++)
                    {
                        int[] polygonTriangleVertices = new int[3];
                        mFnMesh.getPolygonTriangleVertices(polygonId, triangleId, polygonTriangleVertices);

                        /*
                         * Switch coordinate system at global level
                         *
                         * Piece of code kept just in case
                         * See BabylonExporter for more information
                         */
                        //// Inverse winding order to flip faces
                        //var tmp = triangleVertices[1];
                        //triangleVertices[1] = triangleVertices[2];
                        //triangleVertices[2] = tmp;

                        // For each vertex of this triangle (3 vertices per triangle)
                        foreach (int vertexIndexGlobal in polygonTriangleVertices)
                        {
                            // Get the face-relative (local) vertex id
                            int vertexIndexLocal = 0;
                            for (vertexIndexLocal = 0; vertexIndexLocal < polygonVertices.Count; vertexIndexLocal++)
                            {
                                if (polygonVertices[vertexIndexLocal] == vertexIndexGlobal)
                                {
                                    break;
                                }
                            }

                            GlobalVertex vertex = ExtractVertex(mFnMesh, polygonId, vertexIndexGlobal, vertexIndexLocal, uvSetNames, ref isUVExportSuccess);
                            vertex.CurrentIndex = vertices.Count;

                            indices.Add(vertex.CurrentIndex);
                            vertices.Add(vertex);

                            minVertexIndexSubMesh = Math.Min(minVertexIndexSubMesh, vertex.CurrentIndex);
                            maxVertexIndexSubMesh = Math.Max(maxVertexIndexSubMesh, vertex.CurrentIndex);
                            nbIndicesSubMesh++;
                        }
                    }
                }

                if (nbIndicesSubMesh != 0)
                {
                    subMesh.indexCount    = nbIndicesSubMesh;
                    subMesh.verticesStart = minVertexIndexSubMesh;
                    subMesh.verticesCount = maxVertexIndexSubMesh - minVertexIndexSubMesh + 1;

                    subMeshes.Add(subMesh);
                }
            }
        }
Esempio n. 5
0
        /// <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);
        }