maxscript performance

Use bitarrays instead of arrays when possible

example from maxscript doc (split a mesh by uv elements)

fn split_mesh_by_uv_shell node channel = (
    local ob = copy node
    converttomesh ob
    while ob.numfaces > 0 do (
        face_array = #(1)
        cnt = 0
        while cnt < face_array.count do (
            cnt += 1
            -- get data one by one, too much meshop operation
            map_verts = meshop.getmapvertsusingmapface ob channel #(face_array[cnt])
            map_faces = meshop.getmapfacesusingmapvert ob channel map_verts
            -- finditem is slow
            for f in map_faces where finditem face_array f == 0 do (
                append face_array f
            )
        )
        local shell_emesh = editable_mesh()
        shell_emesh.mesh = meshop.detachfaces ob face_array delete:true asmesh:true
        shell_emesh.transform = node.transform
        shell_emesh.name = uniquename (node.name +_uvshell)
    )
    delete ob
)

optimized version

fn split_mesh_by_uv_shell node channel = (
    local ob = copy node
    converttomesh ob
    while ob.numfaces > 0 do (
        -- use bitarray
        local shell_faces = #{1}
        local work_faces = #{1}
        while not work_faces.isempty do (
            -- get data using bitarray at a single meshop function 
            local map_verts = meshop.getmapvertsusingmapface ob channel work_faces
            local work_faces = (meshop.getmapfacesusingmapvert ob channel map_verts) - shell_faces
            -- we can add bitarray using + operator, which is much faster then append
            shell_faces += work_faces
        )
        local shell_emesh = editable_mesh()
        shell_emesh.mesh = meshop.detachfaces ob shell_faces delete:true asmesh:true
        shell_emesh.transform = ob.transform
        shell_emesh.name = uniquename (node.name +_uvshell)
    )
    delete ob
)
old optimize version
1k 108 ms 86 ms
10k 1741 ms 152 ms
20k 8654 ms 314 ms
50k 43148 ms 516 ms

Another advantage of using bitarray, we can process values easier and it\'s pretty fast

union:  A + B
subtract: A - B
intersect: A * B

Disable viewport redraws when making changes to scene objects

Use redraw context

with redraw off (
    -- your code here
)

Use redraw disable function

disablesceneredraw()
-- your code here
enablesceneredraw()

Disable max redraw by sending message to max main window hwnd

windows.sendmessage (windows.getmaxhwnd()) 0x000B 0 1
-- your code here
windows.sendmessage (windows.getmaxhwnd()) 0x000B 0 0

redraw context is the preferred one, because we have to ensure our code will not throw any exception before we re-enable redraw, which will freeze max ui.

Usually, by disabling redraw we can only get tiny performance improvement, so safety first 😉

Disable Undo system when possible

two way of undo context:

with undo on (
-- your code here
)

-- we can also use undo with redraw context
with undo off redraw off (
    -- your code here
)
undo undo label on (
-- your code here
)

Modify Panel can be slow - change to Create Panel when possible

Some operations on scene objects will reevaluate the modifier stack and also force an update of the Command Panel UI. Even if the viewport redraws are suppressed, the Modify Panel might be forced to redraw. When the modifier stack is not needed by the script (for example for setting Sub-Object levels etc.). Here are two methods to disable ui redraw.

Switch to create mode

max create mode

Disable modifier panel

suspendEditing()
-- your code here
resumeEditing()

It seams good to avoid useless update of ui, but in some case we have to update modifier panel to ensure our script work !!!!!

such as editing vertex noraml, using morph modifier, it pretty weird.