### Start Quick Preview Tool Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/quickpreview/README.md Import and start the quickpreview tool from the 3ds Max listener window. ```python import quickpreview quickpreview.startup() ``` -------------------------------- ### Startup Command for Renameselected Tool Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/renameselected/README.md Use this command in the 3ds Max listener to start the renameselected tool. If installed as a package, it starts automatically. ```python import renameselected renameselected.startup() ``` -------------------------------- ### Python Startup Script for Package Initialization Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/doc/pluginpackage.md This Python script initializes installed packages by loading entry points registered for '3dsMax' and 'startup'. It requires pip to be installed and handles potential errors during loading. ```python def _python_startup(): try: import pkg_resources except ImportError: print('startup Python modules require pip to be installed.') return for dist in pkg_resources.working_set: entrypt = pkg_resources.get_entry_info(dist, '3ds Max', 'startup') if not (entrypt is None): try: fcn = entrypt.load() fcn() except Exception as e: print(f'skipped package startup for {dist} because {e}, startup not working') ``` -------------------------------- ### Initialize Z-Depth Channel Module Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/zdepthchannel/README.md Call this function to start the zdepthchannel module. This is typically done from the 3ds Max listener window or automatically during 3ds Max startup if installed as a package. ```python import zdepthchannel zdepthchannel.startup() ``` -------------------------------- ### Start Thread Progress Bar Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/threadprogressbar/README.md Import and start the threadprogressbar module from the 3ds Max listener. ```python import threadprogressbar threadprogressbar.startup() ``` -------------------------------- ### Import and Start Speedsheet Tool Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/speedsheet/README.md This snippet shows how to import the speedsheet package and initiate its startup function from the 3ds Max listener window. ```python import speedsheet speedsheet.startup() ``` -------------------------------- ### Iterating Through Installed Packages Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/pystartup/README.md This loop iterates over all packages currently available in the Python environment, allowing the script to check each one for the startup entry point. ```python for dist in pkg_resources.working_set: ``` -------------------------------- ### Python Startup Script Logic Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/pystartup/README.md The core Python script that iterates through installed packages and loads any that implement the '3dsMax' startup entry point. It relies on pkg_resources from setuptools. ```python def _python_startup(): try: import pkg_resources except ImportError: print('startup Python modules require pip to be installed.') return for dist in pkg_resources.working_set: entrypt = pkg_resources.get_entry_info(dist, '3dsMax', 'startup') if not (entrypt is None): try: fcn = entrypt.load() fcn() except: print(f'skipped package startup for {dist}, startup not working') _python_startup() de_python_startup ``` -------------------------------- ### Start Worker and Connect Signal Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/threadprogressbar/README.md Instantiate the Worker thread, start it, and connect its progress signal to the progress bar's setValue function. ```python # start the worker self.worker = Worker() self.worker.progress.connect(pb.setValue) self.worker.start() ``` -------------------------------- ### MAXScript to Execute Python Startup Code Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/pystartup/README.md This MAXScript code executes a Python script that discovers and runs '3dsMax' entry points from installed pip packages. It ensures that packages implementing the startup mechanism are loaded when 3ds Max starts. ```maxscript if isProperty python "execute" then ( python.execute ("def _python_startup():\n" + " try:\n" + " import pkg_resources\n" + " except ImportError:\n" + " print('startup Python modules require pip to be installed.')\n" + " return\n" + " for dist in pkg_resources.working_set: \n" + " entrypt = pkg_resources.get_entry_info(dist, '3dsMax', 'startup')\n" + " if not (entrypt is None):\n" + " try:\n" + " fcn = entrypt.load()\n" + " fcn()\n" + " except:\n" + " print('skipped package startup for {}, startup not working'.format(dist))\n" + "_python_startup()\n" + "del _python_startup") ) ``` -------------------------------- ### Install reloadmod Package Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/reloadmod/README.md Install the reloadmod package using pip. Ensure you are in the 3ds Max Python environment directory and use the correct path to the package. ```bash cd $maxroot/Python37 Python.exe -m pip install --user /path/to/reloadmod ``` -------------------------------- ### MaxScript Example for Z-Depth Rendering Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/mxs2py/README.md This MaxScript code demonstrates rendering a scene and extracting Z-depth information to create voxel boxes with specific positions and wire colors based on pixel data. ```maxscript renderers.current = Default_Scanline_Renderer() delete $VoxelBox* rbmp = render outputsize:[32,32] channels:#(#zdepth) vfb:off z_d = getchannelasmask rbmp #zdepth progressstart "Rendering Voxels..." for y = 1 to rbmp.height do ( if not progressupdate (100.0 * y / rbmp.height) then exit pixel_line = getpixels rbmp [0,y-1] rbmp.width z_line = getpixels z_d [0,y-1] rbmp.width for x = 1 to rbmp.width do ( b = box width:10 length:10 height:(z_line[x].value/2) b.pos = [x*10,-y*10,0] b.wirecolor = pixel_line[x] b.name = uniquename "VoxelBox" )--end x loop )--end y loop progressend() ``` -------------------------------- ### Start Progress Indicator Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/zdepthchannel/README.md Initializes a progress indicator, typically displayed in the status bar, with a custom caption to show the user the progress of a long-running operation. ```python rt.progressStart("Rendering Voxels...") ``` -------------------------------- ### Starting Socket.IO Client in a Separate Thread Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/socketioclient/README.md This snippet shows how to initiate the Socket.IO connection process in a separate thread to prevent blocking the main 3ds Max UI thread. The `connect_socketio` function is executed in a new thread. ```python x = threading.Thread(target=connect_socketio) x.start() ``` -------------------------------- ### npm Package Dependencies for Socket.IO App Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/socketioclient/README.md This JSON file lists the necessary npm packages, express and socket.io, required for the Socket.IO chat application. Ensure these dependencies are installed using 'npm install'. ```json { "name": "socket-chat-example", "version": "0.0.1", "description": "my first socket.io app", "dependencies": { "express": "^4.17.3", "socket.io": "^4.4.1" } } ``` -------------------------------- ### Record Object Names at Animation Start Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/speedsheet/README.md This code captures the names of all currently selected objects at the beginning of the animation range and writes them to the output file. ```python with pymxs.attime(rt.animationRange.start): objdump = ", ".join(map(lambda x: x.name, list(rt.selection))) output_file.write( f"Object(s): {objdump}\n") ``` -------------------------------- ### Get 3ds Max Main Window Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/pyconsole/README.md Retrieves the main 3ds Max window, which is a Qt window, to allow for docking and manipulation of other Qt widgets. ```python main_window = GetQMaxMainWindow() ``` -------------------------------- ### Iterate Through Animation Frames Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/speedsheet/README.md This loop iterates through each frame of the animation range, from the start to the end, to calculate object speed for each frame. ```python for t in range(int(rt.animationRange.start), int(rt.animationRange.end)): ``` -------------------------------- ### Uninstall Individual HowTo Package (Manual) Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/doc/uninstall.md Manually uninstall a specific HowTo package. The package name should follow the format 'packagename-autodesk'. Ensure your current directory is set to the Python installation folder (e.g., maxinstallationfolder/Python37) before running this command. ```bash # current directory needs to be maxinstallationfolder/Python37: ./python.exe -m pip uninstall reloadmod-autodesk ``` -------------------------------- ### End Progress Display Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/zdepthchannel/README.md Closes the progress indicator that was previously started, signaling the completion of the operation. ```python rt.progressEnd() ``` -------------------------------- ### Python Translation of MaxScript Z-Depth Rendering Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/mxs2py/README.md This Python code is a mechanical translation of the provided MaxScript example, utilizing the pymxs library for interaction with 3ds Max. It requires the mxsshim.py module for emulation of MaxScript constructs. ```python '''Converted from MAXScript to Python with mxs2py''' from pymxs import runtime as rt import mxsshim rt.renderers.current = rt.default_scanline_renderer() rt.delete(mxsshim.path("$VoxelBox*")) rbmp = rt.render(outputsize=rt.point2(32, 32), channels=rt.array(rt.name("zdepth")), vfb=False) z_d = rt.getchannelasmask(rbmp, rt.name("zdepth")) rt.progressstart("Rendering Voxels...") for y in range(int(1), 1 + int(rbmp.height)): if not rt.progressupdate(100.0 * y / rbmp.height): break pixel_line = rt.getpixels(rbmp, rt.point2(0, y - 1), rbmp.width) z_line = rt.getpixels(z_d, rt.point2(0, y - 1), rbmp.width) for x in range(int(1), 1 + int(rbmp.width)): b = rt.box(width=10, length=10, height=(z_line[x - 1].value / 2)) b.pos = rt.point3(x * 10, -y * 10, 0) b.wirecolor = pixel_line[x - 1] b.name = rt.uniquename("VoxelBox") # end x loop # end y loop rt.progressend() ``` -------------------------------- ### Uninstall Pip (Manual) Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/doc/uninstall.md Manually uninstall pip in user mode. Ensure your current directory is set to the Python installation folder (e.g., maxinstallationfolder/Python37) before running this command. ```bash # current directory needs to be maxinstallationfolder/Python37: ./python.exe -m pip uninstall pip ``` -------------------------------- ### Get Z-Depth Channel as Grayscale Mask Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/zdepthchannel/README.md Retrieves the Z-Depth channel from a rendered bitmap as a grayscale mask. This mask can then be used to determine depth information for each pixel. ```python z_d = rt.getChannelAsMask(rbmp, zdepth_name) ``` -------------------------------- ### Get Pixel Data for a Line Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/zdepthchannel/README.md Retrieves a line of pixel data from both the main RGBA bitmap and the Z-depth mask. Note that bitmap indices are 0-based, hence the 'y-1' for the vertical position. ```python pixel_line = rt.getPixels(rbmp, rt.Point2(0, y-1), rbmp.width) z_line = rt.getPixels(z_d, rt.Point2(0, y-1), rbmp.width) ``` -------------------------------- ### Python Entry Point in setup.py Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/pystartup/README.md Define the 3dsMax startup entry point for a Python package. This line in setup.py allows 3ds Max to discover and load your package's startup function. ```python entry_points={'3dsMax': 'startup=yourpackagename:startup'} ``` -------------------------------- ### Loading and Executing the Entry Point Function Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/pystartup/README.md If the startup entry point is found, this block loads the associated function and executes it. It includes error handling to report if a package's startup fails. ```python if not (entrypt is None): try: fcn = entrypt.load() fcn() except: print(f'skipped package startup for {dist}, startup not working') ``` -------------------------------- ### Finding the 3dsMax Startup Entry Point Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/pystartup/README.md This line attempts to retrieve the specific '3dsMax' entry point named 'startup' from the current package being inspected. ```python entrypt = pkg_resources.get_entry_info(dist, '3dsMax', 'startup') ``` -------------------------------- ### Import transformlock Module Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/transformlock/README.md Import the transformlock module and call its startup function to initialize the tool. ```python import transformlock transformlock.startup() ``` -------------------------------- ### Instantiate and Style Python Console Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/pyconsole/README.md Creates a new PythonConsole instance with a predefined theme and applies a dark background stylesheet. ```python # create and setup a console console = PythonConsole(formats=HUGOS_THEME) console.setStyleSheet("background-color: #333333;") ``` -------------------------------- ### Clone the 3ds Max Python How-Tos Repository Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/doc/install.md Clone the repository to your local machine to manage and update the sample projects. This is recommended for easier updates. ```bash # from the directory where you want the sample git clone https://github.com/ADN-DevTech/3dsMax-Python-HowTos.git ``` -------------------------------- ### Create and Configure QDockWidget for Console Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/pyconsole/README.md Sets up a QDockWidget to contain the Python console, defining its object name and window title before adding it to the main 3ds Max window's dock area. ```python # create a dock widget for the console dock_widget = QDockWidget(main_window) dock_widget.setWidget(console) dock_widget.setObjectName("pyconsole") dock_widget.setWindowTitle("Python Console") main_window.addDockWidget(dockingarea, dock_widget) ``` -------------------------------- ### Importing pkg_resources Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/pystartup/README.md This import statement is necessary for the Python startup script to access package information and entry points. ```python import pkg_resources ``` -------------------------------- ### Open File Dialog for Output Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/speedsheet/README.md This code demonstrates how to prompt the user to select a file for saving the speed data using a file dialog with specified captions and file type filters. ```python output_name = rt.getSaveFileName( caption="SpeedSheet File", types="SpeedSheet (*.ssh)|*.ssh|All Files (*.*)|*.*|") ``` -------------------------------- ### Import webbrowser module Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/inbrowserhelp/README.md Import the standard Python webbrowser module to open URLs. ```python import webbrowser ``` -------------------------------- ### HTML for Socket.IO Chat Client Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/socketioclient/README.md This HTML file sets up the user interface for the chat application, including input fields, message display, and JavaScript to handle sending and receiving messages via Socket.IO. ```html Socket.IO chat
``` -------------------------------- ### Create a New Macro Script Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/menuhook/README.md Create a new macro script with a category, action, tooltip, text, and MaxScript code. ```python rt.macros.new( category, action, tooltip, text, mxs) ``` -------------------------------- ### Plugin Package Components Declaration Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/doc/pluginpackage.md This XML snippet shows how to declare Python pre-start-up scripts within a 3ds Max plugin package's PackageContents.xml file. It specifies runtime requirements and the component entry point. ```xml ``` -------------------------------- ### Progress Bar and Abort Button Widgets Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/threadprogressbar/README.md Create a QProgressBar and a QPushButton within the dialog's layout. ```python # progress bar pb = QProgressBar() pb.minimum = MINRANGE pb.maximum = MAXRANGE main_layout.addWidget(pb) # abort button btn = QPushButton("abort") main_layout.addWidget(btn) ``` -------------------------------- ### Enable Console Event Processing Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/pyconsole/README.md Hooks the console into the Qt event processing mechanism, enabling it to handle events and execute code effectively within the 3ds Max environment. ```python # make the console do stuff console.eval_queued() ``` -------------------------------- ### Define startup function for menu hook Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/removeallmaterials/README.md Define the startup function that registers the remove_all_materials function to a menu item in 3ds Max. This function can be called manually or automatically during 3ds Max startup. ```python def startup(): """ Hook the function to a menu item. """ menuhook.register( "removeallmaterials", "howtos", remove_all_materials, menu=["&Scripting", "Python3 Development", "How To"], text="Remove all materials from the scene", tooltip="Remove all materials from the scene") ``` -------------------------------- ### Import menuhook module Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/inbrowserhelp/README.md Import the menuhook module for creating custom menu items in 3ds Max. ```python import menuhook ``` -------------------------------- ### Import removeallmaterials package Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/removeallmaterials/README.md Import the removeallmaterials package to use its functions. This is typically done in the 3ds Max listener window. ```python import removeallmaterials removeallmaterials.startup() ``` -------------------------------- ### Launch RAM Player Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/quickpreview/README.md Opens the generated AVI animation file in the 3ds Max RAM Player. ```python rt.ramplayer(preview_name, "") ``` -------------------------------- ### Define menu topics and URLs Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/inbrowserhelp/README.md Define a list of tuples, where each tuple contains a unique item name, a display description, and a URL for the menu items. URLs are constructed dynamically using 3ds Max version and help paths. ```python from pymxs import runtime as rt MAX_VERSION = rt.maxversion()[7] MAX_HELP = f"help.autodesk.com/view/MAXDEV/{MAX_VERSION}/ENU" TOPICS = [ ("gettingstarted", "Getting Started With Python in 3ds Max", f"{MAX_HELP}/?guid=Max_Python_API_tutorials_creating_the_dialog_html"), ("howtos", "Python HowTos Github Repo", "github.com/ADN-DevTech/3dsMax-Python-HowTos"), ("samples", "Python samples (Github Repo)", "github.com/ADN-DevTech/3dsMax-Python-HowTos/tree/master/src/samples"), ("pymxs", "Pymxs Online Documentation", f"{MAX_HELP}/?guid=Max_Python_API_using_pymxs_html"), ("pyside2", "Qt for Python Documentation (PySide2)", "doc.qt.io/qtforpython/contents.html"), ("python", "Python 3.7 Documentation", "docs.python.org/3.7/") ] ``` -------------------------------- ### Create and Show Dialog Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/threadprogressbar/README.md Define a function to create and display the PyMaxDialog for the progress bar. ```python def threadprogressbar(): '''Update a progress bar from a thread''' dialog = ui.PyMaxDialog() dialog.show() ``` -------------------------------- ### Integrating Samples into 3ds Max 2025 Menu System Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/doc/pluginpackage.md This Python code configures the new menu system in 3ds Max 2025 by registering a callback function to add howto menu items. It uses pymxs and a custom menuhook module. ```python # configure 2025 menus from pymxs import runtime as rt from menuhook import register_howtos_menu_2025 def menu_func(): menumgr = rt.callbacks.notificationparam() register_howtos_menu_2025(menumgr) # menu system cuiregid = rt.name("cuiRegisterMenus") howtoid = rt.name("pyScriptHowtoMenu") rt.callbacks.removescripts(id=cuiregid) rt.callbacks.addscript(cuiregid, menu_func, id=howtoid) ``` -------------------------------- ### Set Floating and Show Dock Widget Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/pyconsole/README.md Configures the dock widget to be either floating or docked based on the 'floating' argument and then makes it visible. ```python dock_widget.setFloating(floating) dock_widget.show() ``` -------------------------------- ### Open File for Writing Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/speedsheet/README.md This snippet illustrates opening a selected file in write mode using Python's built-in open function within a 'with' block to ensure the file is automatically closed. ```python with open(output_name, "w+") as output_file: ``` -------------------------------- ### Define AVI Output Path Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/quickpreview/README.md Constructs the full path for the AVI preview file within the 3ds Max preview directory. ```python preview_name = path.join(rt.getDir(rt.Name("preview")), "quickpreview.avi") ``` -------------------------------- ### Add Menu Item and Update Menu Bar Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/menuhook/README.md Create a menu action item, add it to a target menu if found, and update the menu bar. ```python if targetmenu: newaction = rt.menuman.createActionItem(action, category) if newaction: targetmenu.addItem(newaction, -1) rt.menuman.updateMenuBar() ``` -------------------------------- ### Register menu items Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/inbrowserhelp/README.md Iterate through the defined topics and register each as a menu item. When activated, the menu item will open the corresponding URL in the default web browser. ```python for topic in TOPICS: menuhook.register( f"inbrowserhelp_{topic[0]}", "howtos", lambda topic=topic: webbrowser.open(f"https://{topic[2]}", MENU_LOCATION, text=topic[1], tooltip=topic[1]) ``` -------------------------------- ### Transpile MaxScript to Python using mxs2py Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/mxs2py/README.md Demonstrates how to use the `topy` function from the `mxs2py` library to convert a simple MaxScript command into its Python equivalent. The output is printed to the console. ```python from mxs2py import topy (output, _) = topy("rotate $ (angleaxis 90 [1,0,0])") print(output) ``` -------------------------------- ### Tabify Dock Widget Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/pyconsole/README.md Optionally tabifies the newly created console dock widget with an existing widget if a 'tabto' name is provided. This allows multiple dockable windows to be grouped under a single tab. ```python if (not tabto is None): tabw = main_window.findChild(QWidget, tabto) main_window.tabifyDockWidget(tabw, dock_widget) ``` -------------------------------- ### Find a Menu by Name Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/menuhook/README.md Find a specific menu in the 3ds Max menu manager using its name. ```python targetmenu = rt.menuman.findmenu(menu) ``` -------------------------------- ### Initialize Dialog with Unique Name Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/singleinstancedlg/README.md Initializes the dialog and assigns a unique name using `setObjectName` to facilitate single instance management. ```python def __init__(self, parent): super(PyMaxDialog, self).__init__(parent) self.setWindowTitle('Single Instance Dialog') # keep track of being unique self.setObjectName(PyMaxDialog.unique_name) ``` -------------------------------- ### Create Bitmap for Animation Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/quickpreview/README.md Retrieves the current viewport size and creates a bitmap object to store the animation frames. ```python view_size = rt.getViewSize() anim_bmp = rt.bitmap(view_size.x, view_size.y, filename=preview_name) ``` -------------------------------- ### Import pymxs runtime Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/removeallmaterials/README.md Import the pymxs runtime to access the MAXScript scripting library from Python. This allows interaction with 3ds Max functionalities. ```python from pymxs import runtime as rt ``` -------------------------------- ### Showing the Renameselected Dialog Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/renameselected/README.md This function creates and displays the PyMaxDialog instance, passing the renameselected function as the callback for button clicks. ```python def showdialog(): dialog = ui.PyMaxDialog(renameselected) dialog.show() ``` -------------------------------- ### Worker Thread Execution with mxthread Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/mxthread/README.md This snippet demonstrates how to use `on_main_thread` to decorate functions and `main_thread_print` for thread-safe printing. It also shows how to execute PyMaxS commands and handle exceptions raised from the main thread. ```python from mxthread import on_main_thread, main_thread_print, run_on_main_thread from pymxs import runtime as rt from qtpy.QtCore import QThread class Worker(QThread): """ Worker thread doing various things with maxtrhead. """ def __init__(self, name="worker"): QThread.__init__(self) self.setObjectName(name) def run(self): # use a function that was already decorated with on_main_thread main_thread_print(f"hello from thread {self.objectName()}") # create our own function decorated with on_main_thread @on_main_thread def do_pymxs_stuff(): print("resetting the max file") # reset the max file (so that the scene is empty) rt.resetMaxFile(rt.name("noprompt")) # we are on main thread so we can use print and it will work print("creating 3 boxes on main thread") # pymxs stuff can only work on the main thread. Well no problem we are on the main thread: rt.box(width=1, height=1, depth=1, position=rt.Point3(0,0,0)) rt.box(width=1, height=1, depth=1, position=rt.Point3(0,0,2)) rt.box(width=1, height=1, depth=1, position=rt.Point3(0,0,4)) # make 3ds Max aware that the views are dirtied rt.redrawViews() return 3 # call our main thread function res = do_pymxs_stuff() main_thread_print(f"our main thread function returned {res}") # create another function that will throw something # (to show that exceptions are propagated) @on_main_thread def do_faulty_stuff(): # we are on main thread so we can use print and it will work a = 2 b = 0 return a / b try: res = do_faulty_stuff() main_thread_print(f"The function will fail, this will never be displayed") except Exception as e: main_thread_print(f"our main thread function raised: {e}") # use a lambda instead on_main_thread(lambda : print("hello from lambda"))() # call a function on the main thread without decorating it def some_function(a, b): print(f"a = {a} b = {b}") run_on_main_thread(some_function, 1, 2) main_thread_print(f"we are done, the sample ran correctly!") # Name the main thread QThread.currentThread().setObjectName("main_thread") # create a worker worker = Worker("worker_thread") worker.start() # Note: we cannot wait this worker here. This will create a deadlock. # The worker executes stuff on the main thread and we are on the main thread. # But to convince ourselves, we can print something here and the man thread # calls initiated by the worker will all happen after this print("--- Worker thread calls to the main thread will run after this") ``` -------------------------------- ### Open Output File in 3ds Max Editor Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/speedsheet/README.md This command opens the generated output file in the 3ds Max text editor for review. ```python rt.edit(output_name) ``` -------------------------------- ### Worker Thread Initialization Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/threadprogressbar/README.md Initialize a QThread subclass named Worker, defining a progress signal and an aborted flag. ```python class Worker(QThread): progress = Signal(int) aborted = False def __init__(self): QThread.__init__(self) ``` -------------------------------- ### Create Voxel Box Based on Depth and Position Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/zdepthchannel/README.md Creates a 3D box object. Its height is determined by half the Z-buffer's grayscale value, and its X and Y positions are calculated based on pixel coordinates, with a mirrored Y-axis to align with the MAX world space. ```python box = rt.box(width=10, length=10, height=(z_line[x].value/2)) box.pos = rt.Point3(x*10, -y*10, 0) ``` -------------------------------- ### Define menu location Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/inbrowserhelp/README.md Specify the path within the 3ds Max menu system where the new submenu will be created. ```python MENU_LOCATION = ["&Scripting", "Python3 Development", "Browse Documentation"] ``` -------------------------------- ### Import necessary modules Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/singleinstancedlg/README.md Imports required classes from PySide and the 3ds Max runtime. ```python from qtpy.QtWidgets import QWidget, QDialog, QVBoxLayout, QPushButton from pymxs import runtime as rt MAIN_WINDOW = QWidget.find(rt.windows.getMAXHWND()) ``` -------------------------------- ### Connecting Button Click to Action Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/renameselected/README.md Connects the push button's clicked signal to a lambda function that calls the provided click function with the text from the line edit. ```python btn.clicked.connect(lambda : click(edit.text())) main_layout.addWidget(btn) self.setLayout(main_layout) self.resize(250, 100) ``` -------------------------------- ### Define New Console Function Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/pyconsole/README.md This function creates and configures a new Python console instance within 3ds Max. It supports tabbed docking and floating behavior. ```python def new_console(tabto = None, floating = False, dockingarea = QtCore.Qt.RightDockWidgetArea): """ Create a new console and float it as a max widget tabto: name of a widget on top of which the console should be tabbed floating: True to float the console, False to leave it docked ``` -------------------------------- ### Capture and Save Animation Frames Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/quickpreview/README.md Iterates through animation frames, captures the viewport, copies it to the animation bitmap, and saves each frame. ```python for t in range(int(rt.animationRange.start), int(rt.animationRange.end)): rt.sliderTime = t dib = rt.gw.getViewportDib() rt.copy(dib, anim_bmp) rt.save(anim_bmp) ``` -------------------------------- ### Node.js Server for Socket.IO Chat Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/socketioclient/README.md This JavaScript code sets up an Express server and integrates Socket.IO to handle real-time chat messages. It defines routes for serving the HTML client and manages connections, disconnections, and message broadcasting. ```javascript const app = require('express')(); const http = require('http').Server(app); const io = require('socket.io')(http); const port = process.env.PORT || 3000; app.get('/', (req, res) => { res.sendFile(__dirname + '/index.html'); }); io.on('connection', (socket) => { console.log('a user connected'); socket.on('disconnect', () => { console.log('user disconnected'); }); socket.on('chat message', msg => { io.emit('chat message', msg); }); }); http.listen(port, () => { console.log(`Socket.IO server running at http://localhost:${port}/`); }); ``` -------------------------------- ### Render Viewport with Z-Depth Channel Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/zdepthchannel/README.md Renders the active viewport at a specified resolution (32x32) and requests an additional Z-depth channel. The Virtual Frame Buffer (VFB) is disabled during this process. ```python rbmp = rt.render(outputsize=rt.Point2(32, 32), channels=[zdepth_name], vfb=False) ``` -------------------------------- ### Remove Application Plugins Directory (3ds Max 2025+) Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/doc/uninstall.md Manually remove the Python HowTos application plugin directory for 3ds Max 2025 and later versions. This command should be run from a Git Bash terminal. ```bash rm -fr "$ProgramData/Autodesk/ApplicationPlugins/adn-devtech-python-howtos" ``` -------------------------------- ### Force Garbage Collection Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/quickpreview/README.md Manually triggers garbage collection to free up memory used during the preview capture process. ```python rt.gc() ``` -------------------------------- ### Handling Socket.IO Events on the Main Thread Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/socketioclient/README.md This event handler demonstrates how to process incoming Socket.IO messages on the main 3ds Max thread using `mxthread.run_on_main_thread`. It prints the received data and then disconnects. ```python @sio.on("chat message") def my_message(data): mxthread.run_on_main_thread(print, f"message received {data}") # We could emit something here # sio.emit('my response', {'response': 'my response'}) # We could disconnect ourself (so we only handle one message) sio.disconnect() ``` -------------------------------- ### Menu Registration Function Signature Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/doc/pluginpackage.md Defines the signature for a menu registration function, including parameters for action, category, callback function, and specific identifiers for 3ds Max 2025 menus. ```python def register(action, category, fcn, menu=None, text=None, tooltip=None, in2025_menuid=None, id_2025=None): ``` -------------------------------- ### Update Progress and Check for Cancellation Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/zdepthchannel/README.md Updates the progress indicator with a percentage value based on the current line number and total height. Exits the loop if the user cancels the operation. ```python if not rt.progressupdate(100.0 * y / rbmp.height): break ``` -------------------------------- ### Define Custom PyMaxDialog Class Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/singleinstancedlg/README.md Defines a custom PySide dialog class that will be attached to the 3ds Max main window. It includes a class variable for a unique name. ```python class PyMaxDialog(QDialog): """ Custom dialog attached to the 3ds Max main window """ unique_name = __file__ ``` -------------------------------- ### Show Dialog Function Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/singleinstancedlg/README.md This function ensures that only one instance of the dialog is shown. It uses `findChild` to check for an existing dialog with the unique name and creates a new one only if none is found. ```python def show_dialog(): '''Show the dialog without duplicating it''' dialog = MAIN_WINDOW.findChild(QDialog, PyMaxDialog.unique_name) if dialog is None: dialog = PyMaxDialog(MAIN_WINDOW) dialog.show() ``` -------------------------------- ### Calculate and Log Average Speed Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/speedsheet/README.md After iterating through all frames, this code calculates the average speed over the entire animation range and writes it to the output file. ```python average_speed /= float(rt.animationRange.end - rt.animationRange.start) output_file.write(f"Average Speed: {average_speed}\n") ``` -------------------------------- ### Dialog UI Population Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/renameselected/README.md Populates the PySide dialog with a label, a line edit for input, and a button to trigger the renaming action. ```python super(PyMaxDialog, self).__init__(parent) self.setWindowTitle('Rename') main_layout = QVBoxLayout() label = QLabel("Enter new base name") main_layout.addWidget(label) edit = QLineEdit() main_layout.addWidget(edit) btn = QPushButton("Rename selected objects") ``` -------------------------------- ### Call Function on Main Thread Directly Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/mxthread/README.md Alternatively, call a function on the main thread using run_on_main_thread, passing the function and its arguments. This is useful when decorators are not preferred. ```python from mxthread import run_on_main_thread def some_function(a, b): print(f"a = {a} b = {b}") run_on_main_thread(some_function, 1, 2) ``` -------------------------------- ### PySide Dialog Class Definition Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/renameselected/README.md Defines a custom QDialog subclass for the renaming tool. It accepts a click function in its constructor to handle button actions. ```python class PyMaxDialog(QDialog): """ Custom dialog attached to the 3ds Max main window """ def __init__(self, click, parent=QWidget.find(rt.windows.getMAXHWND())): ``` -------------------------------- ### Storing Registered Menu Items Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/doc/pluginpackage.md This code snippet shows how registered menu items are stored in a list, containing identifiers for the menu, category, and action. This list is used by the menu system to build the UI. ```python registered_items.append((in2025_menuid, id_2025, category, action)) ``` -------------------------------- ### Connect Abort Button Signal Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/threadprogressbar/README.md Connect the clicked signal of the abort button to the abort function of the worker thread. ```python # connect abort button btn.clicked.connect(self.worker.abort) ``` -------------------------------- ### Register Python Function to 3ds Max Menu Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/menuhook/README.md Use this snippet to register a Python function to a specific 3ds Max menu item. The function will be executed when the menu item is clicked. Ensure the 'menuhook' package is imported. ```python import menuhook def fcn(): """ Do something. This is the function we want to attach to a menu item. """ print("hello") menuhook.register( # the name of the action (will be listed in menu customization dialogs) "myaction", # the category for the action "my category", # the function to be executed (this is registered for a single run of 3ds Max) fcn, # the menu for this action. if None is provided the action # will not be added to a menu, only created as an action. # this can be deeply nested. menu=["&Scripting", "Samples"], # the menu text. if None is provided, the action name will be used text="the text for the menu item", # the menu tool tip. if None is provided, the action name will be used tooltip="the tooltip") ``` -------------------------------- ### Adding Menu Items to 3ds Max 2025 Menu Manager Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/doc/pluginpackage.md This Python code iterates through registered items and adds them to the 3ds Max 2025 menu manager. It handles cases where the menu might not be found, printing an error message. ```python # hook the registered items for reg in registered_items: (in2025_menuid, id_2025, category, action) = reg scriptmenu = menumgr.getmenubyid(in2025_menuid) if scriptmenu is not None: try: actionitem = scriptmenu.createaction(id_2025, 647394, f"{action}`{category}") except Exception as e: print(f"Could not create item {category}, {action} in menu {in2025_menuid} because {e}") else: print(f"Could not create item {category}, {action}, in missing menu {in2025_menuid}") ``` -------------------------------- ### Filter Objects by Name Pattern Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/zdepthchannel/README.md Filters existing objects in the scene to find and delete those matching a specific name pattern (e.g., 'VoxelBox'). This is useful for cleaning up previous runs. ```python voxelbox = re.compile("^VoxelBox") for tbd in filter(lambda o: voxelbox.match(o.name), list(rt.objects)): rt.delete(tbd) ``` -------------------------------- ### Calculate Frame Speed Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/speedsheet/README.md This snippet calculates the speed of the selection's center between the current frame (t) and the previous frame (t-1) by measuring the distance and multiplying by the frame rate. ```python with pymxs.attime(t): current_pos = rt.selection.center with pymxs.attime(t-1): last_pos = rt.selection.center frame_speed = rt.distance(current_pos, last_pos) * rt.FrameRate average_speed += frame_speed output_file.write(f"Frame {t}: {frame_speed}\n") ``` -------------------------------- ### Define remove_all_materials function Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/removeallmaterials/README.md Define the core business logic function that iterates through all objects in the scene and sets their material property to None, effectively removing materials. ```python def remove_all_materials(): '''Remove all materials from the scene''' for obj in rt.objects: obj.material = None ``` -------------------------------- ### Decorate Function to Run on Main Thread Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/mxthread/README.md Use the @on_main_thread decorator to ensure a function executes on the main thread. This allows operations like printing that are restricted in worker threads. ```python from mxthread import on_main_thread @on_main_thread def do_faulty_stuff(): # we are on main thread so we can use print and it will work a = 2 b = 0 return a / b ``` -------------------------------- ### Iterate Through Bitmap Lines Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/zdepthchannel/README.md Loops through each horizontal line of a rendered bitmap. The loop variable 'y' represents the current line number. ```python for y in range(1, rbmp.height): print("y =", y) ``` -------------------------------- ### Assign Unique Name to Box Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/zdepthchannel/README.md Assigns a unique name to the created box, using 'VoxelBox' as a base name to ensure no naming conflicts. ```python box.name = rt.uniqueName("VoxelBox") ``` -------------------------------- ### Generated Python Code for Rotation Command Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/mxs2py/README.md This is the Python code generated by `mxs2py` for the MaxScript `rotate $ (angleaxis 90 [1,0,0])` command. It utilizes `pymxs` and `mxsshim` for execution. ```python '''Converted from MAXScript to Python with mxs2py''' from pymxs import runtime as rt import mxsshim import pymxs rt.rotate(mxsshim.path("$"), rt.angleaxis(90, rt.point3(1, 0, 0))) ``` -------------------------------- ### Iterate Through Pixels in a Line Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/zdepthchannel/README.md Loops through each pixel in the current scanline. The variable 'x' represents the horizontal pixel coordinate. It accesses the Z-buffer value for each pixel. ```python for x in range(1, rbmp.width): print("x =", x, z_line[x].value) ``` -------------------------------- ### Assign Wireframe Color to Box Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/zdepthchannel/README.md Sets the wireframe color of the newly created box to match the RGB color of the corresponding rendered pixel. ```python box.wirecolor = pixel_line[x] ``` -------------------------------- ### Register Transform Lock Menu Item Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/transformlock/README.md Registers the lock_selection function as a menu item under the Scripting > Python3 Development > How To menu. This function will be executed when the menu item is clicked. ```python def startup(): """ Hook the transform lock function to a menu item. """ menuhook.register( "transformlock", "howtos", lock_selection, menu=["&Scripting", "Python3 Development", "How To"], text="Lock transformations for the selection", tooltip="Lock transformations for the selection") ``` -------------------------------- ### Registering Renameselected Menu Item Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/renameselected/README.md Hooks the renameselected functionality to a menu item under the 'Scripting' menu in 3ds Max. This allows users to access the tool via the UI. ```python def startup(): """ Hook the function to a menu item. """ menuhook.register( "howtos", "renameselected", showdialog, menu=[ "&Scripting", "Python3 Development", "How To"], text="renameselected sample", tooltip="renameselected sample") ``` -------------------------------- ### Lock Selection Transforms Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/transformlock/README.md Defines the core function to lock all transformations (position, rotation, scale) on the currently selected objects in 3ds Max. ```python def lock_selection(): '''Lock all transforms on the selection''' rt.setTransformLockFlags(rt.selection, rt.Name("all")) ``` -------------------------------- ### Worker Thread Run Loop Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/threadprogressbar/README.md The run function of the Worker thread iterates, emits progress, sleeps, and checks for abortion. ```python for i in range(MINRANGE, MAXRANGE): self.progress.emit(i) time.sleep(0.5) if self.aborted: return self.progress.emit(MAXRANGE) ``` -------------------------------- ### Close Animation Bitmap Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/quickpreview/README.md Closes the bitmap file after all animation frames have been saved. ```python rt.close(anim_bmp) ``` -------------------------------- ### Core Renaming Functionality Source: https://github.com/adn-devtech/3dsmax-python-howtos/blob/master/src/packages/renameselected/README.md This Python function renames all selected objects in 3ds Max using a provided base name. It ensures unique names for each object. ```python def renameselected(text): '''Rename all elements in selection''' if text != "": for i in rt.selection: i.name = rt.uniquename(text) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.