Exemple #1
0
        public static ITriObject GetTriObjectFromNode(this IINode node, int time, out bool deleteIt)
        {
            deleteIt = false;
            IObject obj = node.EvalWorldState(time, true).Obj;

            IClass_ID triObjId = MaxGlobal.Class_ID.Create((int)BuiltInClassIDA.TRIOBJ_CLASS_ID, 0);

            if (obj.CanConvertToType(triObjId) != 0)
            {
                ITriObject tri = (ITriObject)obj.ConvertToType(time, triObjId);

                // Note that the TriObject should only be deleted
                // if the pointer to it is not equal to the object
                // pointer that called ConvertToType()
                if (obj != tri)
                {
                    deleteIt = true;
                }
                return(tri);
            }
            else
            {
                return(null);
            }
        }
Exemple #2
0
        public static IMesh GetMesh(this IObject obj)
        {
            if (obj.CanConvertToType(ClassID.TriObject._IClass_ID) == 0)
                return null;

            var tri = obj.ConvertToType(0, ClassID.TriObject._IClass_ID) as ITriObject;
            return tri == null ? null : tri.Mesh;
        }
Exemple #3
0
        public static ITriObject GetMesh(this IObject obj)
        {
            var triObjectClassId = Loader.Global.Class_ID.Create(0x0009, 0);

            if (obj.CanConvertToType(triObjectClassId) == 0)
                return null;

            return obj.ConvertToType(0, triObjectClassId) as ITriObject;
        }
Exemple #4
0
        public static IPolyObject GetPolyObjectFromNode(this IINode iNode)
        {
            IObject obj = iNode.EvalWorldState(Loader.Core.Time, false).Obj;

            if (obj.CanConvertToType(Loader.Global.PolyObjectClassID) == 1)
            {
                return((IPolyObject)obj.ConvertToType(Loader.Core.Time, Loader.Global.PolyObjectClassID));
            }
            return(null);
        }
Exemple #5
0
        /// <summary>
        /// convert the actual node to editable mesh
        /// </summary>
        public void ConvertToMesh()
        {
            if (!this.IsValid)
            {
                return;
            }

            // get the current node world state
            IObjectState state = this.m_node.EvalWorldState(AssemblyFunctions.Core.Time, false);

            // get the object out of the state and check if it's possible to convert to editable mesh
            IObject obj = state.Obj;

            if (obj.CanConvertToType(AssemblyFunctions.GlobalInterface.TriObjectClassID) == 0)
            {
                return;
            }

            // convert the obj to triobject
            // if the node type was editable mesh, tit will return just the current node mesh
            // elsewhere it will return a new triobj instance which is not bound to anything
            ITriObject tri = obj.ConvertToType(AssemblyFunctions.Core.Time, AssemblyFunctions.GlobalInterface.TriObjectClassID) as ITriObject;

            // check if we got something
            if (tri == null)
            {
                return;
            }

            // remeber the obj and mesh for later use
            this.m_triMesh    = tri.Mesh;
            this.m_baseObject = obj;

            // check if the tri is identical with the current object from the node state
            // if the node was already editable mesh we don't need to do anything
            if (this.m_triMesh == null || tri.Equals((INoncopyable)obj))
            {
                return;
            }

            // notfiy all dependents
            // this notfiy was from a max sample. not sure why call first before change and call change afterwards
            this.m_node.NotifyDependents(Globals.FOREVER, Globals.PART_ALL, RefMessage.Change);

            // the the object reference of the node to the new triobj
            // important: if you exchange the object ref ith the same objref
            // like this.m_node.ObjectRef = this.m_node.ObjectRef you will produce a nice crash sometimes
            // the property setter inside max.net will delete the old reference and since the old is the new
            // the reference will be set to null which is illegal
            this.m_node.ObjectRef = tri;

            // notfiy all dependents
            this.m_node.NotifyDependents(Globals.FOREVER, 0, RefMessage.SubanimStructureChanged);
            this.m_node.NotifyDependents(Globals.FOREVER, Globals.PART_ALL, RefMessage.Change);
        }
