Example #1
0
		public apiMeshGeomUV()
		{
			faceVertexIndex = new MIntArray();
			ucoord = new MFloatArray();
			vcoord = new MFloatArray();

			reset();
		}
Example #2
0
        public apiMeshGeomUV()
        {
            faceVertexIndex = new MIntArray();
            ucoord          = new MFloatArray();
            vcoord          = new MFloatArray();

            reset();
        }
        public override void readFloatArray(MFloatArray array, uint size)
        {
            Trace.Assert(myCurrentChanelNode != null);

            XmlNode     floatArrayNode = myCurrentChanelNode.SelectSingleNode(floatArrayTag);
            XmlNodeList valueNodeList  = floatArrayNode.SelectNodes("value");

            array.clear();
            array.length = size;
            foreach (XmlNode valueNode in valueNodeList)
            {
                double value = Convert.ToDouble(valueNode.InnerText);
                array.append((float)value);
            }
            return;
        }
        public override void writeFloatArray(MFloatArray array)
        {
            if (myCurrentChanelNode != null)
            {
                uint    size     = array.length;
                XmlNode sizeNode = myXmlDoc.CreateElement(sizeTag);
                sizeNode.InnerText = Convert.ToString(size);
                myCurrentChanelNode.AppendChild(sizeNode);

                XmlNode arrayNode = myXmlDoc.CreateElement(floatArrayTag);
                myCurrentChanelNode.AppendChild(arrayNode);

                for (int i = 0; i < size; i++)
                {
                    string  value     = array[i].ToString();
                    XmlNode valueNode = myXmlDoc.CreateElement("value");
                    arrayNode.AppendChild(valueNode);
                }
            }

            return;
        }
