3ds Max - Integrated Submitter - Workflows

Workflow System Overview

Starting with Deadline 10, the 3ds Max integrated submitter (a.k.a. SMTD) added support for dynamic customizable submission modes called “SMTD Workflows”.

Workflows can ship as part of the Deadline installation, or can be added by the user or 3rd party developers.

Workflows are implemented as a kind of “plugin extension” to SMTD, with the installation consisting merely in copying one or more files into a dedicated folder.

A Workflow can provide:

  • A function to determine whether the Workflow should be enabled based on custom logic (e.g. if a plugin is installed),
  • A custom User Interface Layout with existing or new tabs and rollouts,
  • Custom controls visibility / enabled states in existing SMTD rollouts,
  • Custom workflow-specific rollout definitions,
  • Custom sanity check logic to enable/disable the SMTD SUBMIT button,
  • Custom SUBMIT button tooltip text,
  • Custom submission logic executed when the SUBMIT button is pressed.

Custom Workflow Installation

A workflow consists of at least one MAXScript file defining a Workflow Struct with a set of mandatory, optional and user-defined properties and functions. More script files could be part of the Workflow, for example a file to be sent with the job to run a MAXScript Job on the Deadline Worker.

  • The main workflow script must be named according to the pattern SMTDWorkflow_<workflowname>.ms.
  • It must be copied into the \DeadlineRepository\submission\3dsmax\Main\Workflows\ folder.

Several Workflows ship with Deadline and can be used as examples, or as starting points for new Workflows. They include

  • A Bake Textures Job submitter
  • A FumeFX Simulation Job submitter
  • A Phoenix FD Simulation Job submitter
  • A V-Ray Standalone Render Job submitter

When the SMTD UI is launched in 3ds Max, it will scan the Repository’s Workflows folder for .MS script files matching the mandatory name pattern SMTDWorkflow_*.ms, and will evaluate each of them.

  • The script evaluation must return a struct with the expected mandatory properties and functions, otherwise the definition will be ignored.
  • Optional properties and functions will be assumed to have default values if they are not defined.
  • If the evaluation fails due to an error in the script’s code, the Workflow will be ignored.
  • If the isWorkflowActive() function of the Workflow Struct returns false or is not defined, the Workflow will not be added to the UI.

Custom Workflow Struct Definition

Mandatory or Required Functions

The main Workflow definition script must return an instance of a MAXScript Struct with at least the following mandatory properties and functions:

fn isWorkflowActive = ( <boolean> ),

  • This function must return true for the Workflow to be displayed in the SMTD UI.
  • You can hard-code the function to return false when you want to disable the workflow within the company.
  • You can define custom logic by evaluating the conditions on the specific workstation running SMTD, for example a workflow depending on V-Ray could be disabled if V-Ray is not installed:

For Example:

fn isWorkflowActive = (isKindOf VRay RendererClass),

fn submitJob = ( <custom submission code> )

  • This function defines the custom submission logic executed when the SUBMIT button is pressed.
  • If the function is not defined but isWorkflowActive() returns true, the Workflow UI will still be loaded, but pressing the SUBMIT button will do nothing.
    • In other words, the function is necessary to perform meaningful submission work, but it is technically not required for a Workflow to exist in the UI.
    • This means that you can work on a Workflow’s UI and have it appear in the SMTD UI without having any submission logic implemented yet.
  • This function can make calls to any functions in the SMTDFunctions struct to create Job files and perform the actual submission.
  • It can also implement its own Job control files creation and submission logic.

Optional Standard Properties And Functions

The main Workflow definition script can implement the following optional, but strictly named properties and functions:

WorkflowName = “<namestring>”,

  • This property defines a unique name used by SMTD to identify the workflow when saving/loading SMTD settings.
  • The name must be unique to avoid collision with other Workflows.
  • If this property is not defined, the file name of the Workflow script itself will be used instead.
  • Note that the name will also be used to generate a hash used for storing the Workflow’s own settings with the .MAX Scene file.
    • Changing the name after the fact would cause the Workflow to store its settings and attempt to load them at a different “address”.
    • Thus, it is a good idea to define this name early on in the development of the Workflow and to avoid changing it.
  • The name string is case-sensitive!

WorkflowTitle = “Submit <Something> To Deadline”,

  • This property provides the description of the Workflow.
  • It is displayed in the Workflow: drop-down list on top of the SMTD UI.
  • If not defined, the Workflow script’s file name will be used instead.
  • The string is not used for any identification and is case-insensitive.
    • Thus it can be modified at any time as needed.

