Pause script until batchrender is finished

Hello !
I think the title says everything :slight_smile:

I have a script in which I use the batchrender in maya.
But, the rest of the script continue to run even when the batchrender isn’t finished.
Is there a way to pause the script and wait until the batchrender is complete ?

Small question:
How can I apply a shader to a face without selecting the face first ?

Thank you

Was long since I touched renders but want to remember something like what is brought up here

And as for applying shaders to specific faces, I want to remember it being pretty complicated - think I have some code somewhere I did just that with however think I opted for the simpler solution of having the script select the face I wanted - apply the shader then restore selection to what I previously had.

Thank you for your answer !
This is exactly what I was looking for.

But I also read that these Post/Pre Mel do not run with batchRender. I’ll try at home and I’ll come back to let you know !

That’s what I did. I selected the face then I applied the shader. It was the easiest way I could find.

Soooo, I tried using the post MEL to execute something after a render…
But I couldn’t make it work with a batch render.

It works if I render a single frame. But with the batch render it doesn’t work.
Any ideas ?

This works just fine for me, running the batch render from commandline.

REM Example batch render script with callbacks, will print hello world after each rendered frame.
"C:\Program Files\Autodesk\Maya2018\bin\Render.exe" -r sw -s 1 -e 3 -postFrame "print(""hello world\n"")" "C:\Path\To\Scene.ma"

I run the maya batch inside of maya. Maybe that’s why it doesn’t work ?

If I run the batch render in maya I get the prints into mayaRenderLog.txt but think I’ve strayed from your original question about pausing the script to wait for the render to finish.

Docs says

The batchRender will spawn a separate maya process in which commands will be communicated to it through a commandPort. If Maya is unable to find an available port an error will be produced. Maya will attempt to use ports 7835 through 7844.

Haven’t looked into any of that myself.

It’s odd that the post render mel works outside of maya but not inside :confused:

Even if maya tries to communicate through commandPort, I can’t know for sure which port will be used by the batch render :confused:

I think I have to look for another solution.
I thought about writing a tempHistoryLog and check every n seconds if my batch render is complete.
I don’t know if it’s a good solution but I can’t find another way to know if my render is finished…

Maybe this could help you. This is still not finished but should give you an idea how to solve it.

"""Context. Generally submitting render with maya does not require pre and post process.
If you however require to do pre or post scripts your are going to use mel. This python module is trying
to solve this problem.


"""

import abc
from pymel import core as pm


class AbstractRender(object):
    """Base class for render process.
    
    Attributes:
        __metaclass__ (<abc.ABCMeta>): Meta class.

    """

    __metaclass__ = abc.ABCMeta

    def __init__(
        self,
        file_path,
        start_frame,
        end_frame,
        camera,
        pre_function=None,
        post_function=None,
        offset=0,
    ):
        """Initialize class and do nothing.
        
        Args:
            file_path (str): Path to file name.
            start_frame (int): First frame of file path.
            end_frame (int): Last frame of file path.
            camera (str): Camera name to use.
            offset (int): Frame offset to use default to 0.

        """
        super(AbstractRender, self).__init__()
        self.file_path = file_path
        self.start_frame = start_frame
        self.end_frame = end_frame
        self.camera = camera
        self.pre_function = pre_function
        self.post_function = post_function
        self.offset = offset

    @abc.abstractmethod
    def _render(self, frame):
        """Implement me in super class."""
        pass

    def _pre_render(self):
        """Execute pre render command."""
        if self.pre_function:
            self.pre_function()

    def _post_render(self):
        """Execute post render command."""
        if self.post_function:
            self.post_function()

    def __call__(self):
        """Execute render."""
        if self._pre_render:
            self._pre_render()

        pm.setAttr("defaultRenderGlobals.animation", False)
        pm.setAttr("defaultRenderGlobals.outFormatControl", False)

        for frame in range(self.start_frame, self.end_frame + 1):
            pm.SCENE.defaultRenderGlobals.imageFilePrefix.set(
                "{path}.{padding}".format(
                    path=self.file_path, padding=frame + self.offset
                )
            )
            self._render(frame)

        if self._post_render:
            self._post_render()


class OsgRender(AbstractRender):
    """A class for executing hardware render 2.0 renders."""

    def _render(self, frame):
        """Render current frame with hardware render 2.0.

        Args:
            frame (int): Frame to render.

        """
        pm.ogsRender(camera=self.camera, frame=frame)


class HwRender(AbstractRender):
    """A class for executing hardware render renders."""

    def _render(self, frame):
        """Render current frame with hardware render.

        Args:
            frame (int): Frame to render.

        """
        pm.hwRender(frame=frame, camera=self.camera)


class ArnoldPythonRender(AbstractRender):
    """A class for executing arnold renders."""

    def __call__(self):
        """Set arnold driver settings to png."""
        driver = pm.PyNode("defaultArnoldDriver")
        driver.ai_translator.set("png")
        super(ArnoldPythonRender, self).__call__()

    def _render(self, frame):
        """Render current frame with arnold.

        Args:
            frame (int): Frame to render.

        """
        pm.currentTime(frame)
        pm.arnoldRender(camera=self.camera, batch=True)

You’ll have a good deal more control over the process if you don’t use MayaBatch and instead run a Maya standalone instance. That way you can cook up any control scheme you like. The minimal version would be something like a script that took a bunch of file names as arguments, then loaded and rendered them one at a time and asked if you wanted to continue after each one…

 # warning - untested code!!!!!
 import sys
 import traceback
 import maya.standalone
 maya.standalone.initialize()
 import maya.cmds as cmds
  rendered, failed = [], {}

 for filename in sys.argv[1:]:
      try:
           cmds.file(filename, open=True, force=True)
           cmds.render() # you'll probably want to do fancier stuff here!
           rendered.append(filename)
           print ("rendered", filename)
      except Exception as e:
           failed[filename] = traceback.format_exc()
           print (filename, "failed") 

      keep_going = raw_input("keep rendering Y/N:  ")  or "Y"
      if keep_going.upper()[0] != "Y":
          break

  with open(*path/to/logfile", wt) as log:
         log.write("rendered\n")
         for f in rendered:
               log.write("\t")
               log.write(f)
               log.write("\n")
         log.write("\n\nerrors:\n")
         for k, v in failed.items():
              log.write("-" *72)
              log.write(k)
              log.write("\n\n")
              log.writelines(v)
              log.write("\n")
1 Like

I didn’t think of this solution.
It would indeed, solve all of my problem !
I was fixating on using mayabatch.

Thank you very much Theodox !