Example #5
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="mDagPath">DAG path to the transform above mesh</param>
        /// <param name="babylonScene"></param>
        /// <returns></returns>
        private BabylonNode ExportMesh(MDagPath mDagPath, BabylonScene babylonScene)
        {
            RaiseMessage(mDagPath.partialPathName, 1);

            // Transform above mesh
            MFnTransform mFnTransform = new MFnTransform(mDagPath);

            // Mesh direct child of the transform
            MFnMesh mFnMesh = null;

            for (uint i = 0; i < mFnTransform.childCount; i++)
            {
                MObject childObject = mFnTransform.child(i);
                if (childObject.apiType == MFn.Type.kMesh)
                {
                    var _mFnMesh = new MFnMesh(childObject);
                    if (!_mFnMesh.isIntermediateObject)
                    {
                        mFnMesh = _mFnMesh;
                    }
                }
            }
            if (mFnMesh == null)
            {
                RaiseError("No mesh found has child of " + mDagPath.fullPathName);
                return(null);
            }

            RaiseMessage("mFnMesh.fullPathName=" + mFnMesh.fullPathName, 2);

            // --- prints ---
            #region prints

            Action <MFnDagNode> printMFnDagNode = (MFnDagNode mFnDagNode) =>
            {
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.name=" + mFnDagNode.name, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.absoluteName=" + mFnDagNode.absoluteName, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.fullPathName=" + mFnDagNode.fullPathName, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.partialPathName=" + mFnDagNode.partialPathName, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.activeColor=" + mFnDagNode.activeColor.toString(), 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.attributeCount=" + mFnDagNode.attributeCount, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.childCount=" + mFnDagNode.childCount, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.dormantColor=" + mFnDagNode.dormantColor, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.hasUniqueName=" + mFnDagNode.hasUniqueName, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.inUnderWorld=" + mFnDagNode.inUnderWorld, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isDefaultNode=" + mFnDagNode.isDefaultNode, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isInstanceable=" + mFnDagNode.isInstanceable, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isInstanced(true)=" + mFnDagNode.isInstanced(true), 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isInstanced(false)=" + mFnDagNode.isInstanced(false), 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isInstanced()=" + mFnDagNode.isInstanced(), 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.instanceCount(true)=" + mFnDagNode.instanceCount(true), 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.instanceCount(false)=" + mFnDagNode.instanceCount(false), 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isIntermediateObject=" + mFnDagNode.isIntermediateObject, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isShared=" + mFnDagNode.isShared, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.objectColor=" + mFnDagNode.objectColor, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.parentCount=" + mFnDagNode.parentCount, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.parentNamespace=" + mFnDagNode.parentNamespace, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.uuid().asString()=" + mFnDagNode.uuid().asString(), 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.dagRoot().apiType=" + mFnDagNode.dagRoot().apiType, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.model.equalEqual(mFnDagNode.objectProperty)=" + mFnDagNode.model.equalEqual(mFnDagNode.objectProperty), 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.transformationMatrix.toString()=" + mFnDagNode.transformationMatrix.toString(), 3);
            };

            Action <MFnMesh> printMFnMesh = (MFnMesh _mFnMesh) =>
            {
                printMFnDagNode(mFnMesh);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numVertices=" + _mFnMesh.numVertices, 3);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numEdges=" + _mFnMesh.numEdges, 3);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numPolygons=" + _mFnMesh.numPolygons, 3);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numFaceVertices=" + _mFnMesh.numFaceVertices, 3);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numNormals=" + _mFnMesh.numNormals, 3);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numUVSets=" + _mFnMesh.numUVSets, 3);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numUVsProperty=" + _mFnMesh.numUVsProperty, 3);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.displayColors=" + _mFnMesh.displayColors, 3);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numColorSets=" + _mFnMesh.numColorSets, 3);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numColorsProperty=" + _mFnMesh.numColorsProperty, 3);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.currentUVSetName()=" + _mFnMesh.currentUVSetName(), 3);

                var _uvSetNames = new MStringArray();
                mFnMesh.getUVSetNames(_uvSetNames);
                foreach (var uvSetName in _uvSetNames)
                {
                    RaiseVerbose("BabylonExporter.Mesh | uvSetName=" + uvSetName, 3);
                    RaiseVerbose("BabylonExporter.Mesh | mFnMesh.numUVs(uvSetName)=" + mFnMesh.numUVs(uvSetName), 4);
                    MFloatArray us = new MFloatArray();
                    MFloatArray vs = new MFloatArray();
                    mFnMesh.getUVs(us, vs, uvSetName);
                    RaiseVerbose("BabylonExporter.Mesh | us.Count=" + us.Count, 4);
                }
            };

            Action <MFnTransform> printMFnTransform = (MFnTransform _mFnMesh) =>
            {
                printMFnDagNode(mFnMesh);
            };

            RaiseVerbose("BabylonExporter.Mesh | mFnMesh data", 2);
            printMFnMesh(mFnMesh);

            RaiseVerbose("BabylonExporter.Mesh | mFnTransform data", 2);
            printMFnTransform(mFnTransform);

            Print(mFnTransform, 2, "Print ExportMesh mFnTransform");

            Print(mFnMesh, 2, "Print ExportMesh mFnMesh");

            //// Geometry
            //MIntArray triangleCounts = new MIntArray();
            //MIntArray trianglesVertices = new MIntArray();
            //mFnMesh.getTriangles(triangleCounts, trianglesVertices);
            //RaiseVerbose("BabylonExporter.Mesh | triangleCounts.ToArray()=" + triangleCounts.ToArray().toString(), 3);
            //RaiseVerbose("BabylonExporter.Mesh | trianglesVertices.ToArray()=" + trianglesVertices.ToArray().toString(), 3);
            //int[] polygonsVertexCount = new int[mFnMesh.numPolygons];
            //for (int polygonId = 0; polygonId < mFnMesh.numPolygons; polygonId++)
            //{
            //    polygonsVertexCount[polygonId] = mFnMesh.polygonVertexCount(polygonId);
            //}
            //RaiseVerbose("BabylonExporter.Mesh | polygonsVertexCount=" + polygonsVertexCount.toString(), 3);

            ////MFloatPointArray points = new MFloatPointArray();
            ////mFnMesh.getPoints(points);
            ////RaiseVerbose("BabylonExporter.Mesh | points.ToArray()=" + points.ToArray().Select(mFloatPoint => mFloatPoint.toString()), 3);

            ////MFloatVectorArray normals = new MFloatVectorArray();
            ////mFnMesh.getNormals(normals);
            ////RaiseVerbose("BabylonExporter.Mesh | normals.ToArray()=" + normals.ToArray().Select(mFloatPoint => mFloatPoint.toString()), 3);

            //for (int polygonId = 0; polygonId < mFnMesh.numPolygons; polygonId++)
            //{
            //    MIntArray verticesId = new MIntArray();
            //    RaiseVerbose("BabylonExporter.Mesh | polygonId=" + polygonId, 3);

            //    int nbTriangles = triangleCounts[polygonId];
            //    RaiseVerbose("BabylonExporter.Mesh | nbTriangles=" + nbTriangles, 3);

            //    for (int triangleIndex = 0; triangleIndex < triangleCounts[polygonId]; triangleIndex++)
            //    {
            //        RaiseVerbose("BabylonExporter.Mesh | triangleIndex=" + triangleIndex, 3);
            //        int[] triangleVertices = new int[3];
            //        mFnMesh.getPolygonTriangleVertices(polygonId, triangleIndex, triangleVertices);
            //        RaiseVerbose("BabylonExporter.Mesh | triangleVertices=" + triangleVertices.toString(), 3);

            //        foreach (int vertexId in triangleVertices)
            //        {
            //            RaiseVerbose("BabylonExporter.Mesh | vertexId=" + vertexId, 3);
            //            MPoint point = new MPoint();
            //            mFnMesh.getPoint(vertexId, point);
            //            RaiseVerbose("BabylonExporter.Mesh | point=" + point.toString(), 3);

            //            MVector normal = new MVector();
            //            mFnMesh.getFaceVertexNormal(polygonId, vertexId, normal);
            //            RaiseVerbose("BabylonExporter.Mesh | normal=" + normal.toString(), 3);
            //        }
            //    }
            //}

            #endregion


            if (IsMeshExportable(mFnMesh, mDagPath) == false)
            {
                return(null);
            }

            var babylonMesh = new BabylonMesh {
                name = mFnTransform.name, id = mFnTransform.uuid().asString()
            };

            // Position / rotation / scaling / hierarchy
            ExportNode(babylonMesh, mFnTransform, babylonScene);

            // Misc.
            // TODO - Retreive from Maya
            // TODO - What is the difference between isVisible and visibility?
            // TODO - Fix fatal error: Attempting to save in C:/Users/Fabrice/AppData/Local/Temp/Fabrice.20171205.1613.ma
            //babylonMesh.isVisible = mDagPath.isVisible;
            //babylonMesh.visibility = meshNode.MaxNode.GetVisibility(0, Tools.Forever);
            //babylonMesh.receiveShadows = meshNode.MaxNode.RcvShadows == 1;
            //babylonMesh.applyFog = meshNode.MaxNode.ApplyAtmospherics == 1;

            if (mFnMesh.numPolygons < 1)
            {
                RaiseError($"Mesh {babylonMesh.name} has no face", 2);
            }

            if (mFnMesh.numVertices < 3)
            {
                RaiseError($"Mesh {babylonMesh.name} has not enough vertices", 2);
            }

            if (mFnMesh.numVertices >= 65536)
            {
                RaiseWarning($"Mesh {babylonMesh.name} has more than 65536 vertices which means that it will require specific WebGL extension to be rendered. This may impact portability of your scene on low end devices.", 2);
            }

            // Material
            MObjectArray shaders = new MObjectArray();
            mFnMesh.getConnectedShaders(0, shaders, new MIntArray());
            if (shaders.Count > 0)
            {
                List <MFnDependencyNode> materials = new List <MFnDependencyNode>();
                foreach (MObject shader in shaders)
                {
                    // Retreive material
                    MFnDependencyNode shadingEngine      = new MFnDependencyNode(shader);
                    MPlug             mPlugSurfaceShader = shadingEngine.findPlug("surfaceShader");
                    MObject           materialObject     = mPlugSurfaceShader.source.node;
                    MFnDependencyNode material           = new MFnDependencyNode(materialObject);

                    materials.Add(material);
                }

                if (shaders.Count == 1)
                {
                    MFnDependencyNode material = materials[0];

                    // Material is referenced by id
                    babylonMesh.materialId = material.uuid().asString();

                    // Register material for export if not already done
                    if (!referencedMaterials.Contains(material, new MFnDependencyNodeEqualityComparer()))
                    {
                        referencedMaterials.Add(material);
                    }
                }
                else
                {
                    // Create a new id for the group of sub materials
                    string uuidMultiMaterial = GetMultimaterialUUID(materials);

                    // Multi material is referenced by id
                    babylonMesh.materialId = uuidMultiMaterial;

                    // Register multi material for export if not already done
                    if (!multiMaterials.ContainsKey(uuidMultiMaterial))
                    {
                        multiMaterials.Add(uuidMultiMaterial, materials);
                    }
                }
            }

            var vertices = new List <GlobalVertex>();
            var indices  = new List <int>();

            var uvSetNames = new MStringArray();
            mFnMesh.getUVSetNames(uvSetNames);
            bool[] isUVExportSuccess = new bool[Math.Min(uvSetNames.Count, 2)];
            for (int indexUVSet = 0; indexUVSet < isUVExportSuccess.Length; indexUVSet++)
            {
                isUVExportSuccess[indexUVSet] = true;
            }

            // TODO - color, alpha
            //var hasColor = unskinnedMesh.NumberOfColorVerts > 0;
            //var hasAlpha = unskinnedMesh.GetNumberOfMapVerts(-2) > 0;

            // TODO - Add custom properties
            var optimizeVertices = false; // meshNode.MaxNode.GetBoolProperty("babylonjs_optimizevertices");

            // Compute normals
            var subMeshes = new List <BabylonSubMesh>();
            ExtractGeometry(mFnMesh, vertices, indices, subMeshes, uvSetNames, ref isUVExportSuccess, optimizeVertices);

            if (vertices.Count >= 65536)
            {
                RaiseWarning($"Mesh {babylonMesh.name} has {vertices.Count} vertices. This may prevent your scene to work on low end devices where 32 bits indice are not supported", 2);

                if (!optimizeVertices)
                {
                    RaiseError("You can try to optimize your object using [Try to optimize vertices] option", 2);
                }
            }

            for (int indexUVSet = 0; indexUVSet < isUVExportSuccess.Length; indexUVSet++)
            {
                string uvSetName = uvSetNames[indexUVSet];
                // If at least one vertex is mapped to an UV coordinate but some have failed to be exported
                if (isUVExportSuccess[indexUVSet] == false && mFnMesh.numUVs(uvSetName) > 0)
                {
                    RaiseWarning($"Failed to export UV set named {uvSetName}. Ensure all vertices are mapped to a UV coordinate.", 2);
                }
            }

            RaiseMessage($"{vertices.Count} vertices, {indices.Count / 3} faces", 2);

            // Buffers
            babylonMesh.positions = vertices.SelectMany(v => v.Position).ToArray();
            babylonMesh.normals   = vertices.SelectMany(v => v.Normal).ToArray();
            // TODO - Export colors ?
            //babylonMesh.colors = vertices.SelectMany(v => v.Color).ToArray();

            if (uvSetNames.Count > 0 && isUVExportSuccess[0])
            {
                babylonMesh.uvs = vertices.SelectMany(v => v.UV).ToArray();
            }
            if (uvSetNames.Count > 1 && isUVExportSuccess[1])
            {
                babylonMesh.uvs2 = vertices.SelectMany(v => v.UV2).ToArray();
            }

            babylonMesh.subMeshes = subMeshes.ToArray();

            // Buffers - Indices
            babylonMesh.indices = indices.ToArray();


            babylonScene.MeshesList.Add(babylonMesh);
            RaiseMessage("BabylonExporter.Mesh | done", 2);

            return(babylonMesh);
        }