Description = “<text describing in more detail what the Workflow does>”,

  • This optional property provides a more detailed description of the Workflow’s functionality.
  • It will be used for the tooltip of the Workflow: control in the SMTD UI.
  • It will be assumed “” if the property is not defined, thus showing no tooltip.
  • It can also be used as the tooltip of the SUBMIT button if the Workflow does not define a CanSubmit() sanity check function to provide the button’s tooltip text.

fn defineUILayout = ( #( #( #(“Tab Name”, “Tab Description”), #(#(RolloutName, bool_rolleddown),…), … ) )

  • Defines the custom layout definition which lists the tabs and their rollouts and the rollout rolled down states.
  • If not defined, the default SMTD layout showing all available tabs and rollouts will be used.

For Example:

fn defineUILayout = --Optional. If not defined, the default legacy layout with all rollouts will be used
(
  #(
    #(#("Job","Job Settings"),#(#(SMTD_CustomJobRollout,true), #(SMTD_JobOptions,true), #(SMTD_JobFailureDetection,false))),
    #(#("Assets","Assets - Asset Collection And Synchronization"), #(#(SMTD_AssetList,true))),
    #(#("Render","Rendering Options"),#(#(SMTD_ScenePreProcessing,true), #(SMTD_MaxStartup,false))),
    #(#("Options","Submission Options"),#(#(SMTD_UserOptions,true), #(SMTD_SubmissionTimeouts,false))),
    #(#("Limits","Deny List Management and License Limits"),#(#(SMTD_BlackListSlaves,true), #(SMTD_LimitGroups,false)))
  )
),

In the above example,

  • the SMTD_CustomJobRollout is a custom rollout defined in the Workflow script, and it is open by default.
  • the SMTD_JobOptions rollout is the default Job Options rollout of SMTD, and is also open by default.
  • the SMTD_JobFailureDetection is the default Job Failure Detection rollout of SMTD and it is closed by default,
  • and so on…

fn updateUILayout = ( <custom UI-related code> ),

  • This optional function is called after the UI Layout has been built.
  • It can be used to modify the visibility or enabled state of existing rollout’s controls, for example dynamically hide any controls not relevant to the current Workflow.

For Example:

fn updateUILayout =
(
  local disableArray = #("btn_chunk", "spn_chunkSize","chk_restartMax", "chk_forceWorkstationMode", "chk_useSilentMode", "ddl_MaxVersionToForce", "chk_oneCpuPerTask", "chk_EnforceSequentialRendering", "btn_MaxVersionToForce")
  for c in SMTD_JobOptions.controls where findItem  disableArray (c.name as name) > 0 do
  (
    c.enabled = false
    try(c.tooltip = "Not available in this Workflow")catch()
  )
),

In the above example, assuming the standard SMTD_JobOptions rollout was added to the layout, the updateUILayout() function will

  • Disable the controls listed in the disableArray array
  • Set their tooltips to “Not available in this Workflow”, if supported (various controls added tooltip support in different versions of 3ds Max).

fn storeSettings = ( <custom store workflow settings code> ),

  • This function will be called when switching Workflows, and by a FilePreSave callback to ensure the Workflow’s own settings are stored in the MAX file or on disk.
  • Any storage implementation including INI file, or storing with the .MAX scene file can be used.
  • The default approach for the shipping SMTD Workflows is to call SMTDFunctions.storeWorkflowSettingsWithScene() with the Workflow Struct as by-reference argument.

For Example:

fn storeSettings =
(
  SMTD_MainRollout.Ui_report (">Custom Workflow: Storing Settings With Scene...")
  SMTDFunctions.storeWorkflowSettingsWithScene &SMTDWorkflow_WorkflowName
),

In the above example, the function will call another function implemented by the SMTD backend library, which will

  • Handle the saving of all custom properties with the 3ds Max scene;
  • Automatically skip the standard Struct properties .WorkflowName, .WorkflowTitle and .Description;
  • Automatically skip any functions defined in the Struct.

fn restoreSettings = ( <custom restore workflow settings code> ),

  • This function will be called after switching to a new Workflow, and by a FilePostOpen callback to ensure the Workflow’s own settings are restored from the MAX file or from disk.
  • Any storage implementation including INI file, or storing with the .MAX scene file can be used, as long as it matches the method used in storeSettings().
  • The default approach for the shipping SMTD Workflows is to call SMTDFunctions.restoreWorkflowSettingsWithScene() with the Workflow Struct as by-reference argument, and an optional list of properties to skip.

For Example:

fn restoreSettings =
(
  SMTD_MainRollout.Ui_report (">FumeFX Workflow: Restoring Settings From Scene...")
  SMTDFunctions.restoreWorkflowSettingsFromScene &SMTDWorkflow_FumeFX propsToSkip:#()
),