Exemple #6
0
        /// <summary>
        /// collect and fill the property base on the trimesh
        /// </summary>
        public void CollectTriMeshData()
        {
            if (!this.IsValid)
            {
                return;
            }

            // get the current node world state
            IObjectState state = this.m_node.EvalWorldState(AssemblyFunctions.Core.Time, false);

            // get the object out of the state and check if it's possible to convert to editable mesh
            IObject obj = state.Obj;

            if (obj.CanConvertToType(AssemblyFunctions.GlobalInterface.TriObjectClassID) == 0)
            {
                return;
            }

            // convert the obj to triobject
            // if the node type was editable mesh, tit will return just the current node mesh
            // elsewhere it will return a new triobj instance which is not bound to anything
            ITriObject tri = obj.ConvertToType(AssemblyFunctions.Core.Time, AssemblyFunctions.GlobalInterface.TriObjectClassID) as ITriObject;

            if (tri == null)
            {
                return;
            }

            this.m_iNumVerts = tri.Mesh.NumVerts;
            this.m_iNumTris  = tri.Mesh.NumFaces;

            // check if triobj is identical with the object from the node
            // if its not the same we got a new mesh so delete it
            if (!tri.Equals((INoncopyable)obj))
            {
                tri.DeleteMe();
            }
        }
        /// <summary>
        /// This is the routine to convert the input node to polygon faces.
        /// </summary>
        /// <param name="nodeHandle"> Input the node by handle. </param>
        /// <param name="convertToTri"> Input whether to convert to a poly object first. </param>
        /// <param name="addShell"> Input whether to add the shell modifier when finished converting to face. </param>
        /// <param name="shell"> Input the shell thickness amount. </param>
        /// <param name="addEditMesh"> Input whether to add the Edit Mesh modifier when finished converting to face. </param>
        /// <param name="collapseNode"> Input whether to collapse the node afterwards. </param>
        /// <param name="centerPivot"> Input whether to center the pivot on each new face. </param>
        /// <returns> Returns 1 if successful or -1 if not. </returns>
        static public int ConvertToPolygonFaces(uint nodeHandle,
                                                bool convertToPoly = true, // C# now supports default parameters
                                                bool addShell      = true,
                                                float shell        = 0.1f,
                                                bool addEditMesh   = true,
                                                bool collapseNode  = true,
                                                bool centerPivot   = true)
        {
            try
            {
                IGlobal      global = Autodesk.Max.GlobalInterface.Instance;
                IInterface14 ip     = global.COREInterface14;

                IINode node = ip.GetINodeByHandle(nodeHandle);
                if (node == null)
                {
                    return(-1);
                }

                // Get it's current object state. If a modifier has been applied, for example,
                // it is going to return the OS of the mesh in it's current form in the timeline.
                IObjectState os = node.ObjectRef.Eval(ip.Time);

                // Now grab the object itself.
                IObject objOriginal = os.Obj;

                IPolyObject polyObject = objOriginal as IPolyObject;

                IClass_ID   cid     = global.Class_ID.Create((uint)BuiltInClassIDA.POLYOBJ_CLASS_ID, 0);
                IPolyObject polyObj = ip.CreateInstance(SClass_ID.Geomobject, cid as IClass_ID) as IPolyObject;

                if (polyObject == null && convertToPoly)
                {
                    if (objOriginal.CanConvertToType(global.TriObjectClassID) == 1)
                    {
                        objOriginal = objOriginal.ConvertToType(ip.Time, global.TriObjectClassID);
                    }
                    else
                    {
                        return(-1);
                    }
                    ITriObject triOriginal = objOriginal as ITriObject;
                    polyObj.Mesh.AddTri(triOriginal.Mesh);
                    polyObj.Mesh.FillInMesh();
                    polyObj.Mesh.EliminateBadVerts(0);
                    polyObj.Mesh.MakePolyMesh(0, true);
                }
                else if (polyObject == null)
                {
                    polyObj = polyObject;
                }
                else
                {
                    return(-1);
                }

                IMatrix3    mat              = node.GetNodeTM(0, null);
                IPoint3     ptOffsetPos      = node.ObjOffsetPos;
                IQuat       quatOffsetRot    = node.ObjOffsetRot;
                IScaleValue scaleOffsetScale = node.ObjOffsetScale;

                // We can grab the faces as a List and iterate them in .NET API.

                int nNumFaces = polyObj.Mesh.FNum;
                if (m_bUsingProgress)
                {
                    m_ctrlProgress.PB_ProgressMaxNum = nNumFaces;
                }

                ADN_UserBreakCheck checkUserBreak = new ADN_UserBreakCheck();

                for (int i = 0; i < nNumFaces; i++)
                {
                    if (checkUserBreak.Check() == true)
                    {
                        return(-1);
                    }
                    if (m_bUsingProgress)
                    {
                        m_ctrlProgress.PB_ProgressCurrNum = i;
                    }

                    // Create a new poly object for each new face.
                    object objectNewFace = ip.CreateInstance(SClass_ID.Geomobject, cid as IClass_ID);

                    // Create a new node to hold it in the scene.
                    IObject objNewFace = (IObject)objectNewFace;
                    IINode  n          = global.COREInterface.CreateObjectNode(objNewFace);

                    // Name it and ensure it is unique...
                    string newname = "ADN-Sample-Face";
                    ip.MakeNameUnique(ref newname);
                    n.Name = newname;

                    // Based on what we created above, we can safely cast it to TriObject
                    IPolyObject polyNewFace = objNewFace as IPolyObject;

                    // Setup the new poly object with 1 face, and the vertex count from the original object's face we are processing
                    polyNewFace.Mesh.SetNumFaces(1);
                    polyNewFace.Mesh.SetMapNum(2);
                    IMNFace f = polyObj.Mesh.F(i);

                    polyNewFace.Mesh.F(0).Assign(f);

                    IMNFace fnew = polyNewFace.Mesh.F(0);

                    IList <int> vtx = f.Vtx;

                    polyNewFace.Mesh.SetNumVerts(vtx.Count);
                    for (int k = 0; k < vtx.Count; k++)
                    {
                        int     nvindex = vtx[k];
                        IMNVert vert    = polyObj.Mesh.V(nvindex);
                        Debug.Print("\nVertex = " + k + ", " + nvindex);
                        polyNewFace.Mesh.V(k).Assign(vert);
                        fnew.Vtx[k] = k;
                    }


                    int     nedge = nedge = polyNewFace.Mesh.SimpleNewEdge(0, 1);
                    IMNEdge edge  = polyNewFace.Mesh.E(nedge);
                    edge.Track = -1;
                    edge.F1    = 0;
                    edge.F2    = -1;
                    polyNewFace.Mesh.SetEdgeVis(nedge, true);

                    nedge      = polyNewFace.Mesh.SimpleNewEdge(1, 2);
                    edge       = polyNewFace.Mesh.E(nedge);
                    edge.Track = -1;
                    edge.F1    = 0;
                    edge.F2    = -1;
                    polyNewFace.Mesh.SetEdgeVis(nedge, true);

                    nedge      = polyNewFace.Mesh.SimpleNewEdge(2, 3);
                    edge       = polyNewFace.Mesh.E(nedge);
                    edge.Track = -1;
                    edge.F1    = 0;
                    edge.F2    = -1;
                    polyNewFace.Mesh.SetEdgeVis(nedge, true);

                    nedge      = polyNewFace.Mesh.SimpleNewEdge(3, 0);
                    edge       = polyNewFace.Mesh.E(nedge);
                    edge.Track = -1;
                    edge.F1    = 0;
                    edge.F2    = -1;
                    polyNewFace.Mesh.SetEdgeVis(nedge, true);

                    polyNewFace.Mesh.FillInMesh();
                    // make it update.
                    polyNewFace.Mesh.InvalidateGeomCache();

                    if (addShell)
                    {
                        AddOsmShell(n.Handle, shell);
                    }

                    if (addEditMesh)
                    {
                        AddOsmEditMesh(n.Handle);
                    }

                    if (collapseNode)
                    {
                        ip.CollapseNode(n, true);
                    }

                    // update transform to match object being exploded.
                    n.SetNodeTM(0, mat);
                    n.ObjOffsetPos   = ptOffsetPos;
                    n.ObjOffsetRot   = quatOffsetRot;
                    n.ObjOffsetScale = scaleOffsetScale;
                    n.ObjOffsetPos   = ptOffsetPos;
                    if (centerPivot)
                    {
                        n.CenterPivot(0, false);
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.Print(ex.Message);
                return(-1);
            }

            return(1);
        }
        /// <summary>
        /// This is the routine to convert the input node to triangle faces.
        /// </summary>
        /// <param name="nodeHandle"> Input the node by handle. </param>
        /// <param name="convertToTri"> Input whether to convert to a tri object first. </param>
        /// <param name="addShell"> Input whether to add the shell modifier when finished converting to face. </param>
        /// <param name="shell"> Input the shell thickness amount. </param>
        /// <param name="addEditMesh"> Input whether to add the Edit Mesh modifier when finished converting to face. </param>
        /// <param name="collapseNode"> Input whether to collapse the node afterwards. </param>
        /// <param name="centerPivot"> Input whether to center the pivot on each new face. </param>
        /// <returns> Returns 1 if successful or -1 if not. </returns>
        static public int ConvertToTriangleFaces(uint nodeHandle,
                                                 bool convertToTri = true, // C# now supports default parameters
                                                 bool addShell     = true,
                                                 float shell       = 0.1f,
                                                 bool addEditMesh  = true,
                                                 bool collapseNode = true,
                                                 bool centerPivot  = true)
        {
            try
            {
                IGlobal      global = Autodesk.Max.GlobalInterface.Instance;
                IInterface14 ip     = global.COREInterface14;

                IINode node = ip.GetINodeByHandle(nodeHandle);

                // Get it's current object state. If a modifier has been applied, for example,
                // it is going to return the OS of the mesh in it's current form in the timeline.
                IObjectState os = node.ObjectRef.Eval(ip.Time);

                // Now grab the object itself.
                IObject objOriginal = os.Obj;

                // Let's make sure it is a TriObject, which is the typical kind of object with a mesh
                if (!objOriginal.IsSubClassOf(global.TriObjectClassID))
                {
                    // If it is NOT, see if we can convert it...
                    if (convertToTri && objOriginal.CanConvertToType(global.TriObjectClassID) == 1)
                    {
                        objOriginal = objOriginal.ConvertToType(ip.Time, global.TriObjectClassID);
                    }
                    else
                    {
                        return(-1);
                    }
                }

                // Now we should be safe to know it is a TriObject and we can cast it as such.
                // An exception will be thrown...
                ITriObject triOriginal = objOriginal as ITriObject;


                // Let's first setup a class ID for the type of objects are are creating.
                // New TriObject in this case to hold each face.
                IClass_ID cid = global.Class_ID.Create((uint)BuiltInClassIDA.TRIOBJ_CLASS_ID, 0);

                IMatrix3    mat              = node.GetNodeTM(0, null);
                IPoint3     ptOffsetPos      = node.ObjOffsetPos;
                IQuat       quatOffsetRot    = node.ObjOffsetRot;
                IScaleValue scaleOffsetScale = node.ObjOffsetScale;

                // We can grab the faces as a List and iterate them in .NET API.
                IMesh         mesh  = triOriginal.Mesh;
                IList <IFace> faces = triOriginal.Mesh.Faces;

                int nNumFaces = faces.Count;
                if (m_bUsingProgress)
                {
                    m_ctrlProgress.PB_ProgressMaxNum = nNumFaces;
                }

                ADN_UserBreakCheck checkUserBreak = new ADN_UserBreakCheck();
                int count = 0;
                foreach (IFace face in faces)
                {
                    if (checkUserBreak.Check() == true)
                    {
                        return(-1);
                    }
                    if (m_bUsingProgress)
                    {
                        m_ctrlProgress.PB_ProgressCurrNum = ++count;
                    }

                    // Create a new TriObject for each new face.
                    object objectNewFace = ip.CreateInstance(SClass_ID.Geomobject, cid as IClass_ID);

                    // Create a new node to hold it in the scene.
                    IObject objNewFace = (IObject)objectNewFace;
                    IINode  n          = global.COREInterface.CreateObjectNode(objNewFace);

                    // Name it and ensure it is unique...
                    string newname = "ADN-Sample-Face";
                    ip.MakeNameUnique(ref newname);
                    n.Name = newname;

                    // Based on what we created above, we can safely cast it to TriObject
                    ITriObject triNewFace = objNewFace as ITriObject;

                    // Setup the new TriObject with 1 face, and the vertex count from the original object's face we are processing
                    triNewFace.Mesh.SetNumFaces(1, false, false);
                    triNewFace.Mesh.SetNumVerts(face.V.Count(), false, false);

                    // Finish setting up the face (always face '0' because there will only be one per object).
                    triNewFace.Mesh.Faces[0].SetVerts(0, 1, 2);
                    triNewFace.Mesh.Faces[0].SetEdgeVisFlags(EdgeVisibility.Vis, EdgeVisibility.Vis, EdgeVisibility.Vis);
                    triNewFace.Mesh.Faces[0].SmGroup = 2;

                    // Now, for each vertex, get the old face's points and store into new.
                    for (int i = 0; i < face.V.Count(); i++)
                    {
                        //Get the vertex from the original object's face we are processing
                        IPoint3 point = triOriginal.Mesh.GetVert((int)face.GetVert(i));
                        // Set the vertex point in the new face vertex
                        triNewFace.Mesh.SetVert(i, point);
                    }

                    // make it draw.
                    triNewFace.Mesh.InvalidateGeomCache();

                    if (addShell)
                    {
                        AddOsmShell(n.Handle, shell);
                    }

                    if (addEditMesh)
                    {
                        AddOsmEditMesh(n.Handle);
                    }

                    if (collapseNode)
                    {
                        ip.CollapseNode(n, true);
                    }

                    // update transform to match object being exploded.
                    n.SetNodeTM(0, mat);
                    n.ObjOffsetPos   = ptOffsetPos;
                    n.ObjOffsetRot   = quatOffsetRot;
                    n.ObjOffsetScale = scaleOffsetScale;
                    n.ObjOffsetPos   = ptOffsetPos;
                    if (centerPivot)
                    {
                        n.CenterPivot(0, false);
                    }
                }
            }
            catch (Exception)
            {
                return(-1);
            }

            return(1);
        }
        static public string UpdateNodes(float vertexPercent, bool keepNormals, bool collapseStack)
        {
            IGlobal      globalInterface = Autodesk.Max.GlobalInterface.Instance;
            IInterface14 coreInterface   = globalInterface.COREInterface14;

            // start the scene process
            globalInterface.TheHold.Begin();

            IINode nodeRoot = coreInterface.RootNode;

            m_sceneNodes.Clear();
            GetSceneNodes(nodeRoot);

            List <IINode> optimizedNodes = new List <IINode> {
            };

            // Iterate each node in the scene file and process all meshes into ProOptimized meshes.
            foreach (IINode node in m_sceneNodes)
            {
                // Check for object assigned to node (could be something other than object)
                if (node.ObjectRef != null)
                {
                    IObjectState os          = node.ObjectRef.Eval(coreInterface.Time);
                    IObject      objOriginal = os.Obj;
                    if (!objOriginal.IsSubClassOf(globalInterface.TriObjectClassID))
                    {
                        // If it is NOT, see if we can convert it...
                        if (objOriginal.CanConvertToType(globalInterface.TriObjectClassID) == 1)
                        {
                            objOriginal = objOriginal.ConvertToType(coreInterface.Time, globalInterface.TriObjectClassID);
                        }
                        else
                        {
                            RuntimeExecute.LogTrace("\nNode {0} Object Not Converted Error: {1}", node.NodeName, objOriginal.ObjectName);
                            continue;
                        }
                    }
                    ITriObject tri = objOriginal as ITriObject;
                    if (tri == null)
                    {
                        RuntimeExecute.LogTrace("\nNode {0} Object Not Converted Error: {1}", node.NodeName, objOriginal.ObjectName);
                        continue;
                    }
                    int val = tri.Mesh.NumVerts;
                    AddOsmProoptimizer(node, vertexPercent, keepNormals);
                    // get new mesh state
                    os  = node.ObjectRef.Eval(coreInterface.Time);
                    tri = os.Obj as ITriObject;
                    // ** after modifier operation we can see if success by checking if the mesh size is different than before
                    if (val != tri.Mesh.NumVerts)
                    {
                        if (collapseStack)
                        {
                            coreInterface.CollapseNode(node, true);
                        }
                        optimizedNodes.Add(node);
                    }
                }
            }


            int status;

            if (optimizedNodes.Count() > 0)
            {
                // Build result file name based on percentage used
                string full_filename = coreInterface.CurFilePath;
                string filename      = coreInterface.CurFileName;
                vertexPercent = vertexPercent * 100;
                string stringVertexPercent = vertexPercent.ToString("F1");
                stringVertexPercent = stringVertexPercent.Replace('.', '_');
                string output       = "outputFile-" + stringVertexPercent + ".max";
                string new_filename = full_filename.Replace(filename, output);
                status = coreInterface.SaveToFile(new_filename, true, false);

                // setup to export as FBX as well
                string outputFBX      = new_filename.Replace(".max", ".fbx");
                string msCmdFbxExport = "exportFile \"" + outputFBX + "\" #noPrompt using:FBXEXP";
                bool   fbxOk          = globalInterface.ExecuteMAXScriptScript(msCmdFbxExport, false, null, false);

                // If we changed something, put scene back for next iteration
                globalInterface.TheHold.Cancel();

                if ((status == 0) || (fbxOk == false)) // error saving max or fbx file
                {
                    return(null);
                }

                return(new_filename);
            }

            return(null);
        }
Exemple #10
0
        public static bool IsMesh(this IINode node)
        {
            IObject obj = node.EvalWorldState(Loader.Core.Time, false).Obj;

            return(obj.CanConvertToType(Loader.Global.TriObjectClassID) == 1);
        }