/// <summary> /// Adds an object space modifier to provided node (by handle). /// </summary> /// <param name="nodeHandle"> Input the node handle to add the modifier to. </param> /// <param name="cid"> Input the class id of the modifier add. </param> /// <returns> Returns 1 if successful or -1 if not. </returns> static public int AddOsmModifier(uint nodeHandle, IClass_ID cid) { try { IGlobal global = Autodesk.Max.GlobalInterface.Instance; IInterface14 ip = global.COREInterface14; IINode node = ip.GetINodeByHandle(nodeHandle); IObject obj = node.ObjectRef; IIDerivedObject dobj = global.CreateDerivedObject(obj); object objMod = ip.CreateInstance(SClass_ID.Osm, cid as IClass_ID); IModifier mod = (IModifier)objMod; dobj.AddModifier(mod, null, 0); // top of stack node.ObjectRef = dobj; } catch (Exception ex) { Debug.Print(ex.Message); return(-1); } return(1); }
public override void CustomExecute(object parameter) { try { IGlobal global = Autodesk.Max.GlobalInterface.Instance; IInterface14 ip = global.COREInterface14; int nNumSelNodes = ip.SelNodeCount; if (nNumSelNodes <= 0) { ip.PushPrompt("No nodes are selected. Please select at least one node to convert, before running the command."); return; } System.Windows.Window dialog = new System.Windows.Window(); dialog.Title = "Explode It!"; dialog.SizeToContent = System.Windows.SizeToContent.WidthAndHeight; ExplodeGeomUserControl1 ctlExplode = new ExplodeGeomUserControl1(dialog); dialog.Content = ctlExplode; dialog.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner; dialog.ShowInTaskbar = false; dialog.ResizeMode = System.Windows.ResizeMode.NoResize; System.Windows.Interop.WindowInteropHelper windowHandle = new System.Windows.Interop.WindowInteropHelper(dialog); windowHandle.Owner = ManagedServices.AppSDK.GetMaxHWND(); ManagedServices.AppSDK.ConfigureWindowForMax(dialog); dialog.ShowDialog(); //modal version; this prevents changes being made to model while our dialog is running, etc. } catch (Exception ex) { Debug.Print(ex.Message); } }
public override int Proc(IntPtr hwnd, int msg, int point, int flags, IIPoint2 m) { Debug.Print("viewport point: " + m.X + ", " + m.Y); switch (msg) { case 0: // MOUSE_ABORT see .\maxsdk\include\mouseman.h for all possible values { IGlobal global = Autodesk.Max.GlobalInterface.Instance; IInterface14 ip = global.COREInterface14; ip.PopCommandMode(); Debug.Print("mouse callback aborted"); } break; case 1: // MOUSE_POINT see .\maxsdk\include\mouseman.h for all possible values { if (point == 0) { IGlobal global = Autodesk.Max.GlobalInterface.Instance; IInterface14 ip = global.COREInterface14; IViewExp vp = ip.ActiveViewExp; IPoint3 pt = vp.SnapPoint(m, m, null, SnapFlags.InPlane); ip.PopCommandMode(); Debug.Print("3d point (in plane): " + pt.X + ", " + pt.Y + ", " + pt.Z); } // else if ... other points if you have more than one... } break; default: break; } return(1); }
public static void AssemblyMain() { Global = GlobalInterface.Instance; Core = Global.COREInterface14; Class_ID = Global.Class_ID.Create(0x8217f123, 0xef980456); Core.AddClass(new Descriptor()); }
public override void Execute(object parameter) { IGlobal global = Autodesk.Max.GlobalInterface.Instance; IInterface14 ip = global.COREInterface14; try { if (mainDialog == null) { mainDialog = new ApplicationView(); } if (mainDialog.Visibility == Visibility.Hidden) { isopen = false; } if (!isopen) { isopen = true; mainDialog.Closed += new EventHandler(SearchSimilar_Closed); System.Windows.Interop.WindowInteropHelper windowHandle = new System.Windows.Interop.WindowInteropHelper(mainDialog); windowHandle.Owner = ManagedServices.AppSDK.GetMaxHWND(); ManagedServices.AppSDK.ConfigureWindowForMax(mainDialog); mainDialog.Show(); } else { isopen = false; mainDialog.Hide(); } } catch (Exception e) { Debug.Print("Exception occurred: " + e.Message); } }
/// <summary> /// Adds the Shell modifier to the provided node (by handle). /// </summary> /// <param name="nodeHandle"> Input the node handle to add the modifier to. </param> /// <param name="shellAmount"> Input the amount of shell thickness as float. </param> /// <returns> Returns 1 if successful or -1 if not. </returns> static public int AddOsmShell(uint nodeHandle, float shellAmount) { try { IGlobal global = Autodesk.Max.GlobalInterface.Instance; IInterface14 ip = global.COREInterface14; IClass_ID cidOsmShell = global.Class_ID.Create(0x3b9b1a16, 0x6d84e8d0); AddOsmModifier(nodeHandle, cidOsmShell); IINode node = ip.GetINodeByHandle(nodeHandle); IModifier mod = GetModifier(node, cidOsmShell); if (mod != null) { IIParamBlock2 pb = mod.GetParamBlock(0); pb.SetValue(0, 0, shellAmount, 0); // innerAmount parameter is at index zero of the parameter block. } } catch (Exception ex) { Debug.Print(ex.Message); return(-1); } return(1); }
public override void ExitMode() { IGlobal global = Autodesk.Max.GlobalInterface.Instance; IInterface14 ip = global.COREInterface14; ip.PopPrompt(); return; }
public override void EnterMode() { IGlobal global = Autodesk.Max.GlobalInterface.Instance; IInterface14 ip = global.COREInterface14; ip.PushPrompt("Select a point:"); return; }
public ExplodeGeomUserControl1(System.Windows.Window creator) { m_winParent = creator; InitializeComponent(); IGlobal global = Autodesk.Max.GlobalInterface.Instance; IInterface14 ip = global.COREInterface14; IIColorManager cm = global.ColorManager; System.Drawing.Color dcolBack = cm.GetColor(Autodesk.Max.GuiColors.Background, Autodesk.Max.IColorManager.State.Normal); // due to a bug in the 3ds Max .NET API before 2017, you would have to reverse the R and B values to assign color properly. // The Autodesk.Max assembly mapped them incorrectly // pre 2017: System.Windows.Media.Color mcolorBack = System.Windows.Media.Color.FromRgb(dcolBack.B, dcolBack.G, dcolBack.R); // Get current background color and match our dialog to it System.Windows.Media.Color mcolorBack = System.Windows.Media.Color.FromRgb(dcolBack.R, dcolBack.G, dcolBack.B); Brush colorBack = new SolidColorBrush(mcolorBack); // Note, if you want just a fixed color, you can comment this out and use the XAML defined value. LayoutRoot.Background = colorBack; // Get current text color and match our dialog to it. System.Drawing.Color dcolText = cm.GetColor(Autodesk.Max.GuiColors.Text, Autodesk.Max.IColorManager.State.Normal); // pre 2017: System.Windows.Media.Color mcolorText = System.Windows.Media.Color.FromRgb(dcolText.B, dcolText.G, dcolText.R); System.Windows.Media.Color mcolorText = System.Windows.Media.Color.FromRgb(dcolText.R, dcolText.G, dcolText.B); Brush colorText = new SolidColorBrush(mcolorText); // To use pure white, we can just set a system brush. //Brush colorText = Brushes.White; m_gbExplodeTypes.Foreground = colorText; m_rbTriangles.Foreground = colorText; m_rbPolygons.Foreground = colorText; m_gbExplodeOptions.Foreground = colorText; m_cbConvertTri.Foreground = colorText; m_cbConvertPoly.Foreground = colorText; m_cbAddShell.Foreground = colorText; m_lblNumOffset.Foreground = colorText; m_cbAddEditMesh.Foreground = colorText; m_cbCollapseStack.Foreground = colorText; m_cbCenterPivot.Foreground = colorText; m_cbDeleteOriginal.Foreground = colorText; // This is a button control, and we are not setting its color. // So we will not change the text color either. //m_btnExplodeIt.Foreground = colorText; m_lblLabelProNode.Foreground = colorText; m_lblNodeName.Foreground = colorText; m_lblLabelNode.Foreground = colorText; m_lblCurrNode.Foreground = colorText; m_lblLabelOf.Foreground = colorText; m_lblTotNode.Foreground = colorText; m_lblLabelEscape.Foreground = colorText; }
public override void Execute(object parameter) { IGlobal global = Autodesk.Max.GlobalInterface.Instance; IInterface14 ip = global.COREInterface14; AdnCommandMode mode = new AdnCommandMode(); ip.PushCommandMode(mode); }
static void Initialize() { if (global == null) { global = GlobalInterface.Instance; core = global.COREInterface14; Class_ID = global.Class_ID.Create(0x8217f123, 0xef980456); core.AddClass(new Descriptor()); } }
/// <summary> /// Information sent to this LogTrace will appear on the Design Automation output /// </summary> public static void LogTrace(string format, params object[] args) { IGlobal globalInterface = Autodesk.Max.GlobalInterface.Instance; IInterface14 coreInterface = globalInterface.COREInterface14; ILogSys log = coreInterface.Log; // Note flags are necessary to produce Design Automation output. This is same as C++: // SYSLOG_INFO | SYSLOG_IGNORE_VERBOSITY | SYSLOG_BROADCAST log.LogEntry(0x00000004 | 0x00040000 | 0x00010000, false, "", string.Format(format, args)); }
public ROD_ExportG() { maxGlobal = Autodesk.Max.GlobalInterface.Instance; maxInterface = maxGlobal.COREInterface14; IPoint3 U = maxGlobal.Point3.Create(1.0, 0.0, 0.0); IPoint3 V = maxGlobal.Point3.Create(0.0, 0.0, 1.0); IPoint3 N = maxGlobal.Point3.Create(0.0, -1.0, 0.0); IPoint3 T = maxGlobal.Point3.Create(0.0, 0.0, 0.0); _leftHanded = maxGlobal.Matrix3.Create(U, V, N, T); _GleftHanded = maxGlobal.GMatrix.Create(_leftHanded); }
/// <summary> /// Function to specifically update Case Windows with input wedth and height parameters /// </summary> /// <param name="width">The new Width to set the Window</param> /// <param name="height">The new Height to set the Window</param> /// <returns>window count</returns> static public int UpdateWindowNodes(float width, float height) { IGlobal globalInterface = Autodesk.Max.GlobalInterface.Instance; IInterface14 coreInterface = globalInterface.COREInterface14; IINode nodeRoot = coreInterface.RootNode; m_sceneNodes.Clear(); GetSceneNodes(nodeRoot); // 3ds Max uses a class ID for all object types. This is easiest way to find specific type. // ClassID (1902665597L, 1593788199L) == 0x71685F7D, 0x5EFF4727 for casement window IClass_ID cidCasementWindow = globalInterface.Class_ID.Create(0x71685F7D, 0x5EFF4727); // Use LINQ to filter for windows only - in case scene has more than one, // but this should still give us at least one for single window scene! var sceneWindows = from node in m_sceneNodes where ((node.ObjectRef != null) && // In some cases the ObjectRef can be null for certain node types. (node.ObjectRef.ClassID.PartA == cidCasementWindow.PartA) && (node.ObjectRef.ClassID.PartB == cidCasementWindow.PartB)) select node; // Iterate the casement windws and update the hight and width parameters. foreach (IINode item in sceneWindows) { // window is using old-style ParamArray rather than newer ParamBlk2 IIParamArray pb = item.ObjectRef.ParamBlock; pb.SetValue(0, coreInterface.Time, height); // window height is at index zero. pb.SetValue(1, coreInterface.Time, width); // window width is at index one. } // If there are windows, save the window updates int status; if (sceneWindows.Count() > 0) { // The output file name must match what the Design Automation work item is specifying as output file. string full_filename = coreInterface.CurFilePath; string filename = coreInterface.CurFileName; string new_filename = full_filename.Replace(filename, "outputFile.max"); status = coreInterface.SaveToFile(new_filename, true, false); if (status == 0) //error { return(-1); } } // return how many windows were modified. return(sceneWindows.Count()); }
/// <summary> /// Information sent to this LogTrace will appear on the Design Automation output /// </summary> private static void LogTrace(string format, params object[] args) { System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly(); string output_msg = string.Format("DLL {0} compiled on {1}; {2}", System.IO.Path.GetFileName(a.Location), File.GetLastWriteTime(a.Location), string.Format(format, args)); IGlobal globalInterface = Autodesk.Max.GlobalInterface.Instance; IInterface14 coreInterface = globalInterface.COREInterface14; ILogSys log = coreInterface.Log; // Note flags are necessary to produce Design Automation output. This is same as C++: // SYSLOG_INFO | SYSLOG_IGNORE_VERBOSITY | SYSLOG_BROADCAST log.LogEntry(0x00000004 | 0x00040000 | 0x00010000, false, "", output_msg); }
/// <summary> /// Adds the Edit Mesh modifier to the provided node (by handle). /// </summary> /// <param name="nodeHandle"> Input the node handle to add the modifier to. </param> /// <returns> Returns 1 if successful or -1 if not. </returns> static public int AddOsmEditMesh(uint nodeHandle) { try { IGlobal global = Autodesk.Max.GlobalInterface.Instance; IInterface14 ip = global.COREInterface14; IClass_ID cidOsmEditMesh = global.Class_ID.Create(0x00050, 0); AddOsmModifier(nodeHandle, cidOsmEditMesh); } catch (Exception ex) { Debug.Print(ex.Message); return(-1); } return(1); }
/// <summary> /// Adds the Shell modifier to the provided node (by handle). /// </summary> /// <param name="nodeHandle"> Input the node handle to add the modifier to. </param> /// <param name="shellAmount"> Input the amount of shell thickness as float. </param> /// <returns> Returns 1 if successful or -1 if not. </returns> static public int AddOsmProoptimizer(IINode node, float VertexPercent, bool KeepNormals) { try { IGlobal global = Autodesk.Max.GlobalInterface.Instance; IInterface14 ip = global.COREInterface14; int t = ip.Time; // classID:#(1056067556, 1496462090) IClass_ID cidOsmProoptimizer = global.Class_ID.Create(0x3EF24FE4, 0x5932330A); AddOsmModifier(node, cidOsmProoptimizer); IModifier mod = GetModifier(node, cidOsmProoptimizer); if (mod != null) { // In order to get the "Calculate" parameter to trigger the modifier to execute, we have to enable some UI elements. ip.CmdPanelOpen = true; // ensures the command panel in general is open ip.SelectNode(node, true); // Select the node to make it active ip.CommandPanelTaskMode = 2; // TASK_MODE_MODIFY. This makes the modifier panel active. // Now we can set the parameters on the modifier, and at end "calculate" the results. IIParamBlock2 pb = mod.GetParamBlock(0); pb.SetValue((int)ProOptimizerPBValues.optimizer_main_ratio, t, VertexPercent, 0); pb.SetValue((int)ProOptimizerPBValues.optimizer_options_keep_uv, t, 1, 0); pb.SetValue((int)ProOptimizerPBValues.optimizer_options_keep_normals, t, 0, 0); // There is no true way to know if this was valid/invalid for the mesh, so we check the outer level routine on triobject for changes. ** pb.SetValue((int)ProOptimizerPBValues.optimizer_main_calculate, t, 1, 0); ip.ClearNodeSelection(false); } } catch (Exception ex) { Debug.Print(ex.Message); return(-1); } return(1); }
private void m_btnExplodeIt_Click(object sender, RoutedEventArgs e) { // IGlobal global = Autodesk.Max.GlobalInterface.Instance; IInterface14 ip = global.COREInterface14; this.m_pnlProgressPanel.Visibility = System.Windows.Visibility.Visible; try { global.TheHold.Begin(); ADN_Utility.SetProgressControl(this); bool convertPoly = EI_ConvertTypePoly; // true = poly, false = tri bool attemptConvert; if (convertPoly) { attemptConvert = EI_AttemptConvertToPoly; } else { attemptConvert = EI_AttemptConvertToTri; } bool addShell = EI_AddShellModifier; float shellAmount = EI_ShellAmount; bool addEditMesh = EI_AddEditMeshModifier; bool collapseStack = EI_CollapseStack; bool deleteNode = EI_DeleteOriginal; //ip.DisableSceneRedraw(); int stat = 0; int nNumSelNodes = ip.SelNodeCount; m_lblTotNode.Content = nNumSelNodes.ToString(); for (int i = 0; i < nNumSelNodes; i++) { IINode nodeCur = ip.GetSelNode(i); m_lblNodeName.Content = nodeCur.Name; m_lblCurrNode.Content = i + 1; if (convertPoly) { stat = ADN_Utility.ConvertToPolygonFaces(nodeCur.Handle, attemptConvert, addShell, shellAmount, addEditMesh, collapseStack); if (stat < 0) { break; } } else { stat = ADN_Utility.ConvertToTriangleFaces(nodeCur.Handle, attemptConvert, addShell, shellAmount, addEditMesh, collapseStack); if (stat < 0) { break; } } } if (stat < 0) { global.TheHold.Cancel(); } else { // now we need to start at the top to delete the original nodes. if (deleteNode) { IINodeTab tabNodes = global.INodeTabNS.Create(); ip.GetSelNodeTab(tabNodes); if (tabNodes != null) { ip.DeleteNodes(tabNodes, true, true, false); } } global.TheHold.Accept("ADN-PolygonExplode"); } ip.RedrawViews(0, RedrawFlags.Normal, null); } catch { global.TheHold.Cancel(); } this.m_pnlProgressPanel.Visibility = System.Windows.Visibility.Hidden; ADN_Utility.ClearProgressControl(this); m_winParent.Close(); m_bOk = true; }
public static void AssemblyMain() { Global = Autodesk.Max.GlobalInterface.Instance; Core = Global.COREInterface14; Core.AddClass(new Descriptor()); }
public static void AssemblyMain() { Global = GlobalInterface.Instance; //初始化全局实例 Core = Global.COREInterface14; Core.AddClass(new Descriptor()); //初始化插件描述 }
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); }
/// <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); }