If you’re interested in taking the first step into Python for 3D software,
Or simply would like to browse some script examples, your welcome to visit my Gist page,
It contains a useful library of Python code example for Blender, Maya, 3ds max and Unreal engine:
https://gist.github.com/CGLion
Python for 3ds max – Loading an image file and reading pixel values
3ds max 2020
* The EXR image file is located in in the same directory with the 3ds max file in this case.
from MaxPlus import BitmapManager image_file_path = r'BG_park_A.exr' bmp_storage = MaxPlus.Factory.CreateStorage(17) bmp_info = bmp_storage.GetBitmapInfo() bmp_info.SetName(image_file_path) bmp = BitmapManager.Load(bmp_info) bmp.Display()
Script explanation line by line:
And it may very well be that I simply didn’t find the correct way it should be done..
I couldn’t find any other way to independently initiate the BitmapInfo object needed for loading the image, other than Initiating a BitmapStorage object and getting referece to its BitmapInfo object. (the BitmapInfo class has no constructor..)
that the 17 integer argument we supply sets the storage to be compatible with:
32-bit floating-point color depth format (without an alpha channel).
See list of other color format options in this example here:
https://help.autodesk.com/view/3DSMAX/2020/ENU/?guid=__developer_using_maxplus_creating_a_bitmap_html
* They wrote a class containing convenient named constants of the integer arguments (see example code below).
* In this example of creating the BitmapStorage just as a way to generate a BitmapInfo object the actual format you’l supply doesn’t matter, but you can’t use a format that can’t be written to like 8 for example (see list below)
Example code for a BitmapStorage format constants container class:
* This example’s source is in the 3ds max help Python examples:
https://help.autodesk.com/view/3DSMAX/2020/ENU/?guid=__developer_using_maxplus_creating_a_bitmap_html
class BitmapTypes(object): BMM_NO_TYPE = 0 # Not allocated yet BMM_LINE_ART = 1 # 1-bit monochrome image BMM_PALETTED = 2 # 8-bit paletted image. Each pixel value is an index into the color table. BMM_GRAY_8 = 3 # 8-bit grayscale bitmap. BMM_GRAY_16 = 4 # 16-bit grayscale bitmap. BMM_TRUE_16 = 5 # 16-bit true color image. BMM_TRUE_32 = 6 # 32-bit color: 8 bits each for Red, Green, Blue, and Alpha. BMM_TRUE_64 = 7 # 64-bit color: 16 bits each for Red, Green, Blue, and Alpha. BMM_TRUE_24 = 8 # 24-bit color: 8 bits each for Red, Green, and Blue. Cannot be written to. BMM_TRUE_48 = 9 # 48-bit color: 16 bits each for Red, Green, and Blue. Cannot be written to. BMM_YUV_422 = 10 # This is the YUV format - CCIR 601. Cannot be written to. BMM_BMP_4 = 11 # Windows BMP 16-bit color bitmap. Cannot be written to. BMM_PAD_24 = 12 # Padded 24-bit (in a 32 bit register). Cannot be written to. BMM_LOGLUV_32 = 13 BMM_LOGLUV_24 = 14 BMM_LOGLUV_24A = 15 BMM_REALPIX_32 = 16 # The 'Real Pixel' format. BMM_FLOAT_RGBA_32 = 17 # 32-bit floating-point per component (non-compressed), RGB with or without alpha BMM_FLOAT_GRAY_32 = 18 # 32-bit floating-point (non-compressed), monochrome/grayscale BMM_FLOAT_RGB_32 = 19 BMM_FLOAT_A_32 = 20
Reading pixel values from the image:
bmp_storage = bmp.GetStorage() hdr_pixel = bmp_storage.GetHDRPixel(3000,200) print(hdr_pixel)
* in this case, writing over the BitmapStorage object we created earlier just to get the BitmapInfo object..
Note:
When copying and pasting a script from this example, the indentation may not be pasted correctly.
Related:
Python for 3ds max – Select objects of type
Software:
3ds max 2020
Continuing this example,
If you need to select objects (nodes) of a certain type i.e. lights, cameras etc.
You can use the INode class’s GetObject() method to get a reference to the node’s object, or “modified object” in 3ds max terms, and use the object’s GetSuperClassID() method to get the integer id representing the object’s superclass.
In addition, the MaxPlus SuperClassIds class contains convenient constants that can be used to avoid having to check and remember the superclasses numeric ids.
See reference here:
https://help.autodesk.com/view/3DSMAX/2017/ENU/?guid=__py_ref_class_max_plus_1_1_super_class_ids_html
An example of a script that selects all light objects in the scene:
from MaxPlus import SuperClassIds from MaxPlus import SelectionManager def scene_objects(): def list_children(node): list = [] for c in node.Children: list.append(c) list = list + list_children(c) return list return list_children(MaxPlus.Core.GetRootNode()) for o in scene_objects(): obj = o.GetObject() if obj.GetSuperClassID() == SuperClassIds.Light: SelectionManager.SelectNode(o, False)
* note that when copying and pasting a script from this example, the indentation may not be pasted correctly.
Python for 3ds max – Mesh manipulation
Software:
3ds max 2019
An example of creating a mesh ripple deformation using Python for 3ds max:
Script steps:
- Define the effect intensity and a helper point object that will serve as the effect center.
- Collapse the object to an Editable-Mesh so its vertices will be accessible by Python.
Note that the Node‘s Object has to be cast as a TriObject, to access the object’s Mesh data. - Â Loop through the Mesh’s vertices, get their world position, and set a new Z position as a sine function of the distance from the effect center.
import math from MaxPlus import Factory from MaxPlus import ClassIds from MaxPlus import INode from MaxPlus import TriObject from MaxPlus import Matrix3 from MaxPlus import Point3 # Intensity: effecr_mult = 1.0 # Effect center: effector = INode.GetINodeByName('Point001') effect_pos = effector.GetWorldPosition() # Prepare object and eccess it's mesh data: node = INode.GetINodeByName('Teapot001') new_edit_mesh_mod = Factory.CreateObjectModifier(ClassIds.Edit_Mesh) node.AddModifier(new_edit_mesh_mod) node.Collapse(True) node_tm = node.GetWorldTM() node_pos = node.GetWorldPosition() obj = node.GetObject() triobj = TriObject._CastFrom(obj) mesh = triobj.GetMesh() # Process the object's vertices: for i in range(mesh.GetNumVertices()): # Get vertex in world space vert_pos = mesh.GetVertex(i) vert_world_pos = node_tm.VectorTransform(vert_pos) vert_world_pos = vert_world_pos + node_pos # Get vertex distance from effect center: diff_vec = vert_world_pos - effect_pos diff_vec.Z = 0 dist = diff_vec.GetLength() # Set new vertex position: mesh.SetVert(i,vert_pos.X,vert_pos.Y,vert_pos.Z + math.sin(dist)*effecr_mult)
* note that when copying and pasting a script from this example, the indentation may not be pasted correctly.
Related Post:
Python for 3ds max – Animated Mesh
Python for 3ds max – replace selected objects with a merged object
Software:
3ds max 2020
The following Python for 3ds max snippet replaces all selected objects with an object merged from an external 3ds max file.
Notes:
- The ‘model_path’ string variable should be set to the path of the 3ds max file containing the replacement model.
- This example takes into account that the merged file contains only a single object, otherwise the first of the merged objects will be used.
- The script actually replaces the Object node of the selected objects with the Object node of the merged model (creating instances), assigning them the merged material giving them the merged object’s name appended with numbers.
from MaxPlus import FileManager from MaxPlus import SelectionManager model_path = r"D:\Models\Bar_Stool_A.max" place_holders = [] for o in SelectionManager.Nodes: place_holders.append(o) FileManager.Merge(model_path,True,True) model = SelectionManager.GetNode(0) for i in range(len(place_holders)): place_holders[i].SetObject(model.GetObject()) place_holders[i].SetMaterial(model.GetMaterial()) place_holders[i].SetName(model.Name + "_" + str(i)) model.Delete()
* note that when copying and pasting a script from this example, the indentation may not be pasted correctly.
Python for 3ds max – list scene objects
Software:
3ds max 2019
Iterating through a list of all of an object’s hierarchy or all of the objects in the scene is a very common requirement for scripted tools and utilities in 3D animation software.
Coming from a MaxScript background, I was used to just have to write the word ‘objects‘ to reference a list of all of the objects in the scene.
Unless I’m missing something obvious,
There isn’t a shortcut like this available in the 3ds max Python API.
In order to list all the objects in the scene you need to use a recursive function that will return a list of all of a node’s children, and children’s children, etc.
In the following example, the function ‘list_children()’ will return a list all of the objects in the supplied node’s hierarchy, and when given the scene’s root node via MaxPlus.Core.GetRootNode() it will return a list of all the objects in the scene.
Wrapping ‘list_children()’ within the ‘scene_objects()’ function, provides a convenient way get a list of all the objects in the scene just by calling ‘scene_objects()’.
def scene_objects(): def list_children(node): list = [] for c in node.Children: list.append(c) list = list + list_children(c) return list return list_children(MaxPlus.Core.GetRootNode()) for o in scene_objects(): print o.Name
* note that when copying and pasting a script from this example, the indentation may not be pasted correctly.
Related:
Python for 3ds max – Animated Mesh
Software:
3ds max 2019
This is an example of procedurally animating a mesh’s vertices via Python script.
Notes:
1. The model has to be converted to Editable Mesh before the script is run.
* unless the scrip will be extended to do it.
2. The model must be selected for the script to work.
import MaxPlus import math from MaxPlus import INode from MaxPlus import TriObject from MaxPlus import SelectionManager from MaxPlus import Factory from MaxPlus import Animation from MaxPlus import Point3 from MaxPlus import Control ticks_frame = 160 #Selection sel = [] for n in SelectionManager.Nodes: sel.append(n) node = sel[0] #Setup Controllers obj = node.GetObject() Tri = TriObject._CastFrom(obj) mesh = Tri.GetMesh() num_verts = mesh.GetNumVertices() mesh_anim = obj.GetSubAnim(0) pnt_ctrl = Factory.CreateDefaultMasterPointController() node.AssignController(pnt_ctrl,1) for i in range(num_verts): bezp3 = Factory.CreateDefaultPoint3Controller() bezp3.SetPoint3Value(mesh.GetVertex(i)) mesh_anim.AssignController(bezp3,i) #Animation Animation.SetAnimateButtonState(True) for t in range(100): time = t * ticks_frame Animation.SetTime(time) mesh_anim.AddNewKey(time,0) for i in range(num_verts): vert_anim = mesh_anim.GetSubAnim(i) vert_ctrl = Control._CastFrom(vert_anim) vert_val = mesh.GetVertex(i) vert_val.SetZ(vert_val.GetZ() + math.sin(((Animation.GetTime()*0.5)/(ticks_frame))+i)) vert_ctrl.SetPoint3Value(vert_val) Animation.SetAnimateButtonState(False)
* note that when copying and pasting a script from this example, the indentation may not be pasted correctly.
Python for 3ds max – Create Objects
Software:
3ds Max 2019
from MaxPlus import ClassIds from MaxPlus import Point3 import random # Define Sphere geometry object: sphere_obj = Factory.CreateGeomObject(ClassIds.Sphere) sphere_obj.ParameterBlock.Radius.Value = 5 sphere_obj.ParameterBlock.Segs.Value = 64 # Create a list of 10 sphere instanced objects: spheres = [] for i in range(10): spheres.append(Factory.CreateNode(sphere_obj)) # Move spheres to random positions for s in spheres: s.SetLocalPosition(Point3( random.randint(-50,50), random.randint(-50,50), random.randint(-50,50))) scale = 5.0 * (random.randint(30,100)/100.0) s.SetLocalScale(Point3(scale,scale,scale))
* note that when copying and pasting a script from this example, the indentation may not be pasted correctly.
3ds max – Quickly clearing materials in multiple objects
Software:
3ds max 2017
To move clear the material in multiple objects:
- Select the objects.
- In the MaxScript Mini Listener at the bottom left of the 3ds max window,
Type:
for o in $ do (o.material = undefined)
And then press Enter
3ds max – Quickly move multiple objects pivot points to a specified location
Software:
3ds max 2017
To move the pivot point of multiple objects to 0,0,0 location:
- Select the objects.
- In the MaxScript Mini Listener at the bottom left of the 3ds max window,
Type:
$.pivot = [0,0,0]
And then press Enter