Example #6
0
        public void Load(string name)
        {
            List <StaticObjectVertex> vertices = GetVertices();
            List <uint> indices = GetIndices();

            MIntArray        polygonIndexCounts = new MIntArray((uint)indices.Count / 3);
            MIntArray        polygonIndices     = new MIntArray((uint)indices.Count);
            MFloatPointArray meshVertices       = new MFloatPointArray((uint)vertices.Count);
            MFloatArray      arrayU             = new MFloatArray((uint)vertices.Count);
            MFloatArray      arrayV             = new MFloatArray((uint)vertices.Count);
            MFnMesh          mesh        = new MFnMesh();
            MDagPath         meshDagPath = new MDagPath();
            MDGModifier      modifier    = new MDGModifier();
            MFnSet           set         = new MFnSet();

            for (int i = 0; i < indices.Count / 3; i++)
            {
                polygonIndexCounts[i] = 3;
            }

            for (int i = 0; i < indices.Count; i++)
            {
                polygonIndices[i] = (int)indices[i];
            }

            for (int i = 0; i < vertices.Count; i++)
            {
                StaticObjectVertex vertex = vertices[i];

                meshVertices[i] = new MFloatPoint(vertex.Position.X, vertex.Position.Y, vertex.Position.Z);
                arrayU[i]       = vertex.UV.X;
                arrayV[i]       = 1 - vertex.UV.Y;
            }

            //Assign mesh data
            mesh.create(vertices.Count, indices.Count / 3, meshVertices, polygonIndexCounts, polygonIndices, arrayU, arrayV, MObject.kNullObj);
            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
            MFnPartition renderPartition = MayaHelper.FindRenderPartition();

            //Create Materials
            uint startIndex = 0;

            for (int i = 0; i < this.Submeshes.Count; i++)
            {
                MFnDependencyNode   dependencyNode = new MFnDependencyNode();
                MFnLambertShader    lambertShader  = new MFnLambertShader();
                StaticObjectSubmesh submesh        = this.Submeshes[i];

                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");
                MPlug   partitionPlug = new MFnDependencyNode(shadingEngine).findPlug("partition");
                MPlug   setsPlug      = MayaHelper.FindFirstNotConnectedElement(renderPartition.findPlug("sets"));
                modifier.connect(partitionPlug, setsPlug);

                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 = (startIndex + (uint)submesh.Indices.Count) / 3;
                for (uint j = startIndex / 3; j < endIndex; j++)
                {
                    groupPolygonIndices.append((int)j);
                }
                component.addElements(groupPolygonIndices);

                set.setObject(shadingEngine);
                set.addMember(meshDagPath, faceComponent);

                startIndex += (uint)submesh.Indices.Count;
            }

            mesh.updateSurface();
        }
Example #7
0
        unsafe public override void getTweakedUVs(MObject meshObj, MIntArray uvList, MFloatArray uPos, MFloatArray vPos)
        {
            int i = 0;
            MFloatArray uArray = new MFloatArray();
            MFloatArray vArray = new MFloatArray();
            MFnMesh mesh = new MFnMesh(meshObj);
            mesh.getUVs(uArray, vArray);

            uint nbUvShells = 0;
            MIntArray uvShellIds = new MIntArray();

            if ((!flipGlobal) || extendToShell)
                // First, extract the UV shells.
                mesh.getUvShellsIds(uvShellIds, ref nbUvShells);

            if (extendToShell)
            {
                bool[] selected = new bool[nbUvShells];
                for (i = 0; i < nbUvShells; i++)
                {
                    selected[i] = false;
                }

                for (i = 0; i < nbUvShells; i++)
                {
                    int index = uvList[i];
                    index = uvShellIds[index];
                    selected[index] = true;
                }

                uint numUvs = (uint)mesh.numUVsProperty;
                uint numSelUvs = 0;

                // Preallocate a buffer, large enough to hold all Ids. This
                // prevents multiple reallocation from happening when growing
                // the array.
                uvList.length = numUvs;

                for (i = 0; i < numUvs; i++)
                {
                    int index = uvShellIds[i];
                    if (selected[index])
                    {
                        uvList.set((int)i, numSelUvs);
                        numSelUvs++;
                    }
                }

                // clamp the array to the proper size.
                uvList.length = numSelUvs;
            }

            int nbUvShellsInt = (int)nbUvShells;
            // For global flips, just pretend there is only one shell
            if (flipGlobal)
                nbUvShellsInt = 1;

            float[] minMax = new float[nbUvShellsInt * 4];

            for (i = 0; i < nbUvShellsInt; i++)
            {
                minMax[4 * i + 0] = 1e30F;				// Min U
                minMax[4 * i + 1] = 1e30F;				// Min V
                minMax[4 * i + 2] = -1e30F;				// Max U
                minMax[4 * i + 3] = -1e30F;				// Max V
            }

            // Get the bounding box of the UVs, for each shell if flipGlobal
            // is true, or for the whole selection if false.
            for (i = 0; i < uvList.length; i++)
            {
                int indx = uvList[i];
                int shellId = 0;

                if (!flipGlobal)
                {
                    shellId = uvShellIds[indx];
                }

                float value = uArray[indx];
                
                if (value < minMax[4 * shellId + 0])
                    minMax[4 * shellId + 0] = value;

                value = vArray[indx];
                if (value < minMax[4 * shellId + 1])
                    minMax[4 * shellId + 1] = value;

                value = uArray[indx];
                if (value > minMax[4 * shellId + 2])
                    minMax[4 * shellId + 2] = value;

                value = vArray[indx];
                if (value > minMax[4 * shellId + 3])
                    minMax[4 * shellId + 3] = value;
            }

            // Adjust the size of the output arrays
            uPos.length = uvList.length;
            vPos.length = uvList.length;

            for (i = 0; i < uvList.length; i++)
            {
                int shellId = 0;

                int indx = uvList[i];

                if (!flipGlobal)
                    shellId = uvShellIds[indx];

                // Flip U or V along the bounding box center.
                if (horizontal)
                {
                    float value = uArray[indx];
                    value = minMax[4 * shellId + 0] + minMax[4 * shellId + 2] - value;

                    uPos.set(value, (uint)i);
                    value = vArray[indx];
                    vPos.set(value, (uint)i);
                }
                else
                {
                    float value = uArray[indx];
                    uPos.set(value, (uint)i);

                    value = vArray[indx];
                    value = minMax[4 * shellId + 1] + minMax[4 * shellId + 3] - value;
                    vPos.set(value, (uint)i);
                }
            }
            return;
        }