In the above example, the function will call another function implemented by the SMTD backend library, which will

  • Handle the loading of custom properties from the 3ds Max scene;
  • Skip the loading of any properties whose names are supplied via the propsToSkip: keyword argument.
  • The latter can be useful when properties of the Struct are used for temporary data storage and should not be restored on scene loading.

fn CanSubmit = ( #(<boolean>, <string>) ),

  • This optional function implements a Workflow-specific Sanity Check
  • It is called to enable/disable the SUBMIT button, and to define its tooltip according to the results of the Sanity Check.
  • It must return an array containing a Boolean and a string with a description in the form #(true, “Description”) or #(false, “Reason”), where
    • true means enable the button and the string defines the tooltip describing what the submission will do
    • false means disable the button and the string explains why it was disabled.
  • Assumed to be #(true, <struct>.Description) if the function is not defined, where the Description may be “” if the property is not defined either.

Optional Custom Properties And Functions

The Workflow Struct can define custom properties and functions that are not directly expected by the SMTD Workflows subsystem, but might be necessary for the operation of the Workflow itself.

  • The main benefit of defining custom properties in the Workflow Struct is that if the storeSettings() and restoreSettings() functions are implemented and using the standard scene storage mechanism, these custom properties will be automatically stored and restored.

    For Example:

    FumeFXObjectsToSim = #(),
    SimCacheOutput = "",
    UseSimCacheOutput = false,
    PermanentSceneChange = false,
    

    In the above example taken from the FumeFX Simulation Workflow shipping with Deadline,

    • The custom properties define the list of objects to simulate,
    • The output path override filename,
    • Two boolean properties controlling whether to apply the override, and whether to make the changes permanent.

Submission Function And Custom SMTD Settings

When performing a custom submission, especially when relying on the SMTDFunctions to generate Job control files and submit the job, a large number of the existing SMTDSettings could get in the way. For example, if the default settings of SMTD call for Restarting the renderer after each frame, but the Workflow is performing a FumeFX Simulation submission, this particular option must be overwritten and set to false.

There are several hundred SMTDSetting properties to worry about, and setting them all to new values would be unreasonable. A possible way to deal with them en masse is to

  • Grab a copy of the current SMTDSettings struct in a variable,
  • Reset SMTDSettings to Factory Defaults, or to the User Defaults / Sticky Settings defined in the Repository and the local machine,
  • Set only the relevant options exposed by the Workflow’s UI by reading from the copy created in the first step and setting in SMTDSettings.

In addition, SMTD’s own submission code will grab a copy of all SMTDSettings before calling the SubmitJob() function in the Workflow’s Struct, and will copy these values back into SMTDSettings once the submission has finished. This lets you apply any changes to SMTDSettings within the SubmitJob() function without a worry that they might stick around.

Note that when the scene is saved to a .MAX file for submission, the custom Workflow-specific SMTDSettings will be automatically baked into that .MAX file. Should you ever open the .MAX file submitted with the Job, the SMTD UI will load and show you the actual settings enforced by the Workflow. Once the submission is finished, the settings in the current scene will be restored back to what they were before the SubmitJob() function was called. This means that saving the scene to a .MAX file manually after a Workflow submission will not store any temporary settings the SubmitJob() function might have enforced during submission.

Workflow User Interface Considerations

The Workflow Layout definition can contain

  • Any of the existing Tabs
  • New Tabs, if required by the Workflow
  • Any of the existing Rollouts in the same Tabs as in the default layout
  • Any of the existing Rollouts in new Tabs, if that makes more sense
  • Completely new rollout definitions in existing or new Tabs - usually at least the main controls of the Workflow will be hosted in a new custom rollout.

Due to the large amount of rollouts exposed in the Default layout, it is highly recommended to use the Workflows to significantly reduce the UI complexity and only expose rollouts and controls that actually make sense for the Workflow in question.

An existing rollout might contain too many controls that are irrelevant to the current Workflow. Several approaches are available in such cases:

  • The rollout could be displayed As Is, and its irrelevant controls could be simply ignored when performing the submission.
  • The irrelevant controls could be disabled in the updateUILayout() function of the Workflow Struct. See the Phoenix FD Workflow as an example.
  • The irrelevant controls could be hidden by setting the .visible property to false in the updateUILayout() function of the Workflow Struct.
    • In this case, the remaining controls could be reordered by setting their .pos property to regroup and make the rollout look cleaner
  • If hiding too many controls would make the rollout look too empty, you might consider reimplementing only the relevant controls is a custom rollout definition, while affecting the same SMTDSettings.
    • You could copy&paste portions of the original SubmitMaxToDeadline.ms source found in the submission3dsMaxMain folder.
    • See the FumeFX Simulation Workflow for an example of this approach - it redefines the “Job Properties” rollout with just the relevant controls.