3dsmaxbatch plugin?

Since 3dsmaxbatch.exe doesn;t require lic.
I hope to replace maxscript job workstation mode to 3dsmaxbatch.
Any quick hack that I can use?
Or… should I wait until Thinkbox implement?

I don’t think we have plans for 3dsmaxbatch integration, but it should be possible to write a custom plugin for your specific case.

I am not sure how hard it would be.

I am going to give it a try when I have a minute, will let you know how it goes…

1 Like

Progress report:

  • Created a basic 3dsmaxbatch plugin based on the 3dsCmd plugin implementation, removed a ton of code related to DBR etc.

  • Created a basic 3dsMaxBatch Submission Workflow in SMTD to submit a job using the currently loaded scene and a custom script (MAXScript or Python) to run over it. I will make the scene optional in the future, and maybe allow external file(s) to be picked for processing instead of the current scene content.

  • Submitted a simple scene with a teapot on a plane, one light, one animated camera, Scanline Renderer, 101 frames.

  • Set the render output in the render scene dialog.

  • Used a super simple job script that reads the current Start and End Frames of the Deadline Task via the arguments dictionary maxOps.mxsCmdLineArgs, sets the render time to them, and calls the current renderer:

      opts = maxOps.mxsCmdLineArgs
      rendStart=(opts[#startFrame]) as integer
      rendEnd=(opts[#endFrame]) as integer
      max quick render
  • Partial log from the first Task:

This is of course just a simple proof of concept. I will try some more complex stuff like creating and modifying the scene content, saving the scene out, setting the render parameters and output via the script, etc.

I also need to figure out which SMTD parameters make sense to support and which ones to hide.

When I have something usable, I will post it here…

1 Like

Fun in the sun - since the script is currently not included as an auxiliary file but is referenced via the Job Metadata (will make this optional in the future), I could modify it while the job was running for some colorful results:

opts = maxOps.mxsCmdLineArgs
rendStart=(opts[#startFrame]) as integer
rendEnd=(opts[#endFrame]) as integer
theMaterial = standardMaterial diffusecolor:(random black white)
for o in geometry where classof o != TargetObject do o.material = theMaterial
max quick render

A small modification to render each object with a unique random color on each frame:

opts = maxOps.mxsCmdLineArgs
rendStart=(opts[#startFrame]) as integer
rendEnd=(opts[#endFrame]) as integer
for o in geometry where classof o != TargetObject do 
	theMaterial = standardMaterial diffusecolor:(random black white)
	o.material = theMaterial
max quick render

I then added the line

saveMaxFile (getFilenamePath rendOutputFilename + getFileNameFile maxFileName + rendStart as string + ".max")

to the end of the script and it saved the modified scene with the random colors for each frame. I need to convert the frame number to a padded value eventually, but in principle it seems to work well.

1 Like

I made some further changes - the script is now always submitted as auxiliary file with the job to avoid unintended modifications to the output as shown in my previous post. One would have to edit the auxiliary file copy to do that.

On the other hand, the scene file submission respects the SMTD settings for submitting the scene with the job as auxiliary file, or referencing a custom, global, or original path network location via the SceneFile= key value.

I also added 3 options for scene submission - all working well. Default is submitting the current scene, optionally you can select a file from disk, or no file at all. In the last case, the submitted script must construct the scene procedurally starting from nothing.

I also added support for most relevant properties in the SMTD UI.

Here is a WIP UI from the SMTD Workflow:

1 Like

Ok, here is a super early Alpha WIP use-at-your-own-risk version of the 3dsmaxbatch plugin:

3dsmaxbatch_20210507.zip (14.3 KB) - REMOVED. See here for a new version.


  • Copy the file SMTDWorkflow_3dsmaxbatch.ms from the ZIP into your (Repo)\submission\3dsmax\Main\Workflows\ folder.
  • Copy the 3dsmaxbatch folder from the ZIP into your (Repo)\plugins\ folder.
  • Start SMTD in 3ds Max 2018.4 or higher - note that the 3dsmaxbatch in 2018 prior to PU4 was different and incompatible. It did not exist prior to 2018, so older 3ds Max versions are not supported at all.


  • Once the SMTD UI opens, select the new “Submit 3DSMAXBATCH Job To Deadline” Workflow.
  • The 3dsMaxBatch: Script And Scene rollout contains three major areas:
    • The Batch Script File is mandatory. This is the script that will be run by 3dsmaxbatch.exe. It can be MAXScript or Python, and can do anything that can be done in 3ds Max. It will be sent as the first auxiliary file of the Job, so it can be located on a local drive or network share - either way a copy of it will be sent to the Repository.

      • You must use the […] button to pick a file, you cannot edit the text in the field.
    • The Scene File is optional. Radio buttons let you select one of the following options:

      • Submit Current Scene will save a copy of the scene according to the setting of the Assets tab > Scene and Asset Files rollout - either copied as the second auxiliary file with the job, or will be referenced via SceneFile= in the Plugin params.

      • Submit External .MAX File will use a scene file from disk. It will also respect the Assets tab > Scene and Asset Files rollout settings and will be either copied as the second auxiliary file with the job, or will be referenced via SceneFile= in the Plugin params.

        • The path is displayed only when the second radio button is checked.
        • You must use the […] button to pick a valid file, you cannot edit the path manually.
        • The file can be modified via the Job Properties > 3dsmaxbatch Settings dialog.
      • No Scene - Create In Script will launch an empty 3dsMax scene. No scene file will be sent with the Job. It is up to you to generate content using the script.

      • In all 3 cases, the script can save the modified scene to any network path as part of the job.

    • Listener Log Path - This is optional and lets you specify a folder where each Task will write the script Listener Log file. The name of the log will look like mxslog_(jobName)_(TaskID).log, for example “mxslog_3dsmaxbatchtest_1.log” if the Job was called “3dsmaxbatchtest” and this was Task 1. If you re-render the same Task multiple times, old logs will be overwritten. If you don’t specify a path, the Listener output will not be captured. You can use print() and format() calls in your script to write to the Listener.

  • The 3dsMaxBatch: Custom Values rollout lets you define 10 custom strings and 10 custom values. They are all optional and can be used to pass data to the script via the command line arguments of 3dsmaxbatch.
    • The strings can contain anything except for quotation marks (double-quotes will be replaced with single quotes when entering), and the values can contain any MAXScript values like numbers, transform matrices, Point3 values etc.

  • They can be accessed from the Job’s script using maxOps.mxsCmdLineArgs[#CustomStringN] and maxOps.mxsCmdLineArgs[#CustomValueN] where N is an integer from 0 to 9. For example if you enter “Bobo was here” in the Custom String 0 field and submit a job, your script can do print maxOps.mxsCmdLineArgs[#CustomString0] and you will see “Bobo was here” in the Listener Log.

  • The strings and values are exposed to the Job Properties > 3dsmaxbatch Settings panel and can be changed after submission to modify how the script behaves.

  • The rest of the SMTD rollouts have been reduced to only the controls that make sense.

I am sure there are a lot of bugs in the current version. Please report them in this thread!

1 Like

Dang… you are still a machine.
Thanks a lot!!!

How would I access all these from MXS?
I assume there is a new method for 3damaxbatch job?

also I think we should have this exposed.

-i arg

The 3ds Max config file (.ini). Defaults to the per-user default config file (3dsmax.ini).

-p arg

The 3ds Max Plugin config file (.ini). Defaults to the per-user default plugin config file (Plugin.UserSettings.ini) 

And a way to pass mxs value with method.
-mxsValue arg

MAXScript Value Parameter option, where arg = <key>:<value>.

<value> will be accessible as a MAXScript value in <script_file> through the maxOps.mxsCmdLineArgs dictionary using <key> as the dictionary key.

The <value> parameter must be enclosed in quotation marks.

Not sure what you are asking. The extra values and strings I exposed use the -mxsValue and -mxsString flags to pass data to the job, and you then use themaxOps.mxsCmdLineArgs[] dictionary to access by name.

For example, if you enter “bobo was here” in the Custom String 1, then in the job script you do

str1 = maxOps.mxsCmdLineArgs[#CustomString1] 
print str1

and the Listener log (if enabled) will show “bobo was here” as expected.

The same with values, except that they end up being MXS values and not just strings (but they are passed as strings via the job metadata). I added some precautions to the UI to ensure only valid MAXScript values are passed, but there are cases I am not handling. For example, if you select an object in the scene and type in the Custom Value 1 field $, the value will be set to something like

$Teapot:Teapot001 @ [-1.355936,-1.807916,0.000000]

This will of course have no meaning once passed through the submission to the job script. (I might add extra tests to avoid node values from being entered). You could pass the $.inode.handle instead, and resolve on the job script side using

maxOps.getNodeByHandle (maxOps.mxsCmdLineArgs[#CustomValue1] )

Or pass the $.name and resolve using getNodeByName() on the script side…

But if I enter $.pos in the Workflow’s UI, it will expand to [-1.35594,-1.80792,0] and that will travel through the metadata and be read as a Point3 value on the Job Script’s side. I tried in my test script

print maxOps.mxsCmdLineArgs[#CustomValue1].x

and it printed -1.35594 in the Listener Log.

I hear you about the custom plugin and config files. The regular 3dsmax plugin handles those within the custom plugin code, here I just need to expose two more text fields and pass the data to the job.

Now that I think about it, I could make both the name and the value customizable. So you would have two fields - one defining the key name, and one defining the value. Then, you could enter “MyVar1” in the first field, and $.pos in the value field, and then on the script side you would use maxOps.mxsCmdLineArgs[#MyVar1].x instead of indexing by #CustomValue1. I thought that using numbered slots with static and well-defined names would be easier, but it is not as flexible as naming your slots to make the script read better…

I can default all slot names to the current CustomValueN and CustomStringN patterns, so it would even be backwards compatible with the first iteration of the Workflow.

Something like this :slight_smile:


I was asking how can I send 3dsMaxbatch job with SMTDSettings struct.

Here is an example of loading and calling the SMTD Workflow outside of the SMTD UI. You must have loaded the SubmitMaxToDeadline_Functions.ms before that.

	global SMTDWorkflow_3dsMaxBatch
	local the3dsmaxbathWorkflowFile = @"C:\DeadlineRepository\submission\3dsmax\Main\Workflows\SMTDWorkflow_3dsmaxbatch.ms"
	fileIn the3dsmaxbathWorkflowFile --change the code above to detect your Repo, or hard-code to your Repo path
	SMTDWorkflow_3dsMaxBatch.restoreSettings() --load settings from the .MAX file, if any
	if not doesFileExist SMTDWorkflow_3dsMaxBatch.BatchScriptFile do SMTDWorkflow_3dsMaxBatch.BatchScriptFile = @"path\to\script.ms"
	if not doesFileExist SMTDWorkflow_3dsMaxBatch.SceneFile do SMTDWorkflow_3dsMaxBatch.SceneFile = @"path\to\maxscene.max" --if you want an external file
	if not doesFileExist SMTDWorkflow_3dsMaxBatch.ListenerLog do SMTDWorkflow_3dsMaxBatch.ListenerLog = @"path\to\listenerlogs.log" -- only if you want it
	SMTDWorkflow_3dsMaxBatch.SubmitSceneMode = 2 --1 for current scene, 2 for external file, 3 for no scene
	SMTDWorkflow_3dsMaxBatch.CustomString0Name = "BoboString"
	SMTDWorkflow_3dsMaxBatch.CustomString0 = "Bobo was here"
	--you can modify all 10 custom strings
	SMTDWorkflow_3dsMaxBatch.CustomValue0Name = "ObjectPos"
	SMTDWorkflow_3dsMaxBatch.CustomValue0 = [100.0,200.0,0.0]
	--you can modify all 10 custom values
	local canSubmitResult = SMTDWorkflow_3dsMaxBatch.canSubmit() --check if submission is allowed
	format "%\n" canSubmitResult[2] --print the result of the test
	if canSubmitResult[1] == true do --if submission is allowed, call the submit function

This code will work with the next version I am working on right now. The same principles apply to the first version I dropped, except the CustomStringXName and CustomValueXName properties do not exist there.

The script will use some of the SMTDSettings like Pools, Groups, Priority, etc. Basically anything that is shown in the SMTD UI. You can find a full list by looking at the SubmitJob function - I write my own Job files there, so it is a very small subset of SMTDSettings that are being reused. You can set them in your own code before calling the submit function.


Here is WIP v2 from May 11, 2021:

3dsmaxbatch_20210511.zip (16.9 KB)


  • Added Key Names for custom Strings and Values.

  • Added alternative 3dsmax.ini and plugin.ini support - both sent as auxiliary files with the job.

    • The Plugin Info will contain two keys pointing at the argument indices, e.g.

    • These cannot be edited, they are for internal use only. They won’t be included if the respective files are not included.

    • The 3dsMax Settings panel exposes both the Key Name and Key Value - see screenshot in a previous post.

  • Added buttons on top of the Custom Strings and Values lists to reset all Keys and all Values.

  • Added the ability to reset the file names of the Script, Scene, Listener Log, and Alt. Config files by right-clicking the […] button. Added tooltips to inform the user about the new option.

  • Key Name validation will only allow lower and Capital case letters and numbers, all extra symbols will be replaced with underscore, e.g. entering “Object Pos.” will be changed to “Object_Pos_”

  • If the same Key Name is entered twice, an index with underscore prefix will be added, e.g. if you enter “ObjectPos” and then again “ObjectPos” in the next custom value field, the new entry will change to “ObjectPos_2”.

  • Updated all 3dsMaxBatch rollouts to show info when collapsed.

  • Fixed some bugs.

1 Like

So… in theory, if we have a custom MXS submit code that using Deadline command line utility, I can just point to this plugin type and and supply Batch Script File path?

If you set Plugin=3dsmaxbatch in the Job Info Params and provide the script file as first auxiliary file of the deadlinecommand call, then I would say the rest of your existing submission code for the 3dsCmd plugin should work.

But I have not tested that theory. Let me know how it goes.

so… working on an in-house 3dsmaxbatch plugin based on your plugin.
I found out DeadlineTuil.SetMessae is not working.
Could you confirm?

It works in my commandline-based plugin:


def RenderTasks( self ):
    # Render frame(s) of job using CmdController class
    self.Plugin.SetStatusMessage ('Rendering 3dsMaxBatch Tasks')

I copied this. But, setting progrses is not working.

self.AddStdoutHandlerCallback( ".*Progress: (\d+)%.*" ).HandleCallback += self.HandleProgress       

def HandleProgress( self ):
    progress = float( self.GetRegexMatch(1) )
    self.SetProgress( progress )

One more question. I want to bypass some plugins “Failed to initialize” error. I added an popup handler. It doesn’t do anything…

Privacy | Site terms | Cookie preferences