Example #8
0
        public static void ExportXModel(string FilePath, XModelType FileType, bool Siege = false, string Cosmetic = "")
        {
            // Configure scene
            using (var MayaCfg = new MayaSceneConfigure())
            {
                // First, get the current selection
                var ExportObjectList = new MSelectionList();
                MGlobal.getActiveSelectionList(ExportObjectList);

                // If empty, select all joints and meshes
                if (ExportObjectList.length == 0)
                {
                    // Select all joints and meshes
                    MGlobal.executeCommand("string $selected[] = `ls -type joint`; select -r $selected;");
                    MGlobal.executeCommand("string $transforms[] = `ls -tr`;string $polyMeshes[] = `filterExpand -sm 12 $transforms`;select -add $polyMeshes;");

                    // Get it again
                    MGlobal.getActiveSelectionList(ExportObjectList);
                }

                // If still empty, error blank scene
                if (ExportObjectList.length == 0)
                {
                    MGlobal.displayError("[CODTools] The current scene is empty...");
                    return;
                }

                // Progress
                MayaCfg.StartProgress("Exporting XModel...", (int)ExportObjectList.length);

                // Create new model
                var Result = new XModel(System.IO.Path.GetFileNameWithoutExtension(FilePath));
                // Assign siege model flag (Default: false)
                Result.SiegeModel = Siege;

                // Metadata
                var SceneName = string.Empty;
                MGlobal.executeCommand("file -q -sceneName", out SceneName);

                Result.Comments.Add(string.Format("Export filename: '{0}'", FilePath));
                Result.Comments.Add(string.Format("Source filename: '{0}'", SceneName));
                Result.Comments.Add(string.Format("Export time: {0}", DateTime.Now.ToString()));

                // Iterate and add joints
                var ParentStack = new List <string>();
                var UniqueBones = new HashSet <string>();

                foreach (var Joint in ExportObjectList.DependNodes(MFn.Type.kJoint))
                {
                    // Step
                    MayaCfg.StepProgress();

                    // Grab the controller
                    var Path       = GetObjectDagPath(Joint);
                    var Controller = new MFnIkJoint(Path);

                    // Create a new bone
                    var TagName = CleanNodeName(Controller.name);

                    if (UniqueBones.Contains(TagName))
                    {
                        continue;
                    }
                    UniqueBones.Add(TagName);

                    var NewBone = new Bone(TagName);
                    // Add parent
                    ParentStack.Add(GetParentName(Controller));

                    // Fetch the world-space position and rotation
                    var WorldPosition = Controller.getTranslation(MSpace.Space.kWorld);

                    var WorldRotation = new MQuaternion(MQuaternion.identity);
                    Controller.getRotation(WorldRotation, MSpace.Space.kWorld);

                    var WorldScale = new double[3] {
                        1, 1, 1
                    };
                    Controller.getScale(WorldScale);

                    // Create the matrix
                    NewBone.Translation    = WorldPosition * (1 / 2.54);
                    NewBone.Scale          = new MVector(WorldScale[0], WorldScale[1], WorldScale[2]);
                    NewBone.RotationMatrix = WorldRotation.asMatrix;

                    // Add it
                    Result.Bones.Add(NewBone);
                }
                // Sort joints
                SortJoints(ref Result, ParentStack, Cosmetic);

                // Pre-fetch skins
                var SkinClusters = GetSkinClusters();
                var BoneMapping  = Result.GetBoneMapping();

                // A list of used materials
                int MaterialIndex = 0;
                var UsedMaterials = new Dictionary <string, int>();
                var UsedMeshes    = new HashSet <string>();

                // Iterate and add meshes
                foreach (var Mesh in ExportObjectList.DependNodes(MFn.Type.kMesh))
                {
                    // Step
                    MayaCfg.StepProgress();

                    // Grab the controller
                    var Path = GetObjectDagPath(Mesh);
                    Path.extendToShape();
                    var Controller = new MFnMesh(Path);

                    // Ignore duplicates
                    if (UsedMeshes.Contains(Path.partialPathName))
                    {
                        continue;
                    }
                    UsedMeshes.Add(Path.partialPathName);

                    // Pre-fetch materials
                    var MeshMaterials = GetMaterialsMesh(ref Controller, ref Path);
                    foreach (var Mat in MeshMaterials)
                    {
                        if (!UsedMaterials.ContainsKey(Mat.Name))
                        {
                            UsedMaterials.Add(Mat.Name, MaterialIndex++);
                            Result.Materials.Add(Mat);
                        }
                    }

                    // New mesh
                    var NewMesh = new Mesh();

                    // Grab iterators
                    var VertexIterator = new MItMeshVertex(Path);
                    var FaceIterator   = new MItMeshPolygon(Path);

                    // Get the cluster for this
                    var SkinCluster = FindSkinCluster(ref SkinClusters, Controller);
                    var SkinJoints  = new MDagPathArray();

                    if (SkinCluster != null)
                    {
                        SkinCluster.influenceObjects(SkinJoints);
                    }

                    // Build vertex array
                    for (; !VertexIterator.isDone; VertexIterator.next())
                    {
                        // Prepare
                        var NewVert = new Vertex();

                        // Grab data
                        NewVert.Position = VertexIterator.position(MSpace.Space.kWorld) * (1 / 2.54);

                        // Weights if valid
                        if (SkinCluster != null)
                        {
                            var WeightValues = new MDoubleArray();

                            uint Influence = 0;
                            SkinCluster.getWeights(Path, VertexIterator.currentItem(), WeightValues, ref Influence);

                            for (int i = 0; i < (int)WeightValues.length; i++)
                            {
                                if (WeightValues[i] < 0.000001)
                                {
                                    continue;
                                }
                                var WeightTagName = CleanNodeName(SkinJoints[i].partialPathName);
                                var WeightID      = (BoneMapping.ContainsKey(WeightTagName)) ? BoneMapping[WeightTagName] : 0;

                                NewVert.Weights.Add(new Tuple <int, float>(WeightID, (float)WeightValues[i]));
                            }
                        }
                        if (NewVert.Weights.Count == 0)
                        {
                            NewVert.Weights.Add(new Tuple <int, float>(0, 1.0f));
                        }

                        // Add it
                        NewMesh.Vertices.Add(NewVert);
                    }

                    // Build face array
                    for (; !FaceIterator.isDone; FaceIterator.next())
                    {
                        var Indices = new MIntArray();
                        var Normals = new MVectorArray();
                        var UVUs    = new MFloatArray();
                        var UVVs    = new MFloatArray();

                        FaceIterator.getVertices(Indices);
                        FaceIterator.getNormals(Normals, MSpace.Space.kWorld);
                        FaceIterator.getUVs(UVUs, UVVs);

                        // Only support TRIS/QUAD
                        if (Indices.Count < 3)
                        {
                            continue;
                        }

                        if (Indices.Count == 3)
                        {
                            // Create new face
                            var NewFace = new FaceVertex();
                            // Setup
                            NewFace.Indices[0] = Indices[0];
                            NewFace.Indices[2] = Indices[1];
                            NewFace.Indices[1] = Indices[2];

                            // Normals
                            NewFace.Normals[0] = new MVector(Normals[0][0], Normals[0][1], Normals[0][2]);
                            NewFace.Normals[2] = new MVector(Normals[1][0], Normals[1][1], Normals[1][2]);
                            NewFace.Normals[1] = new MVector(Normals[2][0], Normals[2][1], Normals[2][2]);

                            // Colors
                            FaceIterator.getColor(NewFace.Colors[0], 0);
                            FaceIterator.getColor(NewFace.Colors[2], 1);
                            FaceIterator.getColor(NewFace.Colors[1], 2);

                            // Append UV Layers
                            NewFace.UVs[0] = new Tuple <float, float>(UVUs[0], 1 - UVVs[0]);
                            NewFace.UVs[2] = new Tuple <float, float>(UVUs[1], 1 - UVVs[1]);
                            NewFace.UVs[1] = new Tuple <float, float>(UVUs[2], 1 - UVVs[2]);

                            // Set material index
                            if (MeshMaterials.Count > 0)
                            {
                                NewFace.MaterialIndex = UsedMaterials[MeshMaterials[0].Name];
                            }

                            // Add it
                            NewMesh.Faces.Add(NewFace);
                        }
                        else
                        {
                            // Create new faces
                            FaceVertex NewFace = new FaceVertex(), NewFace2 = new FaceVertex();
                            // Setup
                            NewFace.Indices[0]  = Indices[0];
                            NewFace.Indices[2]  = Indices[1];
                            NewFace.Indices[1]  = Indices[2];
                            NewFace2.Indices[0] = Indices[0];
                            NewFace2.Indices[2] = Indices[2];
                            NewFace2.Indices[1] = Indices[3];

                            // Normals
                            NewFace.Normals[0]  = new MVector(Normals[0][0], Normals[0][1], Normals[0][2]);
                            NewFace.Normals[2]  = new MVector(Normals[1][0], Normals[1][1], Normals[1][2]);
                            NewFace.Normals[1]  = new MVector(Normals[2][0], Normals[2][1], Normals[2][2]);
                            NewFace2.Normals[0] = new MVector(Normals[0][0], Normals[0][1], Normals[0][2]);
                            NewFace2.Normals[2] = new MVector(Normals[2][0], Normals[2][1], Normals[2][2]);
                            NewFace2.Normals[1] = new MVector(Normals[3][0], Normals[3][1], Normals[3][2]);

                            // Colors
                            FaceIterator.getColor(NewFace.Colors[0], 0);
                            FaceIterator.getColor(NewFace.Colors[2], 1);
                            FaceIterator.getColor(NewFace.Colors[1], 2);
                            FaceIterator.getColor(NewFace2.Colors[0], 0);
                            FaceIterator.getColor(NewFace2.Colors[2], 2);
                            FaceIterator.getColor(NewFace2.Colors[1], 3);

                            // Append UV Layers
                            NewFace.UVs[0]  = new Tuple <float, float>(UVUs[0], 1 - UVVs[0]);
                            NewFace.UVs[2]  = new Tuple <float, float>(UVUs[1], 1 - UVVs[1]);
                            NewFace.UVs[1]  = new Tuple <float, float>(UVUs[2], 1 - UVVs[2]);
                            NewFace2.UVs[0] = new Tuple <float, float>(UVUs[0], 1 - UVVs[0]);
                            NewFace2.UVs[2] = new Tuple <float, float>(UVUs[2], 1 - UVVs[2]);
                            NewFace2.UVs[1] = new Tuple <float, float>(UVUs[3], 1 - UVVs[3]);

                            // Set material index
                            if (MeshMaterials.Count > 0)
                            {
                                NewFace.MaterialIndex  = UsedMaterials[MeshMaterials[0].Name];
                                NewFace2.MaterialIndex = UsedMaterials[MeshMaterials[0].Name];
                            }

                            // Add it
                            NewMesh.Faces.Add(NewFace);
                            NewMesh.Faces.Add(NewFace2);
                        }
                    }

                    // Add it
                    Result.Meshes.Add(NewMesh);
                }

                // Write
                switch (FileType)
                {
                case XModelType.Export:
                    Result.WriteExport(FilePath);
                    break;

                case XModelType.Bin:
                    Result.WriteBin(FilePath);
                    break;
                }
            }

            // Log complete
            MGlobal.displayInfo(string.Format("[CODTools] Exported {0}", System.IO.Path.GetFileName(FilePath)));
        }
