diff --git a/pype/plugins/maya/publish/collect_render.py b/pype/plugins/maya/publish/collect_render.py index 5cdae580f5..df1d3f4bd5 100644 --- a/pype/plugins/maya/publish/collect_render.py +++ b/pype/plugins/maya/publish/collect_render.py @@ -259,8 +259,8 @@ class CollectMayaRender(pyblish.api.ContextPlugin): if render_instance.data.get("vrayScene") is True: data["families"].append("vrayscene") - if render_instance.data.get("ass") is True: - data["families"].append("assScene") + if render_instance.data.get("assScene") is True: + data["families"].append("assscene") # Include (optional) global settings # Get global overrides and translate to Deadline values diff --git a/pype/plugins/maya/publish/submit_maya_deadline.py b/pype/plugins/maya/publish/submit_maya_deadline.py index 00e3c6ae62..b5962bf2c8 100644 --- a/pype/plugins/maya/publish/submit_maya_deadline.py +++ b/pype/plugins/maya/publish/submit_maya_deadline.py @@ -179,6 +179,9 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): self.log.info("Using published scene for render {}".format( filepath)) + if not os.path.exists(filepath): + self.log.error("published scene does not exist!") + raise # now we need to switch scene in expected files # because token will now point to published # scene file and that might differ from current one @@ -261,6 +264,7 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): payload_data["render_variables"] = render_variables payload_data["renderlayer"] = renderlayer payload_data["workspace"] = workspace + payload_data["dirname"] = dirname frame_pattern = payload_skeleton["JobInfo"]["Frames"] payload_skeleton["JobInfo"]["Frames"] = frame_pattern.format( @@ -315,6 +319,9 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): # Submit preceeding export jobs ------------------------------------- export_job = None + assert not all(x in instance.data["families"] + for x in ['vrayscene', 'assscene']), ( + "Vray Scene and Ass Scene options are mutually exclusive") if "vrayscene" in instance.data["families"]: export_job = self._submit_export(payload_data, "vray") @@ -325,7 +332,7 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): if "vrayscene" in instance.data["families"]: payload = self._get_vray_render_payload(payload_data) elif "assscene" in instance.data["families"]: - pass + payload = self._get_arnold_render_payload(payload_data) else: payload = self._get_maya_payload(payload_data) @@ -381,22 +388,22 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): } plugin_info = { - "SceneFile": data["filepath"], - # Output directory and filename - "OutputFilePath": data["dirname"].replace("\\", "/"), - "OutputFilePrefix": data["render_variables"]["filename_prefix"], # noqa: E501 + "SceneFile": data["filepath"], + # Output directory and filename + "OutputFilePath": data["dirname"].replace("\\", "/"), + "OutputFilePrefix": data["render_variables"]["filename_prefix"], # noqa: E501 - # Only render layers are considered renderable in this pipeline - "UsingRenderLayers": True, + # Only render layers are considered renderable in this pipeline + "UsingRenderLayers": True, - # Render only this layer - "RenderLayer": data["renderlayer"], + # Render only this layer + "RenderLayer": data["renderlayer"], - # Determine which renderer to use from the file itself - "Renderer": self._instance.data["renderer"], + # Determine which renderer to use from the file itself + "Renderer": self._instance.data["renderer"], - # Resolve relative references - "ProjectPath": data["workspace"], + # Resolve relative references + "ProjectPath": data["workspace"], } payload["JobInfo"].update(job_info_ext) payload["PluginInfo"].update(plugin_info) @@ -415,7 +422,7 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): "FramesPerTask": self._instance.data.get("framesPerTask", 1) } - plugin_info = { + plugin_info_ext = { # Renderer "Renderer": "vray", # Input @@ -428,7 +435,73 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): } payload["JobInfo"].update(job_info_ext) - payload["PluginInfo"].update(plugin_info) + payload["PluginInfo"].update(plugin_info_ext) + return payload + + def _get_arnold_export_payload(self, data): + + try: + from pype.scripts import export_maya_ass_job + except Exception: + assert False, ( + "Expected module 'export_maya_ass_job' to be available") + + module_path = export_maya_ass_job.__file__ + if module_path.endswith(".pyc"): + module_path = module_path[: -len(".pyc")] + ".py" + + script = os.path.normpath(module_path) + + payload = copy.deepcopy(payload_skeleton) + job_info_ext = { + # Job name, as seen in Monitor + "Name": "Export {} [{}-{}]".format( + data["jobname"], + int(self._instance.data["frameStartHandle"]), + int(self._instance.data["frameEndHandle"])), + + "Plugin": "Python", + "FramesPerTask": self._instance.data.get("framesPerTask", 1) + } + + plugin_info_ext = { + "Version": "3.6", + "ScriptFile": script, + "Arguments": "", + "SingleFrameOnly": "True", + } + payload["JobInfo"].update(job_info_ext) + payload["PluginInfo"].update(plugin_info_ext) + + envs = [] + for k, v in payload["JobInfo"].items(): + if k.startswith("EnvironmentKeyValue"): + envs.append(v) + + # add app name to environment + envs.append( + "AVALON_APP_NAME={}".format(os.environ.get("AVALON_APP_NAME"))) + envs.append( + "PYPE_ASS_EXPORT_RENDER_LAYER={}".format(data["renderlayer"])) + envs.append( + "PYPE_ASS_EXPORT_SCENE_FILE={}".format(data["filepath"])) + envs.append( + "PYPE_ASS_EXPORT_OUTPUT={}".format( + payload['JobInfo']['OutputFilename0'])) + envs.append( + "PYPE_ASS_EXPORT_START={}".format( + int(self._instance.data["frameStartHandle"]))) + envs.append( + "PYPE_ASS_EXPORT_END={}".format( + int(self._instance.data["frameEndHandle"]))) + envs.append( + "PYPE_ASS_EXPORT_STEP={}".format(1)) + + i = 0 + for e in envs: + payload["JobInfo"]["EnvironmentKeyValue{}".format(i)] = e + i += 1 + return payload def _get_vray_render_payload(self, data): @@ -439,7 +512,7 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): # "vrayscene//_/" scene, _ = os.path.splitext(data["filename"]) - first_file = self.format_output_filename(scene, template) + first_file = self.format_vray_output_filename(scene, template) first_file = "{}/{}".format(data["workspace"], first_file) job_info_ext = { "Name": "Render {} [{}-{}]".format( @@ -464,11 +537,33 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): payload["PluginInfo"].update(plugin_info) return payload + def _get_arnold_render_payload(self, data): + payload = copy.deepcopy(payload_skeleton) + ass_file, _ = os.path.splitext(data["output_filename_0"]) + first_file = ass_file + ".ass" + job_info_ext = { + "Name": "Render {} [{}-{}]".format( + data["jobname"], + int(self._instance.data["frameStartHandle"]), + int(self._instance.data["frameEndHandle"])), + + "Plugin": "Arnold", + "OverrideTaskExtraInfoNames": False, + } + + plugin_info = { + "ArnoldFile": first_file, + } + + payload["JobInfo"].update(job_info_ext) + payload["PluginInfo"].update(plugin_info) + return payload + def _submit_export(self, data, format): if format == "vray": payload = self._get_vray_export_payload(data) self.log.info("Submitting vrscene export job.") - elif format == "ass": + elif format == "arnold": payload = self._get_arnold_export_payload(data) self.log.info("Submitting ass export job.") @@ -535,7 +630,7 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): kwargs['timeout'] = 10 return requests.get(*args, **kwargs) - def format_output_filename(self, filename, template, dir=False): + def format_vray_output_filename(self, filename, template, dir=False): """Format the expected output file of the Export job. Example: diff --git a/pype/scripts/export_maya_ass_job.py b/pype/scripts/export_maya_ass_job.py new file mode 100644 index 0000000000..d343eec131 --- /dev/null +++ b/pype/scripts/export_maya_ass_job.py @@ -0,0 +1,101 @@ +"""This module is used for command line exporting of ASS files.""" + +import os +import argparse +import logging +import subprocess +import platform + +try: + from shutil import which +except ImportError: + # we are in python < 3.3 + def which(command): + path = os.getenv('PATH') + for p in path.split(os.path.pathsep): + p = os.path.join(p, command) + if os.path.exists(p) and os.access(p, os.X_OK): + return p + +handler = logging.basicConfig() +log = logging.getLogger("Publish Image Sequences") +log.setLevel(logging.DEBUG) + +error_format = "Failed {plugin.__name__}: {error} -- {error.traceback}" + + +def __main__(): + parser = argparse.ArgumentParser() + parser.add_argument("--paths", + nargs="*", + default=[], + help="The filepaths to publish. This can be a " + "directory or a path to a .json publish " + "configuration.") + parser.add_argument("--gui", + default=False, + action="store_true", + help="Whether to run Pyblish in GUI mode.") + + parser.add_argument("--pype", help="Pype root") + + kwargs, args = parser.parse_known_args() + + print("Running pype ...") + auto_pype_root = os.path.dirname(os.path.abspath(__file__)) + auto_pype_root = os.path.abspath(auto_pype_root + "../../../../..") + + auto_pype_root = os.environ.get('PYPE_SETUP_PATH') or auto_pype_root + if os.environ.get('PYPE_SETUP_PATH'): + print("Got Pype location from environment: {}".format( + os.environ.get('PYPE_SETUP_PATH'))) + + pype_command = "pype.ps1" + if platform.system().lower() == "linux": + pype_command = "pype" + elif platform.system().lower() == "windows": + pype_command = "pype.bat" + + if kwargs.pype: + pype_root = kwargs.pype + else: + # test if pype.bat / pype is in the PATH + # if it is, which() will return its path and we use that. + # if not, we use auto_pype_root path. Caveat of that one is + # that it can be UNC path and that will not work on windows. + + pype_path = which(pype_command) + + if pype_path: + pype_root = os.path.dirname(pype_path) + else: + pype_root = auto_pype_root + + print("Set pype root to: {}".format(pype_root)) + print("Paths: {}".format(kwargs.paths or [os.getcwd()])) + + # paths = kwargs.paths or [os.environ.get("PYPE_METADATA_FILE")] or [os.getcwd()] # noqa + + mayabatch = os.environ.get("AVALON_APP_NAME").replace("maya", "mayabatch") + args = [ + os.path.join(pype_root, pype_command), + "launch", + "--app", + mayabatch, + "-script", + os.path.join(pype_root, "repos", "pype", + "pype", "scripts", "export_maya_ass_sequence.mel") + ] + + print("Pype command: {}".format(" ".join(args))) + # Forcing forwaring the environment because environment inheritance does + # not always work. + # Cast all values in environment to str to be safe + env = {k: str(v) for k, v in os.environ.items()} + exit_code = subprocess.call(args, env=env) + if exit_code != 0: + raise RuntimeError("Publishing failed.") + + +if __name__ == '__main__': + __main__() diff --git a/pype/scripts/export_maya_ass_sequence.mel b/pype/scripts/export_maya_ass_sequence.mel new file mode 100644 index 0000000000..83d1d010ac --- /dev/null +++ b/pype/scripts/export_maya_ass_sequence.mel @@ -0,0 +1,67 @@ +/* + Script to export specified layer as ass files. + +Attributes: + + scene_file (str): Name of the scene to load. + start (int): Start frame. + end (int): End frame. + step (int): Step size. + output_path (str): File output path. + render_layer (str): Name of render layer. + +*/ + +$scene_file=`getenv "PYPE_ASS_EXPORT_SCENE_FILE"`; +$step=`getenv "PYPE_ASS_EXPORT_STEP"`; +$start=`getenv "PYPE_ASS_EXPORT_START"`; +$end=`getenv "PYPE_ASS_EXPORT_END"`; +$file_path=`getenv "PYPE_ASS_EXPORT_OUTPUT"`; +$render_layer = `getenv "PYPE_ASS_EXPORT_RENDER_LAYER"`; + +print("*** ASS Export Plugin\n"); + +if ($scene_file == "") { + print("!!! cannot determine scene file\n"); + quit -a -ex -1; +} + +if ($step == "") { + print("!!! cannot determine step size\n"); + quit -a -ex -1; +} + +if ($start == "") { + print("!!! cannot determine start frame\n"); + quit -a -ex -1; +} + +if ($end == "") { + print("!!! cannot determine end frame\n"); + quit -a -ex -1; +} + +if ($file_path == "") { + print("!!! cannot determine output file\n"); + quit -a -ex -1; +} + +if ($render_layer == "") { + print("!!! cannot determine render layer\n"); + quit -a -ex -1; +} + + +print(">>> Opening Scene [ " + $scene_file + " ]\n"); + +// open scene +file -o -f $scene_file; + +// switch to render layer +print(">>> Switching layer [ "+ $render_layer + " ]\n"); +editRenderLayerGlobals -currentRenderLayer $render_layer; + +// export +print(">>> Exporting to [ " + $file_path + " ]\n"); +arnoldExportAss -mask 255 -sl 1 -ll 1 -bb 1 -sf $start -se $end -b -fs $step; +print("--- Done\n");