I use simple python snippets to replicate the light pass manager (LPM) script's behaviour for 3dsmax link.

LPM in 3dsmax basically just runs a pre_render script that applies overrides and then renders.

Blender can do the same thing with bpy.app.handlers.render_pre

It works alright, but there is one essential thing that doesnt work as I expected it:

-in 3dsmax, the pre_render_script is only run on the data that is sent to the renderer. The scene in front of the user is unchanged.

-in Blender, the pre_render_script is run on the scene before it is sent to the renderer. Therefore, after rendering, the scene in the viewport has all changes applied and the original state of the scene is lost.

I dont want to write scripts that record the whole state of the scene so it can be rebuilt post render. It is error-prone, needs to be maintained, I am a python noob and besides that, Blender has all the data already stored in the file.

My workaround right now
start the render as a subprocess and run the python script that sets the overrides:

render_cmd = '''\
gnome-terminal -- 
/usr/bin/blender -b 
--python %s
-S Scene -s 1 -e 1 -a
''' % (fname, render_prep_script_name)

This is not bad, I can work with that. But I have to wait for the renderer to save the output image before I can see it. So I am wondering, should the behaviour of the render_pre handler not be different?

| improve this question | | | | |
  • $\begingroup$ yes, this is a simple and good solution and should work fine. But what about heavy production scenes? I feel like I dont want to copy all that data everytime I hit render. $\endgroup$ – cookiemonsterandthegirls Apr 24 '19 at 8:29
  • $\begingroup$ I'm already attempting to answer in the comments, I'll post my suggestions as a proper answer, so that it can be voted by the community. $\endgroup$ – Leander Apr 24 '19 at 8:32

The 3ds Max script must be using a copy of the data, if the data sent to the renderer is editable, but still independant of the scene.

There are a couple of other workaround I can think of.

  • Make a copy of the scene. Then use your python script on the copy and render it. You can delete the copy on render_post or just overwrite the scene everytime you start rendering. This will need a little bit more RAM, but no graphical memory if executed in background mode.
  • The above solution can be improved by making a linked copy (LINK_OBJECTS). It will not take up much more memory, since the data blocks the same. Then (on the copy) make the datablocks you want to change single users and change them.
  • Build an operator with UNDO activated and register it. Then, in your python script, call the operator (which does the changes), render the scene, then undo it. Depending on your scene, this may not be faster than a full copy, but will consume less RAM (I think).
  • Execute your python script from another empty Blender file. Append the scene (which you want to render). Make the changes, and render it, then delete it. Repeat. This is similiar to your setup, but could use the same background blender instance.
  • The above solution can be improved, by only removing and then appending objects which are changed by the python script.
| improve this answer | | | | |
  • $\begingroup$ Thanks Leander. I will look into these options. Curious though, what do you think about the behaviour of the pre_render handle? I am not sure what a good use case is, when it actually changes what I work on. $\endgroup$ – cookiemonsterandthegirls Apr 25 '19 at 9:40
  • 1
    $\begingroup$ @cookie Well, you would still use your handler. E.g. with option 3 (the best I guess), you call the operator in the pre_render handler and in the post_render handler you call the UNDO. $\endgroup$ – Leander Apr 25 '19 at 10:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.