Example #9
0
        /// <summary>
        /// Get TRS and visiblity animations of the transform
        /// </summary>
        /// <param name="transform">Transform above mesh/camera/light</param>
        /// <returns></returns>
        private List <BabylonAnimation> GetAnimation(MFnTransform transform)
        {
            // Animations
            MPlugArray   connections  = new MPlugArray();
            MStringArray animCurvList = new MStringArray();
            MIntArray    keysTime     = new MIntArray();
            MDoubleArray keysValue    = new MDoubleArray();

            MFloatArray translateValues  = new MFloatArray();
            MFloatArray rotateValues     = new MFloatArray();
            MFloatArray scaleValues      = new MFloatArray();
            MFloatArray visibilityValues = new MFloatArray();
            MFloatArray keyTimes         = new MFloatArray();

            List <BabylonAnimationKey> keys             = new List <BabylonAnimationKey>();
            List <BabylonAnimation>    animationsObject = new List <BabylonAnimation>();

            //Get the animCurve
            MGlobal.executeCommand("listConnections -type \"animCurve\" " + transform.fullPathName + ";", animCurvList);

            List <AnimCurvData> animCurvesData = new List <AnimCurvData>();

            foreach (String animCurv in animCurvList)
            {
                AnimCurvData animCurvData = new AnimCurvData();
                animCurvesData.Add(animCurvData);

                animCurvData.animCurv = animCurv;

                //Get the key time for each curves
                MGlobal.executeCommand("keyframe -q " + animCurv + ";", keysTime);

                //Get the value for each curves
                MGlobal.executeCommand("keyframe - q -vc -absolute " + animCurv + ";", keysValue);

                if (animCurv.EndsWith("translateZ") || animCurv.EndsWith("rotateX") || animCurv.EndsWith("rotateY"))
                {
                    for (int index = 0; index < keysTime.Count; index++)
                    {
                        // Switch coordinate system at object level
                        animCurvData.valuePerFrame.Add(keysTime[index], (float)keysValue[index] * -1.0f);
                    }
                }
                else
                {
                    for (int index = 0; index < keysTime.Count; index++)
                    {
                        animCurvData.valuePerFrame.Add(keysTime[index], (float)keysValue[index]);
                    }
                }
            }

            string[] mayaAnimationProperties    = new string[] { "translate", "rotate", "scale" };
            string[] babylonAnimationProperties = new string[] { "position", "rotationQuaternion", "scaling" };
            string[] axis = new string[] { "X", "Y", "Z" };

            // Init TRS default values
            Dictionary <string, float> defaultValues = new Dictionary <string, float>();

            float[] position           = null;
            float[] rotationQuaternion = null;
            float[] rotation           = null;
            float[] scaling            = null;
            GetTransform(transform, ref position, ref rotationQuaternion, ref rotation, ref scaling); // coordinate system already switched
            defaultValues.Add("translateX", position[0]);
            defaultValues.Add("translateY", position[1]);
            defaultValues.Add("translateZ", position[2]);
            defaultValues.Add("rotateX", rotation[0]);
            defaultValues.Add("rotateY", rotation[1]);
            defaultValues.Add("rotateZ", rotation[2]);
            defaultValues.Add("scaleX", scaling[0]);
            defaultValues.Add("scaleY", scaling[1]);
            defaultValues.Add("scaleZ", scaling[2]);

            for (int indexAnimationProperty = 0; indexAnimationProperty < mayaAnimationProperties.Length; indexAnimationProperty++)
            {
                string mayaAnimationProperty = mayaAnimationProperties[indexAnimationProperty];

                // Retreive animation curves data for current animation property
                // Ex: all "translate" data are "translateX", "translateY", "translateZ"
                List <AnimCurvData> animDataProperty = animCurvesData.Where(data => data.animCurv.Contains(mayaAnimationProperty)).ToList();

                if (animDataProperty.Count == 0)
                {
                    // Property is not animated
                    continue;
                }

                // Get all frames for this property
                List <int> framesProperty = new List <int>();
                foreach (var animData in animDataProperty)
                {
                    framesProperty.AddRange(animData.valuePerFrame.Keys);
                }
                framesProperty = framesProperty.Distinct().ToList();
                framesProperty.Sort();

                // Get default values for this property
                BabylonAnimationKey lastBabylonAnimationKey = new BabylonAnimationKey();
                lastBabylonAnimationKey.frame  = 0;
                lastBabylonAnimationKey.values = new float[] { defaultValues[mayaAnimationProperty + "X"], defaultValues[mayaAnimationProperty + "Y"], defaultValues[mayaAnimationProperty + "Z"] };

                // Compute all values for this property
                List <BabylonAnimationKey> babylonAnimationKeys = new List <BabylonAnimationKey>();
                foreach (var frameProperty in framesProperty)
                {
                    BabylonAnimationKey babylonAnimationKey = new BabylonAnimationKey();
                    babylonAnimationKeys.Add(babylonAnimationKey);

                    // Frame
                    babylonAnimationKey.frame = frameProperty;

                    // Values
                    float[] valuesProperty = new float[3];
                    for (int indexAxis = 0; indexAxis < axis.Length; indexAxis++)
                    {
                        AnimCurvData animCurvDataAxis = animDataProperty.Find(data => data.animCurv.EndsWith(axis[indexAxis]));

                        float value;
                        if (animCurvDataAxis != null && animCurvDataAxis.valuePerFrame.ContainsKey(frameProperty))
                        {
                            value = animCurvDataAxis.valuePerFrame[frameProperty];
                        }
                        else
                        {
                            value = lastBabylonAnimationKey.values[indexAxis];
                        }
                        valuesProperty[indexAxis] = value;
                    }
                    babylonAnimationKey.values = valuesProperty.ToArray();

                    // Update last known values
                    lastBabylonAnimationKey = babylonAnimationKey;
                }

                // Convert euler to quaternion angles
                if (indexAnimationProperty == 1) // Rotation
                {
                    foreach (var babylonAnimationKey in babylonAnimationKeys)
                    {
                        BabylonVector3    eulerAngles      = BabylonVector3.FromArray(babylonAnimationKey.values);
                        BabylonQuaternion quaternionAngles = eulerAngles.toQuaternion();
                        babylonAnimationKey.values = quaternionAngles.ToArray();
                    }
                }

                var keysFull = new List <BabylonAnimationKey>(babylonAnimationKeys);

                // Optimization
                OptimizeAnimations(babylonAnimationKeys, true);

                // Ensure animation has at least 2 frames
                if (IsAnimationKeysRelevant(keys))
                {
                    // Create BabylonAnimation
                    string babylonAnimationProperty = babylonAnimationProperties[indexAnimationProperty];
                    animationsObject.Add(new BabylonAnimation()
                    {
                        dataType       = indexAnimationProperty == 1 ? (int)BabylonAnimation.DataType.Quaternion : (int)BabylonAnimation.DataType.Vector3,
                        name           = babylonAnimationProperty + " animation",
                        framePerSecond = 30,
                        loopBehavior   = (int)BabylonAnimation.LoopBehavior.Cycle,
                        property       = babylonAnimationProperty,
                        keys           = babylonAnimationKeys.ToArray(),
                        keysFull       = keysFull
                    });
                }
            }

            return(animationsObject);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="mDagPath">DAG path to the transform above mesh</param>
        /// <param name="babylonScene"></param>
        /// <returns></returns>
        private BabylonNode ExportMesh(MDagPath mDagPath, BabylonScene babylonScene)
        {
            RaiseMessage(mDagPath.partialPathName, 1);

            // Transform above mesh
            mFnTransform = new MFnTransform(mDagPath);

            // Mesh direct child of the transform
            // TODO get the original one rather than the modified?
            MFnMesh mFnMesh = null;

            for (uint i = 0; i < mFnTransform.childCount; i++)
            {
                MObject childObject = mFnTransform.child(i);
                if (childObject.apiType == MFn.Type.kMesh)
                {
                    var _mFnMesh = new MFnMesh(childObject);
                    if (!_mFnMesh.isIntermediateObject)
                    {
                        mFnMesh = _mFnMesh;
                    }
                }
            }
            if (mFnMesh == null)
            {
                RaiseError("No mesh found has child of " + mDagPath.fullPathName);
                return(null);
            }

            RaiseMessage("mFnMesh.fullPathName=" + mFnMesh.fullPathName, 2);

            // --- prints ---
            #region prints

            Action <MFnDagNode> printMFnDagNode = (MFnDagNode mFnDagNode) =>
            {
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.name=" + mFnDagNode.name, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.absoluteName=" + mFnDagNode.absoluteName, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.fullPathName=" + mFnDagNode.fullPathName, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.partialPathName=" + mFnDagNode.partialPathName, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.activeColor=" + mFnDagNode.activeColor.toString(), 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.attributeCount=" + mFnDagNode.attributeCount, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.childCount=" + mFnDagNode.childCount, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.dormantColor=" + mFnDagNode.dormantColor, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.hasUniqueName=" + mFnDagNode.hasUniqueName, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.inUnderWorld=" + mFnDagNode.inUnderWorld, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isDefaultNode=" + mFnDagNode.isDefaultNode, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isInstanceable=" + mFnDagNode.isInstanceable, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isInstanced(true)=" + mFnDagNode.isInstanced(true), 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isInstanced(false)=" + mFnDagNode.isInstanced(false), 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isInstanced()=" + mFnDagNode.isInstanced(), 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.instanceCount(true)=" + mFnDagNode.instanceCount(true), 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.instanceCount(false)=" + mFnDagNode.instanceCount(false), 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isIntermediateObject=" + mFnDagNode.isIntermediateObject, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.isShared=" + mFnDagNode.isShared, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.objectColor=" + mFnDagNode.objectColor, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.parentCount=" + mFnDagNode.parentCount, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.parentNamespace=" + mFnDagNode.parentNamespace, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.uuid().asString()=" + mFnDagNode.uuid().asString(), 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.dagRoot().apiType=" + mFnDagNode.dagRoot().apiType, 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.model.equalEqual(mFnDagNode.objectProperty)=" + mFnDagNode.model.equalEqual(mFnDagNode.objectProperty), 3);
                RaiseVerbose("BabylonExporter.Mesh | mFnDagNode.transformationMatrix.toString()=" + mFnDagNode.transformationMatrix.toString(), 3);
            };

            Action <MFnMesh> printMFnMesh = (MFnMesh _mFnMesh) =>
            {
                printMFnDagNode(mFnMesh);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numVertices=" + _mFnMesh.numVertices, 3);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numEdges=" + _mFnMesh.numEdges, 3);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numPolygons=" + _mFnMesh.numPolygons, 3);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numFaceVertices=" + _mFnMesh.numFaceVertices, 3);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numNormals=" + _mFnMesh.numNormals, 3);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numUVSets=" + _mFnMesh.numUVSets, 3);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numUVsProperty=" + _mFnMesh.numUVsProperty, 3);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.displayColors=" + _mFnMesh.displayColors, 3);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numColorSets=" + _mFnMesh.numColorSets, 3);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.numColorsProperty=" + _mFnMesh.numColorsProperty, 3);
                RaiseVerbose("BabylonExporter.Mesh | _mFnMesh.currentUVSetName()=" + _mFnMesh.currentUVSetName(), 3);

                var _uvSetNames = new MStringArray();
                mFnMesh.getUVSetNames(_uvSetNames);
                foreach (var uvSetName in _uvSetNames)
                {
                    RaiseVerbose("BabylonExporter.Mesh | uvSetName=" + uvSetName, 3);
                    RaiseVerbose("BabylonExporter.Mesh | mFnMesh.numUVs(uvSetName)=" + mFnMesh.numUVs(uvSetName), 4);
                    MFloatArray us = new MFloatArray();
                    MFloatArray vs = new MFloatArray();
                    mFnMesh.getUVs(us, vs, uvSetName);
                    RaiseVerbose("BabylonExporter.Mesh | us.Count=" + us.Count, 4);
                }
            };

            Action <MFnTransform> printMFnTransform = (MFnTransform _mFnMesh) =>
            {
                printMFnDagNode(mFnMesh);
            };

            RaiseVerbose("BabylonExporter.Mesh | mFnMesh data", 2);
            printMFnMesh(mFnMesh);

            RaiseVerbose("BabylonExporter.Mesh | mFnTransform data", 2);
            printMFnTransform(mFnTransform);

            Print(mFnTransform, 2, "Print ExportMesh mFnTransform");

            Print(mFnMesh, 2, "Print ExportMesh mFnMesh");

            //// Geometry
            //MIntArray triangleCounts = new MIntArray();
            //MIntArray trianglesVertices = new MIntArray();
            //mFnMesh.getTriangles(triangleCounts, trianglesVertices);
            //RaiseVerbose("BabylonExporter.Mesh | triangleCounts.ToArray()=" + triangleCounts.ToArray().toString(), 3);
            //RaiseVerbose("BabylonExporter.Mesh | trianglesVertices.ToArray()=" + trianglesVertices.ToArray().toString(), 3);
            //int[] polygonsVertexCount = new int[mFnMesh.numPolygons];
            //for (int polygonId = 0; polygonId < mFnMesh.numPolygons; polygonId++)
            //{
            //    polygonsVertexCount[polygonId] = mFnMesh.polygonVertexCount(polygonId);
            //}
            //RaiseVerbose("BabylonExporter.Mesh | polygonsVertexCount=" + polygonsVertexCount.toString(), 3);

            ////MFloatPointArray points = new MFloatPointArray();
            ////mFnMesh.getPoints(points);
            ////RaiseVerbose("BabylonExporter.Mesh | points.ToArray()=" + points.ToArray().Select(mFloatPoint => mFloatPoint.toString()), 3);

            ////MFloatVectorArray normals = new MFloatVectorArray();
            ////mFnMesh.getNormals(normals);
            ////RaiseVerbose("BabylonExporter.Mesh | normals.ToArray()=" + normals.ToArray().Select(mFloatPoint => mFloatPoint.toString()), 3);

            //for (int polygonId = 0; polygonId < mFnMesh.numPolygons; polygonId++)
            //{
            //    MIntArray verticesId = new MIntArray();
            //    RaiseVerbose("BabylonExporter.Mesh | polygonId=" + polygonId, 3);

            //    int nbTriangles = triangleCounts[polygonId];
            //    RaiseVerbose("BabylonExporter.Mesh | nbTriangles=" + nbTriangles, 3);

            //    for (int triangleIndex = 0; triangleIndex < triangleCounts[polygonId]; triangleIndex++)
            //    {
            //        RaiseVerbose("BabylonExporter.Mesh | triangleIndex=" + triangleIndex, 3);
            //        int[] triangleVertices = new int[3];
            //        mFnMesh.getPolygonTriangleVertices(polygonId, triangleIndex, triangleVertices);
            //        RaiseVerbose("BabylonExporter.Mesh | triangleVertices=" + triangleVertices.toString(), 3);

            //        foreach (int vertexId in triangleVertices)
            //        {
            //            RaiseVerbose("BabylonExporter.Mesh | vertexId=" + vertexId, 3);
            //            MPoint point = new MPoint();
            //            mFnMesh.getPoint(vertexId, point);
            //            RaiseVerbose("BabylonExporter.Mesh | point=" + point.toString(), 3);

            //            MVector normal = new MVector();
            //            mFnMesh.getFaceVertexNormal(polygonId, vertexId, normal);
            //            RaiseVerbose("BabylonExporter.Mesh | normal=" + normal.toString(), 3);
            //        }
            //    }
            //}

            #endregion

            if (IsMeshExportable(mFnMesh, mDagPath) == false)
            {
                return(null);
            }

            var babylonMesh = new BabylonMesh {
                name       = mFnTransform.name,
                id         = mFnTransform.uuid().asString(),
                visibility = Loader.GetVisibility(mFnTransform.fullPathName)
            };

            // Instance
            // For a mesh with instances, we distinguish between master and instance meshes:
            //      - a master mesh stores all the info of the mesh (transform, hierarchy, animations + vertices, indices, materials, bones...)
            //      - an instance mesh only stores the info of the node (transform, hierarchy, animations)

            // Check if this mesh has already been exported as a master mesh
            BabylonMesh babylonMasterMesh = GetMasterMesh(mFnMesh, babylonMesh);
            if (babylonMasterMesh != null)
            {
                RaiseMessage($"The master mesh {babylonMasterMesh.name} was already exported. This one will be exported as an instance.", 2);

                // Export this node as instance
                var babylonInstanceMesh = new BabylonAbstractMesh {
                    name = mFnTransform.name, id = mFnTransform.uuid().asString()
                };

                //// Add instance to master mesh
                List <BabylonAbstractMesh> instances = babylonMasterMesh.instances != null?babylonMasterMesh.instances.ToList() : new List <BabylonAbstractMesh>();

                instances.Add(babylonInstanceMesh);
                babylonMasterMesh.instances = instances.ToArray();

                // Export transform / hierarchy / animations
                ExportNode(babylonInstanceMesh, mFnTransform, babylonScene);

                // Animations
                ExportNodeAnimation(babylonInstanceMesh, mFnTransform);

                return(babylonInstanceMesh);
            }

            // Position / rotation / scaling / hierarchy
            ExportNode(babylonMesh, mFnTransform, babylonScene);

            // Misc.
            // TODO - Retreive from Maya
            //babylonMesh.receiveShadows = meshNode.MaxNode.RcvShadows == 1;
            //babylonMesh.applyFog = meshNode.MaxNode.ApplyAtmospherics == 1;

            if (mFnMesh.numPolygons < 1)
            {
                RaiseError($"Mesh {babylonMesh.name} has no face", 2);
            }

            if (mFnMesh.numVertices < 3)
            {
                RaiseError($"Mesh {babylonMesh.name} has not enough vertices", 2);
            }

            if (mFnMesh.numVertices >= 65536)
            {
                RaiseWarning($"Mesh {babylonMesh.name} has more than 65536 vertices which means that it will require specific WebGL extension to be rendered. This may impact portability of your scene on low end devices.", 2);
            }

            // Animations
            ExportNodeAnimation(babylonMesh, mFnTransform);

            // Material
            MObjectArray shaders = new MObjectArray();
            mFnMesh.getConnectedShaders(0, shaders, new MIntArray());
            if (shaders.Count > 0)
            {
                List <MFnDependencyNode> materials = new List <MFnDependencyNode>();
                foreach (MObject shader in shaders)
                {
                    // Retreive material
                    MFnDependencyNode shadingEngine      = new MFnDependencyNode(shader);
                    MPlug             mPlugSurfaceShader = shadingEngine.findPlug("surfaceShader");
                    MObject           materialObject     = mPlugSurfaceShader.source.node;
                    MFnDependencyNode material           = new MFnDependencyNode(materialObject);

                    materials.Add(material);
                }

                if (shaders.Count == 1)
                {
                    MFnDependencyNode material = materials[0];

                    // Material is referenced by id
                    babylonMesh.materialId = material.uuid().asString();

                    // Register material for export if not already done
                    if (!referencedMaterials.Contains(material, new MFnDependencyNodeEqualityComparer()))
                    {
                        referencedMaterials.Add(material);
                    }
                }
                else
                {
                    // Create a new id for the group of sub materials
                    string uuidMultiMaterial = GetMultimaterialUUID(materials);

                    // Multi material is referenced by id
                    babylonMesh.materialId = uuidMultiMaterial;

                    // Register multi material for export if not already done
                    if (!multiMaterials.ContainsKey(uuidMultiMaterial))
                    {
                        multiMaterials.Add(uuidMultiMaterial, materials);
                    }
                }
            }

            var vertices = new List <GlobalVertex>();
            var indices  = new List <int>();

            var uvSetNames = new MStringArray();
            mFnMesh.getUVSetNames(uvSetNames);
            bool[] isUVExportSuccess = new bool[Math.Min(uvSetNames.Count, 2)];
            for (int indexUVSet = 0; indexUVSet < isUVExportSuccess.Length; indexUVSet++)
            {
                isUVExportSuccess[indexUVSet] = true;
            }

            // skin
            if (_exportSkin)
            {
                mFnSkinCluster = getMFnSkinCluster(mFnMesh);
            }
            int maxNbBones = 0;
            if (mFnSkinCluster != null)
            {
                RaiseMessage($"mFnSkinCluster.name | {mFnSkinCluster.name}", 2);
                Print(mFnSkinCluster, 3, $"Print {mFnSkinCluster.name}");

                // Get the bones dictionary<name, index> => it represents all the bones in the skeleton
                indexByNodeName = GetIndexByFullPathNameDictionary(mFnSkinCluster);

                // Get the joint names that influence this mesh
                allMayaInfluenceNames = GetBoneFullPathName(mFnSkinCluster, mFnTransform);

                // Get the max number of joints acting on a vertex
                int maxNumInfluences = GetMaxInfluence(mFnSkinCluster, mFnTransform, mFnMesh);

                RaiseMessage($"Max influences : {maxNumInfluences}", 2);
                if (maxNumInfluences > 8)
                {
                    RaiseWarning($"Too many bones influences per vertex: {maxNumInfluences}. Babylon.js only support up to 8 bones influences per vertex.", 2);
                    RaiseWarning("The result may not be as expected.", 2);
                }
                maxNbBones = Math.Min(maxNumInfluences, 8);

                if (indexByNodeName != null && allMayaInfluenceNames != null)
                {
                    babylonMesh.skeletonId = GetSkeletonIndex(mFnSkinCluster);
                }
                else
                {
                    mFnSkinCluster = null;
                }
            }
            // Export tangents if option is checked and mesh have tangents
            bool isTangentExportSuccess = _exportTangents;

            // TODO - color, alpha
            //var hasColor = unskinnedMesh.NumberOfColorVerts > 0;
            //var hasAlpha = unskinnedMesh.GetNumberOfMapVerts(-2) > 0;

            // TODO - Add custom properties
            //var optimizeVertices = false; // meshNode.MaxNode.GetBoolProperty("babylonjs_optimizevertices");
            var optimizeVertices = _optimizeVertices; // global option

            // Compute normals
            var subMeshes = new List <BabylonSubMesh>();
            ExtractGeometry(mFnMesh, vertices, indices, subMeshes, uvSetNames, ref isUVExportSuccess, ref isTangentExportSuccess, optimizeVertices);

            if (vertices.Count >= 65536)
            {
                RaiseWarning($"Mesh {babylonMesh.name} has {vertices.Count} vertices. This may prevent your scene to work on low end devices where 32 bits indice are not supported", 2);

                if (!optimizeVertices)
                {
                    RaiseError("You can try to optimize your object using [Try to optimize vertices] option", 2);
                }
            }

            for (int indexUVSet = 0; indexUVSet < isUVExportSuccess.Length; indexUVSet++)
            {
                string uvSetName = uvSetNames[indexUVSet];
                // If at least one vertex is mapped to an UV coordinate but some have failed to be exported
                if (isUVExportSuccess[indexUVSet] == false && mFnMesh.numUVs(uvSetName) > 0)
                {
                    RaiseWarning($"Failed to export UV set named {uvSetName}. Ensure all vertices are mapped to a UV coordinate.", 2);
                }
            }

            RaiseMessage($"{vertices.Count} vertices, {indices.Count / 3} faces", 2);

            // Buffers
            babylonMesh.positions = vertices.SelectMany(v => v.Position).ToArray();
            babylonMesh.normals   = vertices.SelectMany(v => v.Normal).ToArray();

            // export the skin
            if (mFnSkinCluster != null)
            {
                babylonMesh.matricesWeights = vertices.SelectMany(v => v.Weights.ToArray()).ToArray();
                babylonMesh.matricesIndices = vertices.Select(v => v.BonesIndices).ToArray();

                babylonMesh.numBoneInfluencers = maxNbBones;
                if (maxNbBones > 4)
                {
                    babylonMesh.matricesWeightsExtra = vertices.SelectMany(v => v.WeightsExtra != null ? v.WeightsExtra.ToArray() : new[] { 0.0f, 0.0f, 0.0f, 0.0f }).ToArray();
                    babylonMesh.matricesIndicesExtra = vertices.Select(v => v.BonesIndicesExtra).ToArray();
                }
            }

            // Tangent
            if (isTangentExportSuccess)
            {
                babylonMesh.tangents = vertices.SelectMany(v => v.Tangent).ToArray();
            }
            // Color
            string colorSetName;
            mFnMesh.getCurrentColorSetName(out colorSetName);
            if (mFnMesh.numColors(colorSetName) > 0)
            {
                babylonMesh.colors = vertices.SelectMany(v => v.Color).ToArray();
            }
            // UVs
            if (uvSetNames.Count > 0 && isUVExportSuccess[0])
            {
                babylonMesh.uvs = vertices.SelectMany(v => v.UV).ToArray();
            }
            if (uvSetNames.Count > 1 && isUVExportSuccess[1])
            {
                babylonMesh.uvs2 = vertices.SelectMany(v => v.UV2).ToArray();
            }

            babylonMesh.subMeshes = subMeshes.ToArray();

            // Buffers - Indices
            babylonMesh.indices = indices.ToArray();


            babylonScene.MeshesList.Add(babylonMesh);
            RaiseMessage("BabylonExporter.Mesh | done", 2);

            return(babylonMesh);
        }
        public override void writeFloatArray(MFloatArray array)
        {
            if (myCurrentChanelNode != null)
            {
                uint size = array.length;
                XmlNode sizeNode = myXmlDoc.CreateElement(sizeTag);
                sizeNode.InnerText = Convert.ToString(size);
                myCurrentChanelNode.AppendChild(sizeNode);

                XmlNode arrayNode = myXmlDoc.CreateElement(floatArrayTag);
                myCurrentChanelNode.AppendChild(arrayNode);

                for (int i = 0; i < size; i++)
                {
                    string value = array[i].ToString();
                    XmlNode valueNode = myXmlDoc.CreateElement("value");
                    arrayNode.AppendChild(valueNode);
                }
            }

            return;
        }
        public override void readFloatArray(MFloatArray array, uint size)
        {
            Trace.Assert(myCurrentChanelNode != null);

            XmlNode floatArrayNode = myCurrentChanelNode.SelectSingleNode(floatArrayTag);
            XmlNodeList valueNodeList = floatArrayNode.SelectNodes("value");
            array.clear();
            array.length = size;
            foreach (XmlNode valueNode in valueNodeList)
            {
                double value = Convert.ToDouble(valueNode.InnerText);
                array.append((float)value);
            }
            return;
        }
        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();
            }
        }
