Changing render output based on rendered frame?

Hi there,

I’m trying to solve a problem here:

I need to render a few thousand scene files with various material assigned to certain objects.

My thinking was that I’ll prepare a material library where I’ll put the materials I need rendered. I’ll then write a Pre-Frame script that I’ll pass Deadline to do this stuff for each frame.
I want to search for objects that have a certain material assigned. Re-assign a new material from the library based on the currently rendered frame number, i.e.: frame 1 will assign material 1, frame 20 will assign material 20 from the library and so on so fort. Then I re-assign the rendered output filename so that each frame will produce a different file on the file system.

But, my script only produced a single output file as if the filename was not assigned correctly. Is there any kind of deadline specific way to change the render output file name in 3ds Max (2014)?

My Pre-Frame script:

[code]/*
This script will take the current render frame and assign a material
to certain meshes in the scene based off this value in the material
library.

© 2014 by Lukas Dubeda | duber studio | www.duber.cz
*/

dnRE = dotNetObject “System.Text.RegularExpressions.Regex” @"(?<=MATERIAL)[0-9]*" --the RE used for naming the rendered material filenames
dnFilePath = dotNetObject “System.Text.RegularExpressions.Regex” @"(D|d):" --the RE used for naming the rendered material filenames
dnMatRE = dotNetObject “System.Text.RegularExpressions.Regex” @"[0-9]{8}" --the RE used for finding materials with eight numbers in its name

dnTESTNAMEREGEX = dotNetObject “System.Text.RegularExpressions.Regex” @“DVERE_VUV” --RE only for testing purposes. DELETE AFTERWARDS!!!
newMatsLib = loadTempMaterialLibrary @"\RAMMSTEIN_UNMANAGED_PROJECTS_\Sapeli\SRC\2014-07-31\SAPELI_NEW_MATS_2014-07.mat"
curFrame = DeadlineUtil.currentFrame
matID = (filterString newMatsLib[curFrame].name “_” splitEmptyTokens:True)[1]
newFileNameID = dnRE.Replace rendOutputFilename matID
newFileName = dnFilePath.Replace newFileNameID @"\RAMMSTEIN_UNMANAGED_PROJECTS_"
newFileName = dnTESTNAMEREGEX.Replace newFileName @“TEST” --only for testing purposes. DELETE AFTERWARDS!!!
rendOutputFilename = newFileName

for o in geometry where o.ishidden == False and o.material != undefined do
(
if (dnMatRE.IsMatch o.material.name) do
(
try(o.material = newMatsLib[DeadlineUtil.currentFrame]) catch()
)
)

deadlineUtil.LogMessage (“Material ID:” + matID + " swapped, proceeding to render…")
deadlineUtil.LogMessage ("filename: " + rendOutputFilename)[/code]

Hi Lukas,

This is a limitation of the Pre-Frame callback of Max. As explained in the MAXScript Help,

You should be using a Post-Load script (which is more or less equivalent to Pre-Render Callback in MAXScript), running one frame per task chunks. I think the script will be run even if Restart Max Between Tasks is off, but if that does not work, you would need to turn it on.

The alternative approach would be to use a MAXScript job, perform the material assignment in the job’s script, then call render() from it and let it save the output where you want.

Thank you, Bobo, for your thoughts on this, much appretiated.

The MAXScript job you mention, is it anything specific to Deadline, or is it just a post-load script that has the render() method included so that it render, then gets to the next frame etc… separately from control from Deadline?

The MAXScript Job is a special Deadline mode of 3ds Max jobs. Instead of calling the Renderer, Deadline runs a provided MAXScript file. It is very similar to how Post-Load and Pre-Frame scripts are run, but it is the MAIN part of the job and no rendering will be performed by the job itself, only the script will run. Inside the script, you can do ANYTHING that MAXScript can do - if running in Slave mode, you won’t be able to do some things that are disabled in MAXScript, but if you enable Workstation mode, you can basically let Deadline launch Max in licensed workstation mode and do EVERYTHING that MAXScript can do.

For example, many years ago we wrote a script that would import OBJs and animation data from Softimage, assemble a new MAX scene with them and save a new .MAX file as the output instead of rendering… Since saving a .MAX file requires a Max license (it is turned off in free slave mode of Max), we had to force Workstation mode. But we could process hundreds of files overnight without human attention, and in the morning everything was ready to be used in a network folder :slight_smile:

In your case, you could split the processing in two - you could run a MAXscript Job on one machine that assembles MAX files and saves them with the material changes applied in a folder, then run another MAXScript that submits regular render jobs using these new MAX scenes.

Or you could create a single MAXScript Job where, as I proposed, you load the unchanged scene, make some changes via MAXScript like the loading of materials etc, then you call render() with the desired output path, then return TRUE to exit. This can run in Slave mode and will be faster and use less disk space, but you won’t have the Deadline Monitor access to the actual frames being rendered since the rendering itself would happen within the MAXScript body.

Take a look at how XMesh Saver runs on Deadline! When you submit a job from the XMesh Saver, it sends a MAXScript Job that runs a for loop and performs the saving (which is a form of rendering!) and that’s it. It also runs in slave mode. Take a peek into the file
“C:\Program Files\Thinkbox\XMeshSaver MX\Scripts\XMeshSaverDeadlineScriptJob.ms”
for inspiration!

In addition, if you open SMTD and look under the Scripts tab, you can easily enable the MAXScript Job mode and even create a new script from Template. Then just populate the code in the middle of it…

Oh, OK, but that is, unfortunately, not possible for me to do.

First off, I don’t use SMTD at all, I submit via the Monitor.

But mainly for this job, I’ll be submitting thousands of scene files via external Python scripts, so I’ll be building the jobinfo and plugininfo files on the fly.

Is there a parameter for the plugininfo to set so that Deadline treats it only as a MAXScript job and doesn’t actually do any rendering?

I think I should be able to submit the scene file to the 3dsmaxcmd.exe with the script file as one of the parameters, so if I can force Deadline to submit this for me, that’d be gold. :slight_smile: Thanks for pointing me the right direction.

That is even easier :slight_smile:

All you need to do is set a flag in the Job Info file:

MAXScriptJob=1

Then in the DeadlineCommand arguments, you have the MAX scene file followed by the MAXScript file name as another auxiliary file. It will be copied into the Job folder on the Repository and will be run from there.

When the Slave sees the flag MAXScriptJob=1, it will assume that the first Aux. file after the scene file (if the scene file is submitted) is the MS script to run, and no rendering will be performed. It will just load the scene and then run the script. If the script returns TRUE, the task will succeed. If it returns FALSE, it will fail. Note that the script will be run for each task, and you can still use the DeadlineUtil interface to get the current frame and any other Job Info data you might want to pass to the script.
Once again, peek into the XMesh Saver On Deadline script to see how we have used it there to do what we needed to…

Brilliant!!! Man, brilliant!

Thank you, once again, for your wisdom, Bobo. :slight_smile: I appretiate it.