MAXtoA Scripted Plug-ins

NEW in 3ds Max 2018: MAXScript provides a simple way to create a "wrapper" plug-in with a custom UI for Arnold nodes. This approach is for plug-ins that are not shaders - shader plug-ins use a different approach.

A MAXtoA plug-in uses specially-named parameters that the MAXtoA translator understands. MAXtoA ignores other parameters and the internals of the plug-in, whether it contains logic or wraps another existing 3ds Max class. 3ds Max sees the wrapped class and plug-in logic, which will show up in the UI (viewport, modifier stack, etc depending on plug-in type), and Arnold (via MAXtoA) reacts only to the special parameters, using them to instantiate some particular Arnold node and set parameters on it accordingly.

The following plug-in types can be extended:

Parameter Layout and Naming

MAXtoA looks for exposed parameters that following a specific naming convention, and acts on those parameters accordingly. The parameter names that MAXtoA recognizes are:

Parameters are processed in the order they appear in the script, from top to bottom. Declarations must precede usage.

Enum Parameters

Arnold parameters of type enum are normally represented by and integer value starting at zero. However, MAXScript dropdown controls are one-based. Therefore, MAXtoA translates enum type parameters to one-based arrays to support dropdowns in plug-in UIs. This snippet illustrates how enums are defined and wired to a UI control.

Enum Snippet
parameters main rollout:params
(
   . . .
   arnold_node_mode type:#integer default:2 ui:mode
   . . .
)
  
rollout params " Parameters"
(
   . . .
   dropdownlist mode "Mode" items:#("Blend", "Mix", "Replace", "Add", "Sub")
   . . .
)

The parameter on the scripted node (the parameter named arnold_node_mode) will have values 1, 2, 3, 4 or 5 based on what is selected by the dropdown, however, the value actually sent to Arnold will be 0, 1, 2, 3, or 4.

Example: A Spherical Camera Plug-in

This example creates a new camera type, derived from FreeCamera, named "Spherical Cam" in the Arnold category, which simply turns on the Arnold spherical_camera node. This script sets no other parameters.

Example
plugin Camera arnold_spherical_camera
extends:FreeCamera
name:"Spherical Cam"
classID:#(135251,542126)
category:"Arnold"
replaceUI:true
(
	parameters main rollout:params
	(
		arnold_node type:#string default:"spherical_camera"
	)
  
	rollout params "Example Parameters"
	(
		
	)
)

Example: Sphere Geometry Plug-in

This example creates a new geometry type in the Arnold category called "Sphere". It extends the built-in 3ds Max sphere, so it shows up in the viewport as such. But Arnold will actually be given the mathematically exact “sphere” shape node when rendering.

Most of the code in this example enables geometry creation with the mouse and to keeping that in sync with the parameter defining the Arnold object. A much simpler piece of code could have been written had we completely ignored the wrapped object; we could have set the UI in the rollout to apply directly to the Arnold style parameters, which means no updateArnold() function would have been needed, and it could have been only a few lines.

Example
plugin Geometry Arnold_Sphere
name:"Sphere"
classID:#(0xf00df103, 0xc55744a1)
category:"Arnold"
extends:Sphere
replaceUI:true
(
    local lastSize, meshObj
    parameters pblock rollout:params
    (
        arnold_node type:#string default:"sphere"
        arnold_node_radius type:#float default:1.0
        arnold_node_center type:#point3 default:[0.0,0.0,0.0]
      
        radius type:#float animatable:true ui:radius default:1.0
    )

    fn fmax val1 val2 = if val1 > val2 then val1 else val2

    fn updateArnold =
    (
          -- Modify the Arnold Sphere
          arnold_node_radius = delegate.radius
    )
        
    tool create
    (
        on mousePoint click do
        case click of
        (
            1: nodeTM.translation = gridPoint
            2: #stop
        )
        on mouseMove click do
        (
            if click == 2 then (				
                radius = delegate.radius = fmax (abs gridDist.x) (abs gridDist.y)
                updateArnold()
            )
        )
    )  
  
    rollout params "Sphere Parameters"
    (
        Spinner radius "Radius:" range:[0, 1e9, 1]

        on radius changed val do (
            delegate.radius = val
            updateArnold()
        )
    )
)

The key part of this code is the Arnold-specific parameter declarations:

arnold_node type:#string default:"sphere"
arnold_node_radius type:#float default:1.0
arnold_node_center type:#point3 default:[0.0,0.0,0.0]

These parameters tell Arnold to build a node named ‘sphere’ and assign its ‘radius’ parameter of type float and the ‘center’ parameter of type point with the value from these variables.

Had we needed custom declared user variables (which are needed, for example, in the volume node), it would have looked like this:

arnold_node type:#string default:"volume"
arnold_node_min type:#point3 default:[-0.5,-0.5,0] 
arnold_node_max type:#point3 default:[0.5,0.5,1] 
arnold_node_dso type:#string default:"volume_openvdb"
		
arnold_decl_filename type:#string default:"constant STRING"
arnold_node_filename type:#filename default:"smoke.vdb"
		
arnold_decl_bounds_slack type:#string default:"constant FLOAT"
arnold_node_bounds_slack type:#float default:0.0

This would instantiate a node called volume as before, and set its min, max and dso parameters. But the rest of the parameters (due to the plug-in nature of volumes) are user defined, so we need to define a string parameter called "filename", a float parameter called "bounds_slack" and so on and so on.

Example: Gobo Filter Plug-in

This example is a stripped down version of the Arnold Gobo filter modifier plugin (located in <3dsmax>\Plugins\maxscript\arnoldlight_gobofilter.ms). It show case how you can add UI controls to support both a color picker and a Texmap lookup. The Arnold target parameter here is gobo.slidemap.

Example
plugin modifier Arnold_Light_Gobo
name:~ARNOLD_LIGHT_FILTER_GOBO_NAME~
category:"Arnold"

classID:#(0xf00df10d,0x4001a10d)

extends:ArnoldLightFilterModifier replaceUI:true version:1
(
  parameters main rollout:params
  (
    arnold_node type:#string default:"gobo"  
	arnold_node_slidemap type:#color ui:slidemapcolor default:[255,255,255]
	arnold_link_slidemap type:#texturemap ui:slidemap
  )
  rollout params ~ARNOLD_LIGHT_FILTER_GOBO_ROLLOUT_NAME~
  (
	  colorpicker slidemapcolor "Color" color:[255,255,255] modal:false
	  mapButton slidemap "Map"
  )
)