Example #14
0
        unsafe public override void getTweakedUVs(MObject meshObj, MIntArray uvList, MFloatArray uPos, MFloatArray vPos)
        {
            int         i      = 0;
            MFloatArray uArray = new MFloatArray();
            MFloatArray vArray = new MFloatArray();
            MFnMesh     mesh   = new MFnMesh(meshObj);

            mesh.getUVs(uArray, vArray);

            uint      nbUvShells = 0;
            MIntArray uvShellIds = new MIntArray();

            if ((!flipGlobal) || extendToShell)
            {
                // First, extract the UV shells.
                mesh.getUvShellsIds(uvShellIds, ref nbUvShells);
            }

            if (extendToShell)
            {
                bool[] selected = new bool[nbUvShells];
                for (i = 0; i < nbUvShells; i++)
                {
                    selected[i] = false;
                }

                for (i = 0; i < nbUvShells; i++)
                {
                    int index = uvList[i];
                    index           = uvShellIds[index];
                    selected[index] = true;
                }

                uint numUvs    = (uint)mesh.numUVsProperty;
                uint numSelUvs = 0;

                // Preallocate a buffer, large enough to hold all Ids. This
                // prevents multiple reallocation from happening when growing
                // the array.
                uvList.length = numUvs;

                for (i = 0; i < numUvs; i++)
                {
                    int index = uvShellIds[i];
                    if (selected[index])
                    {
                        uvList.set((int)i, numSelUvs);
                        numSelUvs++;
                    }
                }

                // clamp the array to the proper size.
                uvList.length = numSelUvs;
            }

            int nbUvShellsInt = (int)nbUvShells;

            // For global flips, just pretend there is only one shell
            if (flipGlobal)
            {
                nbUvShellsInt = 1;
            }

            float[] minMax = new float[nbUvShellsInt * 4];

            for (i = 0; i < nbUvShellsInt; i++)
            {
                minMax[4 * i + 0] = 1e30F;                              // Min U
                minMax[4 * i + 1] = 1e30F;                              // Min V
                minMax[4 * i + 2] = -1e30F;                             // Max U
                minMax[4 * i + 3] = -1e30F;                             // Max V
            }

            // Get the bounding box of the UVs, for each shell if flipGlobal
            // is true, or for the whole selection if false.
            for (i = 0; i < uvList.length; i++)
            {
                int indx    = uvList[i];
                int shellId = 0;

                if (!flipGlobal)
                {
                    shellId = uvShellIds[indx];
                }

                float value = uArray[indx];

                if (value < minMax[4 * shellId + 0])
                {
                    minMax[4 * shellId + 0] = value;
                }

                value = vArray[indx];
                if (value < minMax[4 * shellId + 1])
                {
                    minMax[4 * shellId + 1] = value;
                }

                value = uArray[indx];
                if (value > minMax[4 * shellId + 2])
                {
                    minMax[4 * shellId + 2] = value;
                }

                value = vArray[indx];
                if (value > minMax[4 * shellId + 3])
                {
                    minMax[4 * shellId + 3] = value;
                }
            }

            // Adjust the size of the output arrays
            uPos.length = uvList.length;
            vPos.length = uvList.length;

            for (i = 0; i < uvList.length; i++)
            {
                int shellId = 0;

                int indx = uvList[i];

                if (!flipGlobal)
                {
                    shellId = uvShellIds[indx];
                }

                // Flip U or V along the bounding box center.
                if (horizontal)
                {
                    float value = uArray[indx];
                    value = minMax[4 * shellId + 0] + minMax[4 * shellId + 2] - value;

                    uPos.set(value, (uint)i);
                    value = vArray[indx];
                    vPos.set(value, (uint)i);
                }
                else
                {
                    float value = uArray[indx];
                    uPos.set(value, (uint)i);

                    value = vArray[indx];
                    value = minMax[4 * shellId + 1] + minMax[4 * shellId + 3] - value;
                    vPos.set(value, (uint)i);
                }
            }
            return;
        }