Custom UI for Third Party Shaders - Arnold for 3ds Max
The MAXtoA Plugin and Shaders
The MAXtoA plugin is responsible for the integration of Arnold shaders in 3ds Max. This integration allows all built-in shaders as well as third party shaders to be integrated into 3ds Max and used in the course of rendering scenes.
Arnold's built-in plugins and shaders are automatically loaded by MAXtoA. Third-party shaders must be placed into the MAXtoA directory or a directory in the plugin path (as set in the Render dialog) to be loaded. However, it is the presence of the MAXtoA plugin that makes this integration possible.
MAXtoA is responsible for mapping Arnold shader nodes and building the matching 3ds Max materials and textures, maintain their integrity, and build a user interface so that 3ds Max users can interact with the Arnold shaders.
This user interface integration is automatic, and the shader developer does not have to do anything. Arnold shaders will be automatically loaded in 3ds Max and visible in the Material editor when Arnold is set as the ActiveShade or Production renderer.
Arnold shaders in the Material Editor
From that moment, shaders can be created by selecting them in the tree view of the material editor and dragging and dropping the node on the canvas or double-clicking the name, like any other 3ds Max material or map.
- Any shader returning a CLOSURE will show up in 3ds Max as a Material.
- Any shader returning any other type will show up in 3ds Max as a Map.
Shaders are located under the Arnold category of the Map/Material Browser. They are categorized according to metadata (more on this below).
If a shader lacks categorization, it will be categorized under the name of the DLL it is loaded from, the "OSL" category if it is an OSL shader, or the "Built-in" category if it is built-into the Arnold core.
The shader will display its attributes as defined by the shader developer. Double-clicking the shader (or in 3ds Max terms, the Material or Map) will trigger the user interface of the shader to be created and displayed in the right pane of the material editor.
UI Customization overview
Shader developers can, if they wish, customize the user interface of their shader. There are two ways:
- Using metadata
- Using Qt ".ui" files.
Metadata allows renaming, grouping, and reordering of the controls, but does otherwise not affect the layout, whereas using .ui files allows designing a fairly complex custom user interface for the shader.
Automatic User Interface
MAXtoA provides the shader developer an automatic mechanism that creates the user interface for any shader. The developer has nothing to do but to make their shader available to 3ds Max.
For the sake of documentation, a simple shader with support files is provided. The Kick utility can be used to list the shader attributes. The command 'Kick -info simple' will generate this output:
Type Name Default
------------ -------------------------------- --------------------------------
INT integer -3
UINT unsigned_int 4
FLOAT float 1.92
BOOL boolean false
RGB color 0.7, 0.7, 0.7
RGBA acolor 1, 0, 0, 1
POINT point 1, 2, 3
POINT2 point2 5, 6
ENUM elements space
The generated UI will look something like this when no custom UI is defined. As you can see - the parameter names are used as a label, and each parameter that is linkable is a button at the end used to select an input.
A second rollup is created which contains only the parameter mapping and a control to enable/disable the connection.
The generated user interface is clean and can be used pretty much as-is. Note that the parameter names are 'beautified'; parameter names that contain underscores are split with spaces, and the first letter of every word is capitalized, so;
unsigned_int -> Unsigned Int
Customizing User Interface
To be able to build a custom user interface, we need to understand the parameter mapping between Arnold and 3ds Max and know which control type to use.
For every Arnold shader, we generate some 3ds Max (1 or 3) parameters depending on if the parameter is linkable or not.
As you can see from the following - parameter unsigned_int has two controls in the parameter rollup - the number, and a slot to put a map into. A third one (to enable the map) can be found on the Maps rollout.
So for our "simple" shaders parameter named unsigned_int, MAXtoA will generate the parameters unsigned_int, unsigned_int.shader and unsigned_int.connected. Note that parameter names are case sensitive.
When MAXtoA generates the UI, it will create two rollups (Parameters and Maps) and layout the various controls in a grid layout.
Parameters type to control type is done automatically in this case.
Metadata UI customization
The first level of customization of the shader UI can be achieved using a metadata file. This file must have the same base name as the shader DLL. So in our example, we have a sampleShader.DLL and a sampleShader.mtd file.
Attribute Name
The first customization we can do and the most obvious is to provide a user-friendly name for parameters. This can be achieved by adding a few lines for every attribute of the shader. Here is our shader UI with friendly names.
Through attribute parameters, users can control numeric ranges, add tooltips, etc.
[node simple]
...
[attr unsigned_int]
max.label STRING "Unsigned Integer"
desc STRING "This is the UNSIGNED INTEGER tooltip"
min INT 0
max INT 6
Shader Parameter Ordering
Another way to customize the shader UI is to provide parameter ordering. This needs to be done at the [node] level.
[node simple]
max.order STRING "boolean integer unsigned_int color acolor string"
Parameters that are not in the list are added at the end. Parameter names that do not exist are ignored.
Rollup Generation
For shaders with a large number of parameters, the user can specify grouping through the folder parameter.
[node simple]
max.parm.folder.folder1 STRING "Rollup1;2;Rollup2;3"
Note that when specifying folder info - only the parameter count specified will be shown. Better be safe and add a third rollup that will pickup the remaining parameters.
Custom UI Through Qt .UI Files
Custom UI is a mechanism that allows the shader designer to completely design the UI to be used to manipulate the shader parameters.
UI files can be edited using Qt Designer, which can be freely downloaded, and the file format is described here (http://doc.qt.io/qt-4.8/designer-ui-file-format.html).
MAXtoA uses the Qt widget name to map the UI controls to the MAXtoA parameters as found when inspecting the shader DLL. The location of the UI files is relative to the location of plugins being loaded.
So for any shader, a user can create a subdirectory where they will save their UI files. Through metadata specifications, MAXtoA will be able to locate and load the UI files and use them to build a custom user interface. The UI files location is as follow:
<shader-location>/MAXtoA_ui/<Shader-Name>/<ui-files>
For example the standard_surface shader UI files are located in:
<MAXtoA dir>/MAXtoA_ui/standard_surface
In our current distribution, you can find seven UI files: basic.ui, coating.ui, emission.ui, special.ui, specular.ui, sss.ui and transparent.ui in the MAXtoA_ui/standard_surface directory. The metadata file allows us to describe what we want to do for the UI for the standard_surface shader, which is as follows:
Mapping Controls
To achieve this, the developer needs to know which controls can be used to edit which type of parameter. Note that max.parm.folder.folder1 and custom UI are incompatible. Parameter types need to be associated correctly to control types in the .ui file. Here is a list of Arnolds parameter types and the best match control to use.
Arnold | Control |
---|---|
INT, UNIT, BYTE | MaxSDK::QMaxSpinBox |
BOOLEAN | QCheckbox |
ENUM | QComboBox |
FLOAT | MaxSDK::QMaxDoubleSpinBox use MaxSDK::QMaxWorldSpinBox if units are required |
Bitmap | QPushButton |
Shader | QPushButton |
String | QEditField |
POINT, VECTOR | MaxSDK::QMaxPoint2Spinner |
POINT2 | MaxSDK::QMaxPoint2Spinner |
POINT3 | MaxSDK::QMaxPoint3Spinner |
MATRIX | MaxSDK::QMaxMatrix3Spinner |
RGB, RGBA | MaxSDK::QMaxColorSwatch |
There are a few ways to create a 3ds Max control, but the easiest (besides editing the UI file by hand) is to use Qt Designer and follow this procedure:
- Drag-and-drop the appropriate widget type into a new form of type widget.
- For controls that are not standard to Qt, drag and drop a control "widget".
- Using the newly created widget, select from its contextual menu "Promote To...".
- Select the appropriate base class (see list above).
- Input the appropriate max class name (from list above).
- Let the system generate a header file and click Add.
- Press promote.
In general, building a custom UI is simple - but there are a few rules that need to be followed:
- Do not make the rollup wider than 300 pixels.
- Do not set a hardcoded size for the widgets but instead, once all widgets are laid on the parent widget, create a grid layout that will manage the size of the child widgets. This gives the best performance, specifically for HDPI display.
Parameter Name Convention
As mentioned previously, for every Arnold parameter, MAXtoA will generate 1 or 3 parameters, depending on if it is connectable or not. And the ".connected" and ".shader" parameter automatically gets added to the Maps rollout.
But if one wants these to show up also on the main pages of the UI (e.g. for small map buttons etc.), the way to add these parameters to the custom UI is to use the proper control and name the widget with the parameter name.
So for unsigned_int.connected, the user should create a checkbox control and name it accordingly. Unfortunately, Qt Designer does not allow period '.' characters to be used as widget names. To solve this, MAXtoA will understand the parameter name unsigned_int__dot__connected and programmatically automatically replace the "dot" with "."
In order for the tooltip to function for a custom UI label, the user must name the label widget with the parameter name followed by _label. For example for the parameter count, the label widget should be named count_label.
MAXtoA Supported Metadata Parameters
Metadata files follow Arnold's metadata specification. See Metadata Files. Note: Documentation specifies "As a convention, we are using metadata names starting with "maya." for Maya specific metadata, and "xsi." for XSI specific metadata. There are some other conventions for standard metadata elements that would be published on a separate document."
MAXtoA supports a number of metadata tokens. For node sections [node shader-name]
max.hidden | bool | The shader will not be visible in max |
max.help_url | string | A help link |
max.category | string | The category |
max.label | string | The label |
max.parm.folder.folder[0..9] | string | For auto-UI mechanism Describes the rollup names and the number of parameters Ex: max.parm.folder.folder1 STRING "Diffuse;6;Specular;9" |
max.order[0..9] | string | For auto-UI mechanism Describes the parameter order. You can extend the parameters list by using max.order[1...9] |
Node example:
# comment
[node standard]
max.category STRING "Shading"
max.parm.folder.folder1 STRING "Diffuse;8;Specular;10"
max.order STRING "folder1 Kd_color Kd direct_diffuse "
max.order2 STRING "Ks_color Ks direct_specular indirect_specular"
For attributes sections [Attr attribute-name]
max.type | string | |
max.label | string | User parameter name |
max.disable_when | string | Disable control when... (need explanation) |
min | int | Range minimum |
max | int | Range max |
desc | string | Description (tooltip) |
linkable | bool | Define if the parameter can be connected to a shader output |
Other attributes can be used in the case of a custom user interface.
Note attribute
max.rollup | string | Describes the rollup custom UI file names Ex: max.rollup STRING "diffuse;specular" In this case, there will be a diffuse.ui and a specular.ui files in the MAXtoA_ui/ |
Example:
max.rollup STRING "diffuse;specular;reflection;refraction;sss;emission;aov"
[Attr rollup-<ui-name>]
max.label | string | Rollup user title |
Example:
[attr rollup-diffuse]
max.label STRING "Diffuse"