From 058fcb97a358a972d34a4cabd45773e249e15cf0 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 9 Jun 2023 17:51:54 +0800 Subject: [PATCH 01/47] multiple render camera supports for 3dsmax --- openpype/hosts/max/api/lib_rendersettings.py | 11 ++-------- .../hosts/max/plugins/create/create_render.py | 22 ++++++++++++++----- .../max/plugins/publish/collect_render.py | 5 +++++ .../plugins/publish/submit_max_deadline.py | 11 ++++++++++ 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/openpype/hosts/max/api/lib_rendersettings.py b/openpype/hosts/max/api/lib_rendersettings.py index 91e4a5bf9b..db8dee3340 100644 --- a/openpype/hosts/max/api/lib_rendersettings.py +++ b/openpype/hosts/max/api/lib_rendersettings.py @@ -35,15 +35,8 @@ class RenderSettings(object): ) def set_render_camera(self, selection): - for sel in selection: - # to avoid Attribute Error from pymxs wrapper - found = False - if rt.classOf(sel) in rt.Camera.classes: - found = True - rt.viewport.setCamera(sel) - break - if not found: - raise RuntimeError("Camera not found") + # to avoid Attribute Error from pymxs wrapper + return rt.viewport.setCamera(selection[0]) def render_output(self, container): folder = rt.maxFilePath diff --git a/openpype/hosts/max/plugins/create/create_render.py b/openpype/hosts/max/plugins/create/create_render.py index 5ad895b86e..ec5635b81b 100644 --- a/openpype/hosts/max/plugins/create/create_render.py +++ b/openpype/hosts/max/plugins/create/create_render.py @@ -14,7 +14,10 @@ class CreateRender(plugin.MaxCreator): def create(self, subset_name, instance_data, pre_create_data): from pymxs import runtime as rt - sel_obj = list(rt.selection) + sel_obj = [ + c for c in rt.Objects + if rt.classOf(c) in rt.Camera.classes] + file = rt.maxFileName filename, _ = os.path.splitext(file) instance_data["AssetName"] = filename @@ -24,11 +27,20 @@ class CreateRender(plugin.MaxCreator): instance_data, pre_create_data) # type: CreatedInstance container_name = instance.data.get("instance_node") - container = rt.getNodeByName(container_name) # TODO: Disable "Add to Containers?" Panel # parent the selected cameras into the container - for obj in sel_obj: - obj.parent = container + if self.selected_nodes: + # set viewport camera for + # rendering(mandatory for deadline) + sel_obj = [ + c for c in rt.getCurrentSelection() + if rt.classOf(c) in rt.Camera.classes] + + if not sel_obj: + raise RuntimeError("Please add at least one camera to the scene " + "before creating the render instance") + + RenderSettings().set_render_camera(sel_obj) # for additional work on the node: # instance_node = rt.getNodeByName(instance.get("instance_node")) @@ -37,7 +49,5 @@ class CreateRender(plugin.MaxCreator): # Changing the Render Setup dialog settings should be done # with the actual Render Setup dialog in a closed state. - # set viewport camera for rendering(mandatory for deadline) - RenderSettings().set_render_camera(sel_obj) # set output paths for rendering(mandatory for deadline) RenderSettings().render_output(container_name) diff --git a/openpype/hosts/max/plugins/publish/collect_render.py b/openpype/hosts/max/plugins/publish/collect_render.py index db5c84fad9..cbb3a7b4d6 100644 --- a/openpype/hosts/max/plugins/publish/collect_render.py +++ b/openpype/hosts/max/plugins/publish/collect_render.py @@ -48,6 +48,10 @@ class CollectRender(pyblish.api.InstancePlugin): instance.name, asset_id) self.log.debug("version_doc: {0}".format(version_doc)) + sel_obj = [ + c for c in rt.Objects + if rt.classOf(c) in rt.Camera.classes] + version_int = 1 if version_doc: version_int += int(version_doc["name"]) @@ -78,6 +82,7 @@ class CollectRender(pyblish.api.InstancePlugin): "renderer": renderer, "source": filepath, "plugin": "3dsmax", + "cameras": sel_obj, "frameStart": int(rt.rendStart), "frameEnd": int(rt.rendEnd), "version": version_int, diff --git a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py index b6a30e36b7..ff5adc39ad 100644 --- a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py @@ -212,6 +212,17 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, plugin_data["RenderOutput"] = beauty_name # as 3dsmax has version with different languages plugin_data["Language"] = "ENU" + render_cameras = instance.data["cameras"] + if render_cameras: + for i, camera in enumerate(render_cameras): + cam_name = "Camera%s" % (i + 1) + plugin_data[cam_name] = camera.name + # set the default camera + plugin_data["Camera"] = render_cameras[0].name + # set empty camera of Camera 0 for the ' + # correct parameter submission + plugin_data["Camera0"] = None + renderer_class = get_current_renderer() renderer = str(renderer_class).split(":")[0] From 5fc037880fa7ddee5c65d63679d1db2810469411 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 19 Jun 2023 17:33:16 +0800 Subject: [PATCH 02/47] refactor the collector and deadline for multiple camera --- openpype/hosts/max/plugins/publish/collect_render.py | 2 +- .../modules/deadline/plugins/publish/submit_max_deadline.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/collect_render.py b/openpype/hosts/max/plugins/publish/collect_render.py index cbb3a7b4d6..8e39da0fbb 100644 --- a/openpype/hosts/max/plugins/publish/collect_render.py +++ b/openpype/hosts/max/plugins/publish/collect_render.py @@ -49,7 +49,7 @@ class CollectRender(pyblish.api.InstancePlugin): asset_id) self.log.debug("version_doc: {0}".format(version_doc)) sel_obj = [ - c for c in rt.Objects + c.name for c in rt.Objects if rt.classOf(c) in rt.Camera.classes] version_int = 1 diff --git a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py index ff5adc39ad..365be7b07b 100644 --- a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py @@ -216,9 +216,9 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, if render_cameras: for i, camera in enumerate(render_cameras): cam_name = "Camera%s" % (i + 1) - plugin_data[cam_name] = camera.name - # set the default camera - plugin_data["Camera"] = render_cameras[0].name + plugin_data[cam_name] = camera + # set the default camera + plugin_data["Camera"] = camera # set empty camera of Camera 0 for the ' # correct parameter submission plugin_data["Camera0"] = None From 6b716b8ce92d5e0466ecb92c03aad86e920b8217 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 12 Jul 2023 19:16:52 +0800 Subject: [PATCH 03/47] hound fix --- openpype/hosts/max/api/lib_renderproducts.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/openpype/hosts/max/api/lib_renderproducts.py b/openpype/hosts/max/api/lib_renderproducts.py index a1039b9309..45d7d7134d 100644 --- a/openpype/hosts/max/api/lib_renderproducts.py +++ b/openpype/hosts/max/api/lib_renderproducts.py @@ -155,8 +155,8 @@ class RenderProducts(object): for name in render_name: render_dict.update({ name: self.get_expected_render_elements( - output_file, name, start_frame, - end_frame, img_fmt) + output_file, name, start_frame, + end_frame, img_fmt) }) elif renderer == "Redshift_Renderer": render_name = self.get_render_elements_name() @@ -169,15 +169,15 @@ class RenderProducts(object): if name == "RsCryptomatte": render_dict.update({ name: self.get_expected_render_elements( - output_file, name, start_frame, - end_frame, img_fmt) + output_file, name, start_frame, + end_frame, img_fmt) }) else: for name in render_name: render_dict.update({ name: self.get_expected_render_elements( - output_file, name, start_frame, - end_frame, img_fmt) + output_file, name, start_frame, + end_frame, img_fmt) }) elif renderer == "Arnold": @@ -186,7 +186,7 @@ class RenderProducts(object): for name in render_name: render_dict.update({ name: self.get_expected_arnold_product( - output_file, name, start_frame, end_frame, img_fmt) + output_file, name, start_frame, end_frame, img_fmt) }) elif renderer in [ "V_Ray_6_Hotfix_3", @@ -198,8 +198,8 @@ class RenderProducts(object): for name in render_name: render_dict.update({ name: self.get_expected_render_elements( - output_file, name, start_frame, - end_frame, img_fmt) # noqa + output_file, name, start_frame, + end_frame, img_fmt) # noqa }) return render_dict From e96bada178f11d8f24d1036746a3f3e519e95b84 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 12 Jul 2023 19:23:03 +0800 Subject: [PATCH 04/47] hound fix --- openpype/hosts/max/api/lib_renderproducts.py | 44 ++++++++++--------- openpype/hosts/max/api/lib_rendersettings.py | 2 +- .../hosts/max/plugins/create/create_render.py | 2 +- 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/openpype/hosts/max/api/lib_renderproducts.py b/openpype/hosts/max/api/lib_renderproducts.py index 45d7d7134d..433214935d 100644 --- a/openpype/hosts/max/api/lib_renderproducts.py +++ b/openpype/hosts/max/api/lib_renderproducts.py @@ -33,6 +33,7 @@ class RenderProducts(object): output_file, start_frame, end_frame, img_fmt ) } + def get_multiple_beauty(self, outputs, cameras): beauty_output_frames = dict() for output, camera in zip(outputs, cameras): @@ -68,9 +69,9 @@ class RenderProducts(object): for name in render_name: aovs_frames.update({ f"{camera}_{name}": ( - self.get_expected_render_elements( - filename, name, start_frame, - end_frame, ext) + self.get_expected_render_elements( + filename, name, start_frame, + end_frame, ext) ) }) elif renderer == "Redshift_Renderer": @@ -84,9 +85,9 @@ class RenderProducts(object): if name == "RsCryptomatte": aovs_frames.update({ f"{camera}_{name}": ( - self.get_expected_render_elements( - filename, name, start_frame, - end_frame, ext) + self.get_expected_render_elements( + filename, name, start_frame, + end_frame, ext) ) }) else: @@ -105,9 +106,9 @@ class RenderProducts(object): for name in render_name: aovs_frames.update({ f"{camera}_{name}": ( - self.get_expected_arnold_product( - filename, name, start_frame, - end_frame, ext) + self.get_expected_arnold_product( + filename, name, start_frame, + end_frame, ext) ) }) elif renderer in [ @@ -120,9 +121,9 @@ class RenderProducts(object): for name in render_name: aovs_frames.update({ f"{camera}_{name}": ( - self.get_expected_render_elements( - filename, name, start_frame, - end_frame, ext) + self.get_expected_render_elements( + filename, name, start_frame, + end_frame, ext) ) }) @@ -155,8 +156,8 @@ class RenderProducts(object): for name in render_name: render_dict.update({ name: self.get_expected_render_elements( - output_file, name, start_frame, - end_frame, img_fmt) + output_file, name, start_frame, + end_frame, img_fmt) }) elif renderer == "Redshift_Renderer": render_name = self.get_render_elements_name() @@ -169,15 +170,15 @@ class RenderProducts(object): if name == "RsCryptomatte": render_dict.update({ name: self.get_expected_render_elements( - output_file, name, start_frame, - end_frame, img_fmt) + output_file, name, start_frame, + end_frame, img_fmt) }) else: for name in render_name: render_dict.update({ name: self.get_expected_render_elements( - output_file, name, start_frame, - end_frame, img_fmt) + output_file, name, start_frame, + end_frame, img_fmt) }) elif renderer == "Arnold": @@ -186,7 +187,8 @@ class RenderProducts(object): for name in render_name: render_dict.update({ name: self.get_expected_arnold_product( - output_file, name, start_frame, end_frame, img_fmt) + output_file, name, start_frame, + end_frame, img_fmt) }) elif renderer in [ "V_Ray_6_Hotfix_3", @@ -198,8 +200,8 @@ class RenderProducts(object): for name in render_name: render_dict.update({ name: self.get_expected_render_elements( - output_file, name, start_frame, - end_frame, img_fmt) # noqa + output_file, name, start_frame, + end_frame, img_fmt) # noqa }) return render_dict diff --git a/openpype/hosts/max/api/lib_rendersettings.py b/openpype/hosts/max/api/lib_rendersettings.py index 663f610e45..33cfc6dc4a 100644 --- a/openpype/hosts/max/api/lib_rendersettings.py +++ b/openpype/hosts/max/api/lib_rendersettings.py @@ -192,7 +192,7 @@ class RenderSettings(object): renderlayer = rt.batchRenderMgr.GetView(layer_no) # use camera name as renderlayer name renderlayer.name = cam - renderlayer.outputFilename ="{0}_{1}..{2}".format( + renderlayer.outputFilename = "{0}_{1}..{2}".format( output, cam, img_fmt) outputs.append(renderlayer.outputFilename) return outputs diff --git a/openpype/hosts/max/plugins/create/create_render.py b/openpype/hosts/max/plugins/create/create_render.py index 64e97fb941..23397e1a98 100644 --- a/openpype/hosts/max/plugins/create/create_render.py +++ b/openpype/hosts/max/plugins/create/create_render.py @@ -17,7 +17,7 @@ class CreateRender(plugin.MaxCreator): file = rt.maxFileName filename, _ = os.path.splitext(file) instance_data["AssetName"] = filename - num_of_renderlayer = rt.batchRenderMgr.numViews + num_of_renderlayer = rt.batchRenderMgr.numViews if num_of_renderlayer > 0: rt.batchRenderMgr.DeleteView(num_of_renderlayer) From 9ce0d97e48d4313b3d50d6edab36ab3608a98799 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 12 Jul 2023 19:28:08 +0800 Subject: [PATCH 05/47] hound fix --- openpype/hosts/max/api/lib_renderproducts.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/max/api/lib_renderproducts.py b/openpype/hosts/max/api/lib_renderproducts.py index 433214935d..d2d5fb08da 100644 --- a/openpype/hosts/max/api/lib_renderproducts.py +++ b/openpype/hosts/max/api/lib_renderproducts.py @@ -77,7 +77,7 @@ class RenderProducts(object): elif renderer == "Redshift_Renderer": render_name = self.get_render_elements_name() if render_name: - rs_aov_files = rt.Execute("renderers.current.separateAovFiles") + rs_aov_files = rt.Execute("renderers.current.separateAovFiles") # noqa # this doesn't work, always returns False # rs_AovFiles = rt.RedShift_Renderer().separateAovFiles if ext == "exr" and not rs_aov_files: @@ -97,9 +97,8 @@ class RenderProducts(object): self.get_expected_render_elements( filename, name, start_frame, end_frame, ext) - ) - }) - + ) + }) elif renderer == "Arnold": render_name = self.get_arnold_product_name() if render_name: From b182f29c90dd8810ab130331ad370e58fc21ab38 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 12 Jul 2023 19:32:25 +0800 Subject: [PATCH 06/47] hound fix --- openpype/hosts/max/api/lib_renderproducts.py | 24 ++++++-------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/openpype/hosts/max/api/lib_renderproducts.py b/openpype/hosts/max/api/lib_renderproducts.py index d2d5fb08da..03dfcf3345 100644 --- a/openpype/hosts/max/api/lib_renderproducts.py +++ b/openpype/hosts/max/api/lib_renderproducts.py @@ -68,11 +68,9 @@ class RenderProducts(object): if render_name: for name in render_name: aovs_frames.update({ - f"{camera}_{name}": ( - self.get_expected_render_elements( + f"{camera}_{name}": self.get_expected_render_elements( filename, name, start_frame, end_frame, ext) - ) }) elif renderer == "Redshift_Renderer": render_name = self.get_render_elements_name() @@ -84,31 +82,25 @@ class RenderProducts(object): for name in render_name: if name == "RsCryptomatte": aovs_frames.update({ - f"{camera}_{name}": ( - self.get_expected_render_elements( + f"{camera}_{name}": self.get_expected_render_elements( filename, name, start_frame, end_frame, ext) - ) }) else: for name in render_name: aovs_frames.update({ - f"{camera}_{name}": ( - self.get_expected_render_elements( + f"{camera}_{name}": self.get_expected_render_elements( filename, name, start_frame, end_frame, ext) - ) }) elif renderer == "Arnold": render_name = self.get_arnold_product_name() if render_name: for name in render_name: aovs_frames.update({ - f"{camera}_{name}": ( - self.get_expected_arnold_product( + f"{camera}_{name}": self.get_expected_arnold_product( filename, name, start_frame, end_frame, ext) - ) }) elif renderer in [ "V_Ray_6_Hotfix_3", @@ -119,11 +111,9 @@ class RenderProducts(object): if render_name: for name in render_name: aovs_frames.update({ - f"{camera}_{name}": ( - self.get_expected_render_elements( - filename, name, start_frame, - end_frame, ext) - ) + f"{camera}_{name}": self.get_expected_render_elements( + filename, name, start_frame, + end_frame, ext) }) return aovs_frames From 4c01e09ef9d3ae8f4fb67b724e9c227e9afaa7f1 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 12 Jul 2023 19:35:01 +0800 Subject: [PATCH 07/47] hound fix --- openpype/hosts/max/api/lib_renderproducts.py | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/openpype/hosts/max/api/lib_renderproducts.py b/openpype/hosts/max/api/lib_renderproducts.py index 03dfcf3345..59417a39fa 100644 --- a/openpype/hosts/max/api/lib_renderproducts.py +++ b/openpype/hosts/max/api/lib_renderproducts.py @@ -68,7 +68,7 @@ class RenderProducts(object): if render_name: for name in render_name: aovs_frames.update({ - f"{camera}_{name}": self.get_expected_render_elements( + f"{camera}_{name}": self.get_expected_aovs( filename, name, start_frame, end_frame, ext) }) @@ -82,14 +82,14 @@ class RenderProducts(object): for name in render_name: if name == "RsCryptomatte": aovs_frames.update({ - f"{camera}_{name}": self.get_expected_render_elements( + f"{camera}_{name}": self.get_expected_aovs( filename, name, start_frame, end_frame, ext) }) else: for name in render_name: aovs_frames.update({ - f"{camera}_{name}": self.get_expected_render_elements( + f"{camera}_{name}": self.get_expected_aovs( filename, name, start_frame, end_frame, ext) }) @@ -111,9 +111,9 @@ class RenderProducts(object): if render_name: for name in render_name: aovs_frames.update({ - f"{camera}_{name}": self.get_expected_render_elements( - filename, name, start_frame, - end_frame, ext) + f"{camera}_{name}": self.get_expected_aovs( + filename, name, start_frame, + end_frame, ext) }) return aovs_frames @@ -144,7 +144,7 @@ class RenderProducts(object): if render_name: for name in render_name: render_dict.update({ - name: self.get_expected_render_elements( + name: self.get_expected_aovs( output_file, name, start_frame, end_frame, img_fmt) }) @@ -158,14 +158,14 @@ class RenderProducts(object): for name in render_name: if name == "RsCryptomatte": render_dict.update({ - name: self.get_expected_render_elements( + name: self.get_expected_aovs( output_file, name, start_frame, end_frame, img_fmt) }) else: for name in render_name: render_dict.update({ - name: self.get_expected_render_elements( + name: self.get_expected_aovs( output_file, name, start_frame, end_frame, img_fmt) }) @@ -188,7 +188,7 @@ class RenderProducts(object): if render_name: for name in render_name: render_dict.update({ - name: self.get_expected_render_elements( + name: self.get_expected_aovs( output_file, name, start_frame, end_frame, img_fmt) # noqa }) @@ -251,8 +251,8 @@ class RenderProducts(object): return render_name - def get_expected_render_elements(self, folder, name, - start_frame, end_frame, fmt): + def get_expected_aovs(self, folder, name, + start_frame, end_frame, fmt): """Get all the expected render element output files. """ render_elements = [] for f in range(start_frame, end_frame): From 9f90e3a1f15bba7e26303d3fafee5ef5d9bd238e Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 12 Jul 2023 19:35:57 +0800 Subject: [PATCH 08/47] hound fix --- openpype/hosts/max/api/lib_renderproducts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/max/api/lib_renderproducts.py b/openpype/hosts/max/api/lib_renderproducts.py index 59417a39fa..0b8c53dfa0 100644 --- a/openpype/hosts/max/api/lib_renderproducts.py +++ b/openpype/hosts/max/api/lib_renderproducts.py @@ -98,7 +98,7 @@ class RenderProducts(object): if render_name: for name in render_name: aovs_frames.update({ - f"{camera}_{name}": self.get_expected_arnold_product( + f"{camera}_{name}": self.get_expected_arnold_product( # noqa filename, name, start_frame, end_frame, ext) }) From c81818d09509b6b85e3259e6bac362717aa1ca1c Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 14 Jul 2023 20:25:49 +0800 Subject: [PATCH 09/47] add multi camera options for render creator --- openpype/hosts/max/api/lib_rendersettings.py | 6 +-- .../hosts/max/plugins/create/create_render.py | 19 ++++++++ .../max/plugins/publish/collect_render.py | 46 ++++++++++--------- 3 files changed, 47 insertions(+), 24 deletions(-) diff --git a/openpype/hosts/max/api/lib_rendersettings.py b/openpype/hosts/max/api/lib_rendersettings.py index 33cfc6dc4a..18160c66a0 100644 --- a/openpype/hosts/max/api/lib_rendersettings.py +++ b/openpype/hosts/max/api/lib_rendersettings.py @@ -177,8 +177,8 @@ class RenderSettings(object): render_element_list.append(aov_name) return render_element_list - def create_batch_render_layer(self, container, - output_dir, cameras): + def batch_render_layer(self, container, + output_dir, cameras): outputs = list() output = os.path.join(output_dir, container) img_fmt = self._project_settings["max"]["RenderSettings"]["image_format"] # noqa @@ -186,7 +186,7 @@ class RenderSettings(object): camera = rt.getNodeByName(cam) layer_no = rt.batchRenderMgr.FindView(cam) renderlayer = None - if layer_no is None: + if layer_no == 0: renderlayer = rt.batchRenderMgr.CreateView(camera) else: renderlayer = rt.batchRenderMgr.GetView(layer_no) diff --git a/openpype/hosts/max/plugins/create/create_render.py b/openpype/hosts/max/plugins/create/create_render.py index 23397e1a98..617334753a 100644 --- a/openpype/hosts/max/plugins/create/create_render.py +++ b/openpype/hosts/max/plugins/create/create_render.py @@ -2,6 +2,7 @@ """Creator plugin for creating camera.""" import os from openpype.hosts.max.api import plugin +from openpype.lib import BoolDef from openpype.hosts.max.api.lib_rendersettings import RenderSettings @@ -17,6 +18,7 @@ class CreateRender(plugin.MaxCreator): file = rt.maxFileName filename, _ = os.path.splitext(file) instance_data["AssetName"] = filename + instance_data["multiCamera"] = pre_create_data.get("multi_cam") num_of_renderlayer = rt.batchRenderMgr.numViews if num_of_renderlayer > 0: rt.batchRenderMgr.DeleteView(num_of_renderlayer) @@ -29,3 +31,20 @@ class CreateRender(plugin.MaxCreator): container_name = instance.data.get("instance_node") # set output paths for rendering(mandatory for deadline) RenderSettings().render_output(container_name) + # TODO: create multiple camera options + if self.selected_nodes: + selected_nodes_name = [] + for sel in self.selected_nodes: + name = sel.name + selected_nodes_name.append(name) + RenderSettings().batch_render_layer( + container_name, filename, + selected_nodes_name) + + def get_pre_create_attr_defs(self): + attrs = super(CreateRender, self).get_pre_create_attr_defs() + return attrs + [ + BoolDef("multi_cam", + label="Multiple Cameras Submission", + default=False), + ] diff --git a/openpype/hosts/max/plugins/publish/collect_render.py b/openpype/hosts/max/plugins/publish/collect_render.py index 736ffa5865..ca2f2f444f 100644 --- a/openpype/hosts/max/plugins/publish/collect_render.py +++ b/openpype/hosts/max/plugins/publish/collect_render.py @@ -26,22 +26,7 @@ class CollectRender(pyblish.api.InstancePlugin): file = rt.maxFileName current_file = os.path.join(folder, file) filepath = current_file.replace("\\", "/") - container_name = instance.data.get("instance_node") context.data['currentFile'] = current_file - cameras = instance.data.get("members") - sel_cam = [ - c.name for c in cameras - if rt.classOf(c) in rt.Camera.classes] - render_dir = os.path.dirname(rt.rendOutputFilename) - outputs = RenderSettings().create_batch_render_layer( - container_name, render_dir, sel_cam - ) - aov_outputs = RenderSettings().get_batch_render_elements( - container_name, render_dir, sel_cam - ) - files_aov = RenderProducts().get_multiple_beauty(outputs, cameras) - aovs = RenderProducts().get_multiple_aovs(outputs, cameras) - files_aov.update(aovs) asset = get_current_asset_name() files_by_aov = RenderProducts().get_beauty(instance.name) @@ -49,11 +34,33 @@ class CollectRender(pyblish.api.InstancePlugin): aovs = RenderProducts().get_aovs(instance.name) files_by_aov.update(aovs) + if instance.data.get("multiCamera"): + cameras = instance.data.get("members") + if not cameras: + raise RuntimeError("There should be at least" + " one renderable camera in container") + sel_cam = [ + c.name for c in cameras + if rt.classOf(c) in rt.Camera.classes] + container_name = instance.data.get("instance_node") + render_dir = os.path.dirname(rt.rendOutputFilename) + outputs = RenderSettings().batch_render_layer( + container_name, render_dir, sel_cam + ) + + instance.data["cameras"] = sel_cam + + files_by_aov = RenderProducts().get_multiple_beauty( + outputs, sel_cam) + aovs = RenderProducts().get_multiple_aovs( + outputs, sel_cam) + files_by_aov.update(aovs) + if "expectedFiles" not in instance.data: instance.data["expectedFiles"] = list() instance.data["files"] = list() - instance.data["expectedFiles"].append(files_aov) - instance.data["files"].append(files_aov) + instance.data["expectedFiles"].append(files_by_aov) + instance.data["files"].append(files_by_aov) img_format = RenderProducts().image_format() project_name = context.data["projectName"] @@ -94,13 +101,10 @@ class CollectRender(pyblish.api.InstancePlugin): "renderer": renderer, "source": filepath, "plugin": "3dsmax", - "cameras": sel_cam, "frameStart": int(rt.rendStart), "frameEnd": int(rt.rendEnd), "version": version_int, - "farm": True, - "renderoutput": outputs, - "aovoutput": aov_outputs + "farm": True } instance.data.update(data) From 22524c1d8473226b7687626b30b34ab237708fb5 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 17 Jul 2023 17:22:09 +0800 Subject: [PATCH 10/47] add option for multiple job and plugin infos --- openpype/hosts/max/api/lib_rendersettings.py | 21 ++-- .../deadline/abstract_submit_deadline.py | 25 ++++ .../plugins/publish/submit_max_deadline.py | 113 +++++++++++++++--- 3 files changed, 136 insertions(+), 23 deletions(-) diff --git a/openpype/hosts/max/api/lib_rendersettings.py b/openpype/hosts/max/api/lib_rendersettings.py index 18160c66a0..f2294fbf95 100644 --- a/openpype/hosts/max/api/lib_rendersettings.py +++ b/openpype/hosts/max/api/lib_rendersettings.py @@ -160,7 +160,7 @@ class RenderSettings(object): return orig_render_elem def get_batch_render_elements(self, container, - output_dir, cameras): + output_dir, camera): render_element_list = list() output = os.path.join(output_dir, container) render_elem = rt.maxOps.GetCurRenderElementMgr() @@ -168,15 +168,20 @@ class RenderSettings(object): if render_elem_num < 0: return img_fmt = self._project_settings["max"]["RenderSettings"]["image_format"] # noqa - for cam in cameras: - for i in range(render_elem_num): - renderlayer_name = render_elem.GetRenderElement(i) - target, renderpass = str(renderlayer_name).split(":") - aov_name = "{0}_{1}_{2}..{3}".format( - output, cam, renderpass, img_fmt) - render_element_list.append(aov_name) + + for i in range(render_elem_num): + renderlayer_name = render_elem.GetRenderElement(i) + target, renderpass = str(renderlayer_name).split(":") + aov_name = "{0}_{1}_{2}..{3}".format( + output, camera, renderpass, img_fmt) + render_element_list.append(aov_name) return render_element_list + def get_batch_render_output(self, camera): + target_layer_no = rt.batchRenderMgr.FindView(camera) + target_layer = rt.batchRenderMgr.GetView(target_layer_no) + return target_layer.outputFilename + def batch_render_layer(self, container, output_dir, cameras): outputs = list() diff --git a/openpype/modules/deadline/abstract_submit_deadline.py b/openpype/modules/deadline/abstract_submit_deadline.py index 551a2f7373..de6babf555 100644 --- a/openpype/modules/deadline/abstract_submit_deadline.py +++ b/openpype/modules/deadline/abstract_submit_deadline.py @@ -592,6 +592,31 @@ class AbstractSubmitDeadline(pyblish.api.InstancePlugin, return file_path + def get_job_info_through_camera(self, camera=None): + """Get the job parameters for deadline submission when + multi-camera is enabled. + Args: + infos(dict): a dictionary with job info. + """ + pass + + def get_plugin_info_through_camera(self, camera=None): + """Get the plugin parameters for deadline submission when + multi-camera is enabled. + Args: + infos(dict): a dictionary with plugin info. + """ + pass + + def _use_published_name_for_multiples(self, data): + """Process the parameters submission for deadline when + user enables multi-cameras option. + Args: + job_info_list (list): A list of multiple job infos + plugin_info_list (list): A list of multiple plugin infos + """ + pass + def assemble_payload( self, job_info=None, plugin_info=None, aux_files=None): """Assemble payload data from its various parts. diff --git a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py index 365be7b07b..6bbc956f55 100644 --- a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py @@ -56,7 +56,7 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, cls.priority) cls.chuck_size = settings.get("chunk_size", cls.chunk_size) cls.group = settings.get("group", cls.group) - + # TODO: multiple camera instance, separate job infos def get_job_info(self): job_info = DeadlineJobInfo(Plugin="3dsmax") @@ -73,7 +73,6 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, src_filepath = context.data["currentFile"] src_filename = os.path.basename(src_filepath) - job_info.Name = "%s - %s" % (src_filename, instance.name) job_info.BatchName = src_filename job_info.Plugin = instance.data["plugin"] @@ -179,9 +178,19 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, } self.log.debug("Submitting 3dsMax render..") - payload = self._use_published_name(payload_data) - job_info, plugin_info = payload - self.submit(self.assemble_payload(job_info, plugin_info)) + #TODO: multiple camera options + if instance.data.get("multiCamera"): + payload = self._use_published_name_for_multiples(payload_data) + job_infos, plugin_infos = payload + for job_info, plugin_info in zip(job_infos, plugin_infos): + self.log.debug(f"job_info: {job_info}") + self.log.debug(f"plugin_info: {plugin_info}") + submission = self.assemble_payload(job_info, plugin_info) + self.submit(submission) + else: + payload = self._use_published_name(payload_data) + job_info, plugin_info = payload + self.submit(self.assemble_payload(job_info, plugin_info)) def _use_published_name(self, data): instance = self._instance @@ -212,16 +221,6 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, plugin_data["RenderOutput"] = beauty_name # as 3dsmax has version with different languages plugin_data["Language"] = "ENU" - render_cameras = instance.data["cameras"] - if render_cameras: - for i, camera in enumerate(render_cameras): - cam_name = "Camera%s" % (i + 1) - plugin_data[cam_name] = camera - # set the default camera - plugin_data["Camera"] = camera - # set empty camera of Camera 0 for the ' - # correct parameter submission - plugin_data["Camera0"] = None renderer_class = get_current_renderer() @@ -250,6 +249,90 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, return job_info, plugin_info + def get_job_info_through_camera(self, camera): + instance = self._instance + context = instance.context + job_info = copy.deepcopy(self.job_info) + exp = instance.data.get("expectedFiles") + + src_filepath = context.data["currentFile"] + src_filename = os.path.basename(src_filepath) + job_info.Name = "%s - %s - %s" % ( + src_filename, instance.name, camera) + for filepath in self._iter_expected_files(exp): + if camera not in filepath: + continue + job_info.OutputDirectory += os.path.dirname(filepath) + job_info.OutputFilename += os.path.basename(filepath) + + return job_info + # set the output filepath with the relative camera + + def get_plugin_info_through_camera(self, camera): + instance = self._instance + # set the target camera + plugin_info = copy.deepcopy(self.plugin_info) + plugin_data = {} + # set the output filepath with the relative camera + files = instance.data.get("expectedFiles") + if not files: + raise RuntimeError("No render elements found") + first_file = next(self._iter_expected_files(files)) + old_output_dir = os.path.dirname(first_file) + rgb_output = RenderSettings().get_batch_render_output(camera) # noqa + rgb_bname = os.path.basename(rgb_output) + dir = os.path.dirname(first_file) + beauty_name = f"{dir}/{rgb_bname}" + beauty_name = beauty_name.replace("\\", "/") + plugin_info["RenderOutput"] = beauty_name + renderer_class = get_current_renderer() + + renderer = str(renderer_class).split(":")[0] + if renderer in [ + "ART_Renderer", + "Redshift_Renderer", + "V_Ray_6_Hotfix_3", + "V_Ray_GPU_6_Hotfix_3", + "Default_Scanline_Renderer", + "Quicksilver_Hardware_Renderer", + ]: + render_elem_list = RenderSettings().get_batch_render_elements( + instance.name, old_output_dir, camera + ) + for i, element in enumerate(render_elem_list): + elem_bname = os.path.basename(element) + new_elem = f"{dir}/{elem_bname}" + new_elem = new_elem.replace("/", "\\") + plugin_info["RenderElementOutputFilename%d" % i] = new_elem # noqa + + if camera: + # set the default camera + plugin_data["Camera"] = camera + + plugin_data["Camera0"] = None + + plugin_info.update(plugin_data) + return plugin_info + + def _use_published_name_for_multiples(self, data): + """Process the parameters submission for deadline when + user enables multi-cameras option. + Args: + job_info_list (list): A list of multiple job infos + plugin_info_list (list): A list of multiple plugin infos + """ + job_info_list = [] + plugin_info_list = [] + instance = self._instance + cameras = instance.data.get("cameras", []) + for cam in cameras: + job_info = self.get_job_info_through_camera(cam) + plugin_info = self.get_plugin_info_through_camera(cam) + job_info_list.append(job_info) + plugin_info_list.append(plugin_info) + + return job_info_list, plugin_info_list + def from_published_scene(self, replace_in_path=True): instance = self._instance if instance.data["renderer"] == "Redshift_Renderer": From 5ad81ea6bff0544cffdf7abe04a29eb64d8ec58c Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 17 Jul 2023 17:44:24 +0800 Subject: [PATCH 11/47] make sure camera parameters are being collected accurately --- .../plugins/publish/submit_max_deadline.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py index 6bbc956f55..23a2b4c679 100644 --- a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py @@ -131,11 +131,11 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, # Add list of expected files to job # --------------------------------- - exp = instance.data.get("expectedFiles") - - for filepath in self._iter_expected_files(exp): - job_info.OutputDirectory += os.path.dirname(filepath) - job_info.OutputFilename += os.path.basename(filepath) + if not instance.data.get("multiCamera"): + exp = instance.data.get("expectedFiles") + for filepath in self._iter_expected_files(exp): + job_info.OutputDirectory += os.path.dirname(filepath) + job_info.OutputFilename += os.path.basename(filepath) return job_info @@ -178,7 +178,7 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, } self.log.debug("Submitting 3dsMax render..") - #TODO: multiple camera options + if instance.data.get("multiCamera"): payload = self._use_published_name_for_multiples(payload_data) job_infos, plugin_infos = payload @@ -306,9 +306,10 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, plugin_info["RenderElementOutputFilename%d" % i] = new_elem # noqa if camera: - # set the default camera + # set the default camera and target camera + # (weird parameters from max) plugin_data["Camera"] = camera - + plugin_data["Camera1"] = camera plugin_data["Camera0"] = None plugin_info.update(plugin_data) From f5c8994fa31039b0549eddaa7bbe5ec8e5c3cee8 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 17 Jul 2023 20:21:34 +0800 Subject: [PATCH 12/47] get the correct naming for all render outputs --- openpype/hosts/max/api/lib_renderproducts.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openpype/hosts/max/api/lib_renderproducts.py b/openpype/hosts/max/api/lib_renderproducts.py index 5446e4fca3..863dccd99e 100644 --- a/openpype/hosts/max/api/lib_renderproducts.py +++ b/openpype/hosts/max/api/lib_renderproducts.py @@ -41,6 +41,8 @@ class RenderProducts(object): beauty_output_frames = dict() for output, camera in zip(outputs, cameras): filename, ext = os.path.splitext(output) + filename = filename.replace(".", "") + ext = ext.replace(".", "") start_frame = int(rt.rendStart) end_frame = int(rt.rendEnd) + 1 new_beauty = self.get_expected_beauty( @@ -57,6 +59,8 @@ class RenderProducts(object): aovs_frames = {} for output, camera in zip(outputs, cameras): filename, ext = os.path.splitext(output) + filename = filename.replace(".", "") + ext = ext.replace(".", "") start_frame = int(rt.rendStart) end_frame = int(rt.rendEnd) + 1 From 523ad0519dcbe52d4821d0981ddc4cc6962aaf60 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 17 Jul 2023 20:44:29 +0800 Subject: [PATCH 13/47] get all beauty as expected files in a correct manner --- openpype/hosts/max/api/lib_renderproducts.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/max/api/lib_renderproducts.py b/openpype/hosts/max/api/lib_renderproducts.py index 863dccd99e..eaf5015ba8 100644 --- a/openpype/hosts/max/api/lib_renderproducts.py +++ b/openpype/hosts/max/api/lib_renderproducts.py @@ -48,9 +48,10 @@ class RenderProducts(object): new_beauty = self.get_expected_beauty( filename, start_frame, end_frame, ext ) - beauty_output_frames = ({ + beauty_output = ({ f"{camera}_beauty": new_beauty }) + beauty_output_frames.update(beauty_output) return beauty_output_frames def get_multiple_aovs(self, outputs, cameras): From 3bb7f871d452fdef0e46db3a92518e8dd8d94afe Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 18 Jul 2023 17:57:04 +0800 Subject: [PATCH 14/47] bug fix camera instance doesn't include anything --- .../deadline/plugins/publish/submit_publish_job.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_publish_job.py b/openpype/modules/deadline/plugins/publish/submit_publish_job.py index 01a5c55286..1665a05f1e 100644 --- a/openpype/modules/deadline/plugins/publish/submit_publish_job.py +++ b/openpype/modules/deadline/plugins/publish/submit_publish_job.py @@ -361,7 +361,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin, self.log.info("Submitting Deadline job ...") url = "{}/api/jobs".format(self.deadline_url) - response = requests.post(url, json=payload, timeout=10) + response = requests.post(url, json=payload, timeout=10, verify=False) if not response.ok: raise Exception(response.text) @@ -472,6 +472,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin, host_name = self.context.data["hostName"] subset = instance_data["subset"] cameras = instance_data.get("cameras", []) + self.log.info(f"camera: {cameras}") instances = [] # go through aovs in expected files for aov, files in exp_files[0].items(): @@ -497,7 +498,8 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin, task[0].upper(), task[1:], subset[0].upper(), subset[1:]) - cam = [c for c in cameras if c in col.head] + cam = [c for c in cameras if c in cols[0].head] + self.log.debug(f"cam: {cam}") if cam: if aov: subset_name = '{}_{}_{}'.format(group_name, cam, aov) @@ -898,6 +900,12 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin, for v in values: instance_skeleton_data[v] = instance.data.get(v) + # if there are cameras, get the camera + # ]data for instance_skeleton_data + cameras = instance.data.get("cameras") + if cameras: + instance_skeleton_data["cameras"] = cameras + # look into instance data if representations are not having any # which are having tag `publish_on_farm` and include them for repre in instance.data.get("representations", []): From f349e720b09c78e6541eb7b10d6eb31f9020b425 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 20 Jul 2023 23:45:08 +0800 Subject: [PATCH 15/47] exporting camera scene through instanceplugin by subprocess --- openpype/hosts/max/api/lib_rendersettings.py | 18 +++ .../publish/save_scenes_for_cameras.py | 110 ++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py diff --git a/openpype/hosts/max/api/lib_rendersettings.py b/openpype/hosts/max/api/lib_rendersettings.py index 0a6f6569bf..2d453b9712 100644 --- a/openpype/hosts/max/api/lib_rendersettings.py +++ b/openpype/hosts/max/api/lib_rendersettings.py @@ -182,6 +182,24 @@ class RenderSettings(object): target_layer = rt.batchRenderMgr.GetView(target_layer_no) return target_layer.outputFilename + def batch_render_elements(self, camera): + target_layer_no = rt.batchRenderMgr.FindView(camera) + target_layer = rt.batchRenderMgr.GetView(target_layer_no) + outputfilename = target_layer.outputFilename + directory = os.path.dirname(outputfilename) + render_elem = rt.maxOps.GetCurRenderElementMgr() + render_elem_num = render_elem.NumRenderElements() + if render_elem_num < 0: + return + ext = self._project_settings["max"]["RenderSettings"]["image_format"] # noqa + + for i in range(render_elem_num): + renderlayer_name = render_elem.GetRenderElement(i) + target, renderpass = str(renderlayer_name).split(":") + aov_name = "{0}_{1}_{2}..{3}".format( + directory, camera, renderpass, ext) + render_elem.SetRenderElementFileName(i, aov_name) + def batch_render_layer(self, container, output_dir, cameras): outputs = list() diff --git a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py new file mode 100644 index 0000000000..d3357ba478 --- /dev/null +++ b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py @@ -0,0 +1,110 @@ +import pyblish.api +import os +import sys +import tempfile + +from pymxs import runtime as rt +from openpype.lib import run_subprocess +from openpype.hosts.max.api.lib import get_max_version +from openpype.hosts.max.api.lib_rendersettings import RenderSettings +from openpype.hosts.max.api.lib_renderproducts import RenderProducts + + +class SaveScenesForCamera(pyblish.api.InstancePlugin): + """Save scene files for multiple cameras before + deadline submission + + """ + + label = "Save Scene files for cameras" + order = pyblish.api.ExtractorOrder - 0.48 + hosts = ["max"] + families = ["maxrender", "workfile"] + + def process(self, instance): + if not instance.data.get("multiCamera"): + self.log.debug("Skipping instance...") + return + current_folder = rt.maxFilePath + current_filename = rt.maxFileName + current_filepath = os.path.join(current_folder, current_filename) + camera_scene_files = [] + repres_list = [] + scripts = [] + filename, ext = os.path.splitext(current_filename) + fmt = RenderProducts().image_format() + cameras = instance.data.get("cameras") + if not cameras: + return + new_folder = "{}_{}".format(current_folder, filename) + os.makedirs(new_folder, exist_ok=True) + for camera in cameras: + new_output = RenderSettings().get_batch_render_output(camera) # noqa + new_output = new_output.replace("\\", "/") + new_filename = "{}_{}{}".format( + filename, camera, ext) + new_filepath = os.path.join(new_folder, new_filename) + new_filepath = new_filepath.replace("\\", "/") + camera_scene_files.append(new_filepath) + RenderSettings().batch_render_elements(camera) + rt.rendOutputFilename = new_output + rt.saveMaxFile(current_filepath) + script = (""" +from pymxs import runtime as rt +import os +new_filepath = "{new_filepath}" +new_output = "{new_output}" +camera = "{camera}" +rt.rendOutputFilename = new_output +directory = os.path.dirname(new_output) +render_elem = rt.maxOps.GetCurRenderElementMgr() +render_elem_num = render_elem.NumRenderElements() +if render_elem_num > 0: + ext = "{ext}" + for i in range(render_elem_num): + renderlayer_name = render_elem.GetRenderElement(i) + target, renderpass = str(renderlayer_name).split(":") + aov_name = directory + "_" + camera + "_" + renderpass + "." + "." + ext + render_elem.SetRenderElementFileName(i, aov_name) +rt.saveMaxFile(new_filepath) + """).format(new_filepath=new_filepath, + new_output=new_output, + camera=camera, + ext=fmt) + scripts.append(script) + + max_version = get_max_version() + maxBatch_exe = os.path.join(os.getenv(f"ADSK_3DSMAX_x64_{max_version}"), "3dsmaxbatch") + maxBatch_exe = maxBatch_exe.replace("\\", "/") + if sys.platform == "windows": + maxBatch_exe += ".exe" + maxBatch_exe = os.path.normpath(maxBatch_exe) + with tempfile.TemporaryDirectory() as tmp_dir_name: + tmp_script_path = os.path.join(tmp_dir_name, "extract_scene_files.py") + log_file =os.path.join(tmp_dir_name, "fatal.log") + self.log.info("Using script file: {}".format(tmp_script_path)) + + with open(tmp_script_path, "wt") as tmp: + for script in scripts: + tmp.write(script+"\n") + tmp.write("rt.quitMax(quiet=True)"+"\n") + tmp.write("import time"+"\n") + tmp.write("time.sleep(3)") + + try: + current_filepath = current_filepath.replace("\\","/") + log_file = log_file.replace("\\", "/") + tmp_script_path = tmp_script_path.replace("\\","/") + run_subprocess([maxBatch_exe, tmp_script_path, + "-sceneFile", current_filepath]) + except RuntimeError: + self.log.debug("Checking the scene files existing or not") + + for camera_scene in camera_scene_files: + if not os.path.exists(camera_scene): + self.log.error("Camera scene files not existed yet!") + raise RuntimeError("MaxBatch.exe doesn't run as expected") + self.log.debug(f"Found Camera scene:{camera_scene}") + + if "sceneFiles" not in instance.data: + instance.data["sceneFiles"] = camera_scene_files From f4a864c0d2b0141f5cd81e40edb25b77374b22d7 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 20 Jul 2023 23:50:29 +0800 Subject: [PATCH 16/47] cosmetic fix --- .../plugins/publish/save_scenes_for_cameras.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py index d3357ba478..2abdb5dba1 100644 --- a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py +++ b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py @@ -74,27 +74,27 @@ rt.saveMaxFile(new_filepath) scripts.append(script) max_version = get_max_version() - maxBatch_exe = os.path.join(os.getenv(f"ADSK_3DSMAX_x64_{max_version}"), "3dsmaxbatch") + maxBatch_exe = os.path.join( + os.getenv(f"ADSK_3DSMAX_x64_{max_version}"), "3dsmaxbatch") maxBatch_exe = maxBatch_exe.replace("\\", "/") if sys.platform == "windows": maxBatch_exe += ".exe" maxBatch_exe = os.path.normpath(maxBatch_exe) with tempfile.TemporaryDirectory() as tmp_dir_name: - tmp_script_path = os.path.join(tmp_dir_name, "extract_scene_files.py") - log_file =os.path.join(tmp_dir_name, "fatal.log") + tmp_script_path = os.path.join( + tmp_dir_name, "extract_scene_files.py") self.log.info("Using script file: {}".format(tmp_script_path)) with open(tmp_script_path, "wt") as tmp: for script in scripts: - tmp.write(script+"\n") - tmp.write("rt.quitMax(quiet=True)"+"\n") - tmp.write("import time"+"\n") + tmp.write(script + "\n") + tmp.write("rt.quitMax(quiet=True)" + "\n") + tmp.write("import time" + "\n") tmp.write("time.sleep(3)") try: - current_filepath = current_filepath.replace("\\","/") - log_file = log_file.replace("\\", "/") - tmp_script_path = tmp_script_path.replace("\\","/") + current_filepath = current_filepath.replace("\\", "/") + tmp_script_path = tmp_script_path.replace("\\", "/") run_subprocess([maxBatch_exe, tmp_script_path, "-sceneFile", current_filepath]) except RuntimeError: From 7ae8b86c58ab061daa8b9acefab478adc14651fb Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 20 Jul 2023 23:51:21 +0800 Subject: [PATCH 17/47] hound fix --- openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py index 2abdb5dba1..af47959f8f 100644 --- a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py +++ b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py @@ -64,7 +64,7 @@ if render_elem_num > 0: for i in range(render_elem_num): renderlayer_name = render_elem.GetRenderElement(i) target, renderpass = str(renderlayer_name).split(":") - aov_name = directory + "_" + camera + "_" + renderpass + "." + "." + ext + aov_name = directory + "_" + camera + "_" + renderpass + "." + "." + ext # noqa render_elem.SetRenderElementFileName(i, aov_name) rt.saveMaxFile(new_filepath) """).format(new_filepath=new_filepath, From 3377150fe65342a421107fe71d08f72303cd0151 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 21 Jul 2023 16:14:36 +0800 Subject: [PATCH 18/47] clean up the save_scene_camera code --- .../plugins/publish/save_scenes_for_cameras.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py index af47959f8f..c6d264de32 100644 --- a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py +++ b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py @@ -29,7 +29,6 @@ class SaveScenesForCamera(pyblish.api.InstancePlugin): current_filename = rt.maxFileName current_filepath = os.path.join(current_folder, current_filename) camera_scene_files = [] - repres_list = [] scripts = [] filename, ext = os.path.splitext(current_filename) fmt = RenderProducts().image_format() @@ -88,9 +87,6 @@ rt.saveMaxFile(new_filepath) with open(tmp_script_path, "wt") as tmp: for script in scripts: tmp.write(script + "\n") - tmp.write("rt.quitMax(quiet=True)" + "\n") - tmp.write("import time" + "\n") - tmp.write("time.sleep(3)") try: current_filepath = current_filepath.replace("\\", "/") @@ -100,11 +96,23 @@ rt.saveMaxFile(new_filepath) except RuntimeError: self.log.debug("Checking the scene files existing or not") - for camera_scene in camera_scene_files: + for camera_scene, camera in zip(camera_scene_files, cameras): if not os.path.exists(camera_scene): self.log.error("Camera scene files not existed yet!") raise RuntimeError("MaxBatch.exe doesn't run as expected") self.log.debug(f"Found Camera scene:{camera_scene}") + instance.context.data["currentFile"] = camera_scene + representation = { + "name": "max", + "ext": "max", + "files": os.path.basename(camera_scene), + "stagingDir": new_folder, + "outputName": camera + } + self.log.debug(f"representation: {representation}") + if instance.data.get("representations") is None: + instance.data["representations"] = [] + instance.data["representations"].append(representation) if "sceneFiles" not in instance.data: instance.data["sceneFiles"] = camera_scene_files From 4144ca8e18fc2c5cf1e3b4971748cffa57ff3a9a Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 21 Jul 2023 16:45:48 +0800 Subject: [PATCH 19/47] clean up the save_scene_camera code --- .../publish/save_scenes_for_cameras.py | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py index c6d264de32..2369cf78a3 100644 --- a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py +++ b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py @@ -22,13 +22,11 @@ class SaveScenesForCamera(pyblish.api.InstancePlugin): families = ["maxrender", "workfile"] def process(self, instance): - if not instance.data.get("multiCamera"): - self.log.debug("Skipping instance...") - return current_folder = rt.maxFilePath current_filename = rt.maxFileName current_filepath = os.path.join(current_folder, current_filename) camera_scene_files = [] + repres_list = [] scripts = [] filename, ext = os.path.splitext(current_filename) fmt = RenderProducts().image_format() @@ -94,25 +92,25 @@ rt.saveMaxFile(new_filepath) run_subprocess([maxBatch_exe, tmp_script_path, "-sceneFile", current_filepath]) except RuntimeError: - self.log.debug("Checking the scene files existing or not") + self.log.debug("Checking the scene files existing") for camera_scene, camera in zip(camera_scene_files, cameras): if not os.path.exists(camera_scene): self.log.error("Camera scene files not existed yet!") raise RuntimeError("MaxBatch.exe doesn't run as expected") self.log.debug(f"Found Camera scene:{camera_scene}") - instance.context.data["currentFile"] = camera_scene representation = { - "name": "max", - "ext": "max", - "files": os.path.basename(camera_scene), - "stagingDir": new_folder, - "outputName": camera + "name": camera, + "ext": "max", + "files": os.path.basename(camera_scene), + "stagingDir": os.path.dirname(camera_scene), + "outputName": camera } - self.log.debug(f"representation: {representation}") - if instance.data.get("representations") is None: - instance.data["representations"] = [] - instance.data["representations"].append(representation) + repres_list.append(representation) if "sceneFiles" not in instance.data: instance.data["sceneFiles"] = camera_scene_files + + if instance.data.get("representations") is None: + instance.data["representations"] = [] + instance.data["representations"] = (repres_list) From d62b410efbc3776598d7705c0ee223f672e4a994 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 21 Jul 2023 16:57:51 +0800 Subject: [PATCH 20/47] clean up the save_scene_camera code --- openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py index 2369cf78a3..3031c0d4cf 100644 --- a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py +++ b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py @@ -113,4 +113,4 @@ rt.saveMaxFile(new_filepath) if instance.data.get("representations") is None: instance.data["representations"] = [] - instance.data["representations"] = (repres_list) + instance.data["representations"]= repres_list From 855143d217400b813f128b0804e599332dbe95d6 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 21 Jul 2023 17:11:26 +0800 Subject: [PATCH 21/47] clean up --- .../plugins/publish/save_scenes_for_cameras.py | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py index 3031c0d4cf..8aff9b58dd 100644 --- a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py +++ b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py @@ -11,8 +11,8 @@ from openpype.hosts.max.api.lib_renderproducts import RenderProducts class SaveScenesForCamera(pyblish.api.InstancePlugin): - """Save scene files for multiple cameras before - deadline submission + """Save scene files for multiple cameras without + editing the original scene before deadline submission """ @@ -26,7 +26,6 @@ class SaveScenesForCamera(pyblish.api.InstancePlugin): current_filename = rt.maxFileName current_filepath = os.path.join(current_folder, current_filename) camera_scene_files = [] - repres_list = [] scripts = [] filename, ext = os.path.splitext(current_filename) fmt = RenderProducts().image_format() @@ -99,18 +98,6 @@ rt.saveMaxFile(new_filepath) self.log.error("Camera scene files not existed yet!") raise RuntimeError("MaxBatch.exe doesn't run as expected") self.log.debug(f"Found Camera scene:{camera_scene}") - representation = { - "name": camera, - "ext": "max", - "files": os.path.basename(camera_scene), - "stagingDir": os.path.dirname(camera_scene), - "outputName": camera - } - repres_list.append(representation) if "sceneFiles" not in instance.data: instance.data["sceneFiles"] = camera_scene_files - - if instance.data.get("representations") is None: - instance.data["representations"] = [] - instance.data["representations"]= repres_list From 7ecb5ba056f2e5adf5f6ebbc6af19db16b207d56 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 21 Jul 2023 17:14:23 +0800 Subject: [PATCH 22/47] hound fix --- openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py index 8aff9b58dd..918b6cda43 100644 --- a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py +++ b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py @@ -93,7 +93,7 @@ rt.saveMaxFile(new_filepath) except RuntimeError: self.log.debug("Checking the scene files existing") - for camera_scene, camera in zip(camera_scene_files, cameras): + for camera_scene in camera_scene_files: if not os.path.exists(camera_scene): self.log.error("Camera scene files not existed yet!") raise RuntimeError("MaxBatch.exe doesn't run as expected") From 0a7d24ba5f2f3b8dfaaeb7b0fbf8309c27ce5c38 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 21 Jul 2023 18:27:00 +0800 Subject: [PATCH 23/47] use sys.executable to find the directory of maxBatch.exe --- openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py index 918b6cda43..0ccc69591a 100644 --- a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py +++ b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py @@ -5,7 +5,6 @@ import tempfile from pymxs import runtime as rt from openpype.lib import run_subprocess -from openpype.hosts.max.api.lib import get_max_version from openpype.hosts.max.api.lib_rendersettings import RenderSettings from openpype.hosts.max.api.lib_renderproducts import RenderProducts @@ -69,9 +68,8 @@ rt.saveMaxFile(new_filepath) ext=fmt) scripts.append(script) - max_version = get_max_version() maxBatch_exe = os.path.join( - os.getenv(f"ADSK_3DSMAX_x64_{max_version}"), "3dsmaxbatch") + os.path.dirname(sys.executable), "3dsmaxbatch") maxBatch_exe = maxBatch_exe.replace("\\", "/") if sys.platform == "windows": maxBatch_exe += ".exe" From 7692b95f1c113c8f2da8c0ae335398c0f7740a17 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 21 Jul 2023 19:37:00 +0800 Subject: [PATCH 24/47] change the scene_path command in submit 3dsmax renders and make sure render elements have the correct path --- .../publish/save_scenes_for_cameras.py | 19 +++++++++++-------- .../plugins/publish/submit_max_deadline.py | 5 ++++- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py index 0ccc69591a..9561f53996 100644 --- a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py +++ b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py @@ -18,7 +18,7 @@ class SaveScenesForCamera(pyblish.api.InstancePlugin): label = "Save Scene files for cameras" order = pyblish.api.ExtractorOrder - 0.48 hosts = ["max"] - families = ["maxrender", "workfile"] + families = ["maxrender"] def process(self, instance): current_folder = rt.maxFilePath @@ -47,11 +47,13 @@ class SaveScenesForCamera(pyblish.api.InstancePlugin): script = (""" from pymxs import runtime as rt import os +filename = "{filename}" new_filepath = "{new_filepath}" new_output = "{new_output}" camera = "{camera}" rt.rendOutputFilename = new_output -directory = os.path.dirname(new_output) +directory = os.path.dirname(rt.rendOutputFilename) +directory = os.path.join(directory, filename) render_elem = rt.maxOps.GetCurRenderElementMgr() render_elem_num = render_elem.NumRenderElements() if render_elem_num > 0: @@ -62,18 +64,19 @@ if render_elem_num > 0: aov_name = directory + "_" + camera + "_" + renderpass + "." + "." + ext # noqa render_elem.SetRenderElementFileName(i, aov_name) rt.saveMaxFile(new_filepath) - """).format(new_filepath=new_filepath, + """).format(filename=filename, + new_filepath=new_filepath, new_output=new_output, camera=camera, ext=fmt) scripts.append(script) - maxBatch_exe = os.path.join( + maxbatch_exe = os.path.join( os.path.dirname(sys.executable), "3dsmaxbatch") - maxBatch_exe = maxBatch_exe.replace("\\", "/") + maxbatch_exe = maxbatch_exe.replace("\\", "/") if sys.platform == "windows": - maxBatch_exe += ".exe" - maxBatch_exe = os.path.normpath(maxBatch_exe) + maxbatch_exe += ".exe" + maxbatch_exe = os.path.normpath(maxbatch_exe) with tempfile.TemporaryDirectory() as tmp_dir_name: tmp_script_path = os.path.join( tmp_dir_name, "extract_scene_files.py") @@ -86,7 +89,7 @@ rt.saveMaxFile(new_filepath) try: current_filepath = current_filepath.replace("\\", "/") tmp_script_path = tmp_script_path.replace("\\", "/") - run_subprocess([maxBatch_exe, tmp_script_path, + run_subprocess([maxbatch_exe, tmp_script_path, "-sceneFile", current_filepath]) except RuntimeError: self.log.debug("Checking the scene files existing") diff --git a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py index 5fed10a7c5..57f4353dcc 100644 --- a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py @@ -12,7 +12,6 @@ from openpype.pipeline import ( legacy_io, OpenPypePyblishPluginMixin ) -from openpype.settings import get_project_settings from openpype.hosts.max.api.lib import ( get_current_renderer, get_multipass_setting @@ -272,8 +271,12 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, instance = self._instance # set the target camera plugin_info = copy.deepcopy(self.plugin_info) + plugin_data = {} # set the output filepath with the relative camera + for camera_scene_path in instance.data.get("sceneFiles"): + if camera in camera_scene_path: + plugin_data["SceneFile"] = camera_scene_path files = instance.data.get("expectedFiles") if not files: raise RuntimeError("No render elements found") From b8952629705de15b9fbcc2ca18bba16bd83b7014 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 21 Jul 2023 20:51:16 +0800 Subject: [PATCH 25/47] if multiCamera enabled, the deadline submission wont use the published workfiles to render --- .../modules/deadline/plugins/publish/submit_max_deadline.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py index 57f4353dcc..f3d873a1db 100644 --- a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py @@ -349,7 +349,11 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, if instance.data["renderer"] == "Redshift_Renderer": self.log.debug("Using Redshift...published scene wont be used..") replace_in_path = False - return replace_in_path + + if instance.data["multiCamera"] == True: + self.log.debug("Using Redshift...published scene wont be used..") + replace_in_path = False + return replace_in_path @staticmethod def _iter_expected_files(exp): From 5893675dc0e96dbcef99c5dc89fabc5b9831a783 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 21 Jul 2023 20:53:35 +0800 Subject: [PATCH 26/47] some cosmetic fix --- .../modules/deadline/plugins/publish/submit_max_deadline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py index f3d873a1db..904732c4b4 100644 --- a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py @@ -350,7 +350,7 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, self.log.debug("Using Redshift...published scene wont be used..") replace_in_path = False - if instance.data["multiCamera"] == True: + if instance.data.get("multiCamera"): self.log.debug("Using Redshift...published scene wont be used..") replace_in_path = False return replace_in_path From 9801ad52a0e42fbc2a69e0b5c514453d0a6d4954 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 24 Jul 2023 18:30:58 +0800 Subject: [PATCH 27/47] make sure the renderpass subset name is correct when saving scenes for camera in subprocess --- .../max/plugins/publish/save_scenes_for_cameras.py | 2 +- .../deadline/plugins/publish/submit_max_deadline.py | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py index 9561f53996..9382a8f4b3 100644 --- a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py +++ b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py @@ -64,7 +64,7 @@ if render_elem_num > 0: aov_name = directory + "_" + camera + "_" + renderpass + "." + "." + ext # noqa render_elem.SetRenderElementFileName(i, aov_name) rt.saveMaxFile(new_filepath) - """).format(filename=filename, + """).format(filename=instance.name, new_filepath=new_filepath, new_output=new_output, camera=camera, diff --git a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py index 904732c4b4..822962b23e 100644 --- a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py @@ -303,10 +303,11 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, instance.name, old_output_dir, camera ) for i, element in enumerate(render_elem_list): - elem_bname = os.path.basename(element) - new_elem = f"{dir}/{elem_bname}" - new_elem = new_elem.replace("/", "\\") - plugin_info["RenderElementOutputFilename%d" % i] = new_elem # noqa + if camera in element: + elem_bname = os.path.basename(element) + new_elem = f"{dir}/{elem_bname}" + new_elem = new_elem.replace("/", "\\") + plugin_info["RenderElementOutputFilename%d" % i] = new_elem # noqa if camera: # set the default camera and target camera @@ -349,10 +350,6 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, if instance.data["renderer"] == "Redshift_Renderer": self.log.debug("Using Redshift...published scene wont be used..") replace_in_path = False - - if instance.data.get("multiCamera"): - self.log.debug("Using Redshift...published scene wont be used..") - replace_in_path = False return replace_in_path @staticmethod From ed55100dd19d2f99d572a78999278b73a78b1c76 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 31 Jul 2023 17:37:21 +0800 Subject: [PATCH 28/47] ondrej's comment --- .../publish/save_scenes_for_cameras.py | 3 --- .../deadline/abstract_submit_deadline.py | 25 ------------------ .../plugins/publish/submit_max_deadline.py | 26 ++++++++++++++++--- 3 files changed, 22 insertions(+), 32 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py index 9382a8f4b3..79e9088ac7 100644 --- a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py +++ b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py @@ -99,6 +99,3 @@ rt.saveMaxFile(new_filepath) self.log.error("Camera scene files not existed yet!") raise RuntimeError("MaxBatch.exe doesn't run as expected") self.log.debug(f"Found Camera scene:{camera_scene}") - - if "sceneFiles" not in instance.data: - instance.data["sceneFiles"] = camera_scene_files diff --git a/openpype/modules/deadline/abstract_submit_deadline.py b/openpype/modules/deadline/abstract_submit_deadline.py index ae568c43e3..3fa427204b 100644 --- a/openpype/modules/deadline/abstract_submit_deadline.py +++ b/openpype/modules/deadline/abstract_submit_deadline.py @@ -531,31 +531,6 @@ class AbstractSubmitDeadline(pyblish.api.InstancePlugin, return replace_with_published_scene_path( self._instance, replace_in_path=replace_in_path) - def get_job_info_through_camera(self, camera=None): - """Get the job parameters for deadline submission when - multi-camera is enabled. - Args: - infos(dict): a dictionary with job info. - """ - pass - - def get_plugin_info_through_camera(self, camera=None): - """Get the plugin parameters for deadline submission when - multi-camera is enabled. - Args: - infos(dict): a dictionary with plugin info. - """ - pass - - def _use_published_name_for_multiples(self, data): - """Process the parameters submission for deadline when - user enables multi-cameras option. - Args: - job_info_list (list): A list of multiple job infos - plugin_info_list (list): A list of multiple plugin infos - """ - pass - def assemble_payload( self, job_info=None, plugin_info=None, aux_files=None): """Assemble payload data from its various parts. diff --git a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py index 822962b23e..78e570a780 100644 --- a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py @@ -164,7 +164,7 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, def process_submission(self): instance = self._instance - filepath = self.scene_path + filepath = instance.context.data["currentFile"] files = instance.data["expectedFiles"] if not files: @@ -184,6 +184,7 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, self.log.debug("Submitting 3dsMax render..") project_settings = instance.context.data["project_settings"] if instance.data.get("multiCamera"): + self.log.debug("Submitting jobs for multiple cameras..") payload = self._use_published_name_for_multiples( payload_data, project_settings) job_infos, plugin_infos = payload @@ -249,6 +250,11 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, return job_info, plugin_info def get_job_info_through_camera(self, camera): + """Get the job parameters for deadline submission when + multi-camera is enabled. + Args: + infos(dict): a dictionary with job info. + """ instance = self._instance context = instance.context job_info = copy.deepcopy(self.job_info) @@ -268,15 +274,27 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, # set the output filepath with the relative camera def get_plugin_info_through_camera(self, camera): + """Get the plugin parameters for deadline submission when + multi-camera is enabled. + Args: + infos(dict): a dictionary with plugin info. + """ instance = self._instance # set the target camera plugin_info = copy.deepcopy(self.plugin_info) plugin_data = {} # set the output filepath with the relative camera - for camera_scene_path in instance.data.get("sceneFiles"): - if camera in camera_scene_path: - plugin_data["SceneFile"] = camera_scene_path + if instance.data.get("multiCamera"): + scene_filepath = instance.context.data["currentFile"] + scene_filename = os.path.basename(scene_filepath) + scene_directory = os.path.dirname(scene_filepath) + current_filename, ext = os.path.splitext(scene_filename) + camera_scene_name = f"{current_filename}_{camera}{ext}" + camera_scene_filepath = os.path.join( + scene_directory, f"_{current_filename}", camera_scene_name) + plugin_data["SceneFile"] = camera_scene_filepath + files = instance.data.get("expectedFiles") if not files: raise RuntimeError("No render elements found") From 0d9873dd41dc71d603b100469a1faa419688a85c Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 31 Jul 2023 22:32:19 +0800 Subject: [PATCH 29/47] ondrej's comment --- .../modules/deadline/plugins/publish/submit_max_deadline.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py index 78e570a780..15019c2647 100644 --- a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py @@ -12,6 +12,7 @@ from openpype.pipeline import ( legacy_io, OpenPypePyblishPluginMixin ) +from openpype.pipeline.publish import KnownPublishError from openpype.hosts.max.api.lib import ( get_current_renderer, get_multipass_setting @@ -168,7 +169,7 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, files = instance.data["expectedFiles"] if not files: - raise RuntimeError("No Render Elements found!") + raise KnownPublishError("No Render Elements found!") first_file = next(self._iter_expected_files(files)) output_dir = os.path.dirname(first_file) instance.data["outputDir"] = output_dir From 3e49e6c642b1813d90111bd4007b039f46fded27 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 31 Jul 2023 23:19:31 +0800 Subject: [PATCH 30/47] use KnownPublishError instead of RuntimeError --- .../modules/deadline/plugins/publish/submit_max_deadline.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py index 15019c2647..29ce315bdc 100644 --- a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py @@ -210,7 +210,7 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, files = instance.data.get("expectedFiles") if not files: - raise RuntimeError("No render elements found") + raise KnownPublishError("No render elements found") first_file = next(self._iter_expected_files(files)) old_output_dir = os.path.dirname(first_file) output_beauty = RenderSettings().get_render_output(instance.name, @@ -298,7 +298,7 @@ class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline, files = instance.data.get("expectedFiles") if not files: - raise RuntimeError("No render elements found") + raise KnownPublishError("No render elements found") first_file = next(self._iter_expected_files(files)) old_output_dir = os.path.dirname(first_file) rgb_output = RenderSettings().get_batch_render_output(camera) # noqa From 1e19bfa6949c7340a7ea146d87d66d1f2bb80aa4 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 30 Aug 2023 16:42:58 +0800 Subject: [PATCH 31/47] fix the weird naming of publish render folder --- openpype/pipeline/farm/pyblish_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/pipeline/farm/pyblish_functions.py b/openpype/pipeline/farm/pyblish_functions.py index fe3ab97de8..61cceb80ad 100644 --- a/openpype/pipeline/farm/pyblish_functions.py +++ b/openpype/pipeline/farm/pyblish_functions.py @@ -583,7 +583,7 @@ def _create_instances_for_aov(instance, skeleton, aov_filter, additional_data, else: # in case of single frame cam = [c for c in cameras if c in col] - if cam: + if cam or subset != "maxrenderMain": if aov: subset_name = '{}_{}_{}'.format(group_name, cam, aov) else: From 960e7a24bc68cb913ef4a6b6857d01b0006f04cd Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 30 Aug 2023 17:32:31 +0800 Subject: [PATCH 32/47] fixing bigroy's comment on camera subset interruption --- openpype/pipeline/farm/pyblish_functions.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openpype/pipeline/farm/pyblish_functions.py b/openpype/pipeline/farm/pyblish_functions.py index 61cceb80ad..fb73e46508 100644 --- a/openpype/pipeline/farm/pyblish_functions.py +++ b/openpype/pipeline/farm/pyblish_functions.py @@ -583,11 +583,15 @@ def _create_instances_for_aov(instance, skeleton, aov_filter, additional_data, else: # in case of single frame cam = [c for c in cameras if c in col] - if cam or subset != "maxrenderMain": + if cam: if aov: subset_name = '{}_{}_{}'.format(group_name, cam, aov) + if subset == "maxrenderMain": + subset_name = '{}_{}'.format(group_name, aov) else: subset_name = '{}_{}'.format(group_name, cam) + if subset == "maxrenderMain": + subset_name = '{}'.format(group_name) else: if aov: subset_name = '{}_{}'.format(group_name, aov) From 749ca64e58caa9b95df2edc0347c72d44e15c151 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 30 Aug 2023 18:54:14 +0800 Subject: [PATCH 33/47] roy's comment on the subset naming based on cameras in multiple camera rendering --- openpype/pipeline/farm/pyblish_functions.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/openpype/pipeline/farm/pyblish_functions.py b/openpype/pipeline/farm/pyblish_functions.py index fb73e46508..0c5d6a2712 100644 --- a/openpype/pipeline/farm/pyblish_functions.py +++ b/openpype/pipeline/farm/pyblish_functions.py @@ -579,18 +579,24 @@ def _create_instances_for_aov(instance, skeleton, aov_filter, additional_data, # if there are multiple cameras, we need to add camera name if isinstance(col, (list, tuple)): - cam = [c for c in cameras if c in col[0]] + cam = next((c for c in cameras if c in col[0]), None) else: # in case of single frame - cam = [c for c in cameras if c in col] + cam = next((cam for cam in cameras if cam in col), None) if cam: if aov: subset_name = '{}_{}_{}'.format(group_name, cam, aov) if subset == "maxrenderMain": + # Max submit scenes by cameras for multiple camera + # submission, it results to include the camera name inside + # the original subset and i.e group_name subset_name = '{}_{}'.format(group_name, aov) else: subset_name = '{}_{}'.format(group_name, cam) if subset == "maxrenderMain": + # Max submit scenes by cameras for multiple camera + # submission, it results to include the camera name inside + # the original subset and i.e group_name subset_name = '{}'.format(group_name) else: if aov: From 1f2e32311f71448d2cc16348871d36ebf0093f04 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 30 Aug 2023 20:34:44 +0800 Subject: [PATCH 34/47] remove camera_name in aov if there is one --- openpype/pipeline/farm/pyblish_functions.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/openpype/pipeline/farm/pyblish_functions.py b/openpype/pipeline/farm/pyblish_functions.py index 0c5d6a2712..58ffeb937f 100644 --- a/openpype/pipeline/farm/pyblish_functions.py +++ b/openpype/pipeline/farm/pyblish_functions.py @@ -585,19 +585,13 @@ def _create_instances_for_aov(instance, skeleton, aov_filter, additional_data, cam = next((cam for cam in cameras if cam in col), None) if cam: if aov: + # if there is duplicatd camera name found in aov, + # it would be removed + if aov.startswith(cam): + aov = aov.replace(f"{cam}_", "") subset_name = '{}_{}_{}'.format(group_name, cam, aov) - if subset == "maxrenderMain": - # Max submit scenes by cameras for multiple camera - # submission, it results to include the camera name inside - # the original subset and i.e group_name - subset_name = '{}_{}'.format(group_name, aov) else: subset_name = '{}_{}'.format(group_name, cam) - if subset == "maxrenderMain": - # Max submit scenes by cameras for multiple camera - # submission, it results to include the camera name inside - # the original subset and i.e group_name - subset_name = '{}'.format(group_name) else: if aov: subset_name = '{}_{}'.format(group_name, aov) From 30ea0213b72237cdc9bd2920c691fb22cf184338 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 5 Sep 2023 18:40:07 +0800 Subject: [PATCH 35/47] add pattern for clique.assemble function to just iterate through frame ranges --- openpype/pipeline/farm/pyblish_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/pipeline/farm/pyblish_functions.py b/openpype/pipeline/farm/pyblish_functions.py index 58ffeb937f..3f19c3cc95 100644 --- a/openpype/pipeline/farm/pyblish_functions.py +++ b/openpype/pipeline/farm/pyblish_functions.py @@ -548,7 +548,7 @@ def _create_instances_for_aov(instance, skeleton, aov_filter, additional_data, instances = [] # go through AOVs in expected files for aov, files in exp_files[0].items(): - cols, rem = clique.assemble(files) + cols, rem = clique.assemble(files, patterns=[clique.PATTERNS['frames']]) # we shouldn't have any reminders. And if we do, it should # be just one item for single frame renders. if not cols and rem: From 44391391df926316b8c7585e526ebbaffc5ab3d6 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 5 Sep 2023 18:41:00 +0800 Subject: [PATCH 36/47] hound --- openpype/pipeline/farm/pyblish_functions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/pipeline/farm/pyblish_functions.py b/openpype/pipeline/farm/pyblish_functions.py index 3f19c3cc95..5713c13c4e 100644 --- a/openpype/pipeline/farm/pyblish_functions.py +++ b/openpype/pipeline/farm/pyblish_functions.py @@ -548,7 +548,8 @@ def _create_instances_for_aov(instance, skeleton, aov_filter, additional_data, instances = [] # go through AOVs in expected files for aov, files in exp_files[0].items(): - cols, rem = clique.assemble(files, patterns=[clique.PATTERNS['frames']]) + cols, rem = clique.assemble( + files, patterns=[clique.PATTERNS['frames']]) # we shouldn't have any reminders. And if we do, it should # be just one item for single frame renders. if not cols and rem: From 60e5eb74aeee01ad6a621554eac950a5852cdb90 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 5 Sep 2023 18:43:30 +0800 Subject: [PATCH 37/47] big roy's comments on the line 582-583 --- openpype/pipeline/farm/pyblish_functions.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/openpype/pipeline/farm/pyblish_functions.py b/openpype/pipeline/farm/pyblish_functions.py index 5713c13c4e..0bdc2b1339 100644 --- a/openpype/pipeline/farm/pyblish_functions.py +++ b/openpype/pipeline/farm/pyblish_functions.py @@ -579,11 +579,8 @@ def _create_instances_for_aov(instance, skeleton, aov_filter, additional_data, group_name = subset # if there are multiple cameras, we need to add camera name - if isinstance(col, (list, tuple)): - cam = next((c for c in cameras if c in col[0]), None) - else: - # in case of single frame - cam = next((cam for cam in cameras if cam in col), None) + expected_filepath = col[0] if isinstance(col, (list, tuple)) else col + cam = next((cam for cam in cameras if cam in expected_filepath), None) if cam: if aov: # if there is duplicatd camera name found in aov, From 75d17fcdffb6e10b049110be6defa023b6a5d68e Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 5 Sep 2023 18:56:45 +0800 Subject: [PATCH 38/47] restore the pattern for not breaking the submit publish job --- openpype/pipeline/farm/pyblish_functions.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openpype/pipeline/farm/pyblish_functions.py b/openpype/pipeline/farm/pyblish_functions.py index 0bdc2b1339..181aad6cb5 100644 --- a/openpype/pipeline/farm/pyblish_functions.py +++ b/openpype/pipeline/farm/pyblish_functions.py @@ -548,8 +548,7 @@ def _create_instances_for_aov(instance, skeleton, aov_filter, additional_data, instances = [] # go through AOVs in expected files for aov, files in exp_files[0].items(): - cols, rem = clique.assemble( - files, patterns=[clique.PATTERNS['frames']]) + cols, rem = clique.assemble(files) # we shouldn't have any reminders. And if we do, it should # be just one item for single frame renders. if not cols and rem: From dadc6fa85747cb4790b226e2279fdacd1744064c Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 26 Sep 2023 15:12:21 +0800 Subject: [PATCH 39/47] make sure render outputs with all cameras should be in the render publish folder --- openpype/pipeline/farm/pyblish_functions.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/openpype/pipeline/farm/pyblish_functions.py b/openpype/pipeline/farm/pyblish_functions.py index 181aad6cb5..5019d01be3 100644 --- a/openpype/pipeline/farm/pyblish_functions.py +++ b/openpype/pipeline/farm/pyblish_functions.py @@ -582,11 +582,13 @@ def _create_instances_for_aov(instance, skeleton, aov_filter, additional_data, cam = next((cam for cam in cameras if cam in expected_filepath), None) if cam: if aov: - # if there is duplicatd camera name found in aov, - # it would be removed - if aov.startswith(cam): - aov = aov.replace(f"{cam}_", "") - subset_name = '{}_{}_{}'.format(group_name, cam, aov) + # Multiple cameras publishing in some hosts such as 3dsMax + # have aov data set to "Camera001_beauty" to differentiate + # the render output files + if not aov.startswith(cam): + subset_name = '{}_{}_{}'.format(group_name, cam, aov) + else: + subset_name = '{}_{}'.format(group_name, aov) else: subset_name = '{}_{}'.format(group_name, cam) else: @@ -594,7 +596,6 @@ def _create_instances_for_aov(instance, skeleton, aov_filter, additional_data, subset_name = '{}_{}'.format(group_name, aov) else: subset_name = '{}'.format(group_name) - if isinstance(col, (list, tuple)): staging = os.path.dirname(col[0]) else: From 55555e3078e3289e663f13709334e0ed4e038e72 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 27 Sep 2023 22:00:38 +0800 Subject: [PATCH 40/47] iterate the camera list --- openpype/pipeline/farm/pyblish_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/pipeline/farm/pyblish_functions.py b/openpype/pipeline/farm/pyblish_functions.py index 5019d01be3..1a5cbbf3e2 100644 --- a/openpype/pipeline/farm/pyblish_functions.py +++ b/openpype/pipeline/farm/pyblish_functions.py @@ -579,7 +579,7 @@ def _create_instances_for_aov(instance, skeleton, aov_filter, additional_data, # if there are multiple cameras, we need to add camera name expected_filepath = col[0] if isinstance(col, (list, tuple)) else col - cam = next((cam for cam in cameras if cam in expected_filepath), None) + cam = next(iter(cam for cam in cameras if cam in expected_filepath), None) if cam: if aov: # Multiple cameras publishing in some hosts such as 3dsMax From 810b3259d1e7441bda9a147bdf4942a6a9fd101c Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 27 Sep 2023 22:29:41 +0800 Subject: [PATCH 41/47] hound --- openpype/pipeline/farm/pyblish_functions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/pipeline/farm/pyblish_functions.py b/openpype/pipeline/farm/pyblish_functions.py index 1a5cbbf3e2..e5530481d2 100644 --- a/openpype/pipeline/farm/pyblish_functions.py +++ b/openpype/pipeline/farm/pyblish_functions.py @@ -579,7 +579,8 @@ def _create_instances_for_aov(instance, skeleton, aov_filter, additional_data, # if there are multiple cameras, we need to add camera name expected_filepath = col[0] if isinstance(col, (list, tuple)) else col - cam = next(iter(cam for cam in cameras if cam in expected_filepath), None) + cam = next( + iter(cam for cam in cameras if cam in expected_filepath), None) if cam: if aov: # Multiple cameras publishing in some hosts such as 3dsMax From 824912dba1e1d6d793d872d93188312bb6e43309 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 28 Sep 2023 19:08:09 +0800 Subject: [PATCH 42/47] update camera subset name condition --- openpype/pipeline/farm/pyblish_functions.py | 22 ++++++++++----------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/openpype/pipeline/farm/pyblish_functions.py b/openpype/pipeline/farm/pyblish_functions.py index e5530481d2..f0d330da71 100644 --- a/openpype/pipeline/farm/pyblish_functions.py +++ b/openpype/pipeline/farm/pyblish_functions.py @@ -579,24 +579,22 @@ def _create_instances_for_aov(instance, skeleton, aov_filter, additional_data, # if there are multiple cameras, we need to add camera name expected_filepath = col[0] if isinstance(col, (list, tuple)) else col - cam = next( - iter(cam for cam in cameras if cam in expected_filepath), None) - if cam: - if aov: - # Multiple cameras publishing in some hosts such as 3dsMax - # have aov data set to "Camera001_beauty" to differentiate - # the render output files - if not aov.startswith(cam): - subset_name = '{}_{}_{}'.format(group_name, cam, aov) + cams = [cam for cam in cameras if cam in expected_filepath] + if cams: + for cam in cams: + if aov: + if not aov.startswith(cam): + subset_name = '{}_{}_{}'.format(group_name, cam, aov) + else: + subset_name = "{}_{}".format(group_name, aov) else: - subset_name = '{}_{}'.format(group_name, aov) - else: - subset_name = '{}_{}'.format(group_name, cam) + subset_name = '{}_{}'.format(group_name, cam) else: if aov: subset_name = '{}_{}'.format(group_name, aov) else: subset_name = '{}'.format(group_name) + if isinstance(col, (list, tuple)): staging = os.path.dirname(col[0]) else: From 5b2e5faccdbd0e425e0d9f438f0e82f96fe15c24 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 19 Oct 2023 18:30:03 +0800 Subject: [PATCH 43/47] remove if condition of cameras --- openpype/pipeline/farm/pyblish_functions.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/openpype/pipeline/farm/pyblish_functions.py b/openpype/pipeline/farm/pyblish_functions.py index f0d330da71..8ae46ae1a1 100644 --- a/openpype/pipeline/farm/pyblish_functions.py +++ b/openpype/pipeline/farm/pyblish_functions.py @@ -580,20 +580,17 @@ def _create_instances_for_aov(instance, skeleton, aov_filter, additional_data, # if there are multiple cameras, we need to add camera name expected_filepath = col[0] if isinstance(col, (list, tuple)) else col cams = [cam for cam in cameras if cam in expected_filepath] - if cams: - for cam in cams: - if aov: - if not aov.startswith(cam): - subset_name = '{}_{}_{}'.format(group_name, cam, aov) - else: - subset_name = "{}_{}".format(group_name, aov) - else: - subset_name = '{}_{}'.format(group_name, cam) - else: + for cam in cams: if aov: - subset_name = '{}_{}'.format(group_name, aov) + if aov.startswith(cam): + subset_name = '{}_{}_{}'.format(group_name, cam, aov) + else: + subset_name = "{}_{}".format(group_name, aov) else: - subset_name = '{}'.format(group_name) + if aov.startswith(cam): + subset_name = '{}_{}'.format(group_name, cam) + else: + subset_name = '{}'.format(group_name) if isinstance(col, (list, tuple)): staging = os.path.dirname(col[0]) From 5bb6f304d381938d1effa7cc089971ab85f46352 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 19 Oct 2023 19:26:42 +0800 Subject: [PATCH 44/47] use known publish error instead of runtime error --- openpype/hosts/max/plugins/publish/collect_render.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/max/plugins/publish/collect_render.py b/openpype/hosts/max/plugins/publish/collect_render.py index 78ab02ef5e..01d7cff32d 100644 --- a/openpype/hosts/max/plugins/publish/collect_render.py +++ b/openpype/hosts/max/plugins/publish/collect_render.py @@ -5,6 +5,7 @@ import pyblish.api from pymxs import runtime as rt from openpype.pipeline import get_current_asset_name +from openpype.pipeline.publish import KnownPublishError from openpype.hosts.max.api import colorspace from openpype.hosts.max.api.lib import get_max_version, get_current_renderer from openpype.hosts.max.api.lib_rendersettings import RenderSettings @@ -45,8 +46,8 @@ class CollectRender(pyblish.api.InstancePlugin): if instance.data.get("multiCamera"): cameras = instance.data.get("members") if not cameras: - raise RuntimeError("There should be at least" - " one renderable camera in container") + raise KnownPublishError("There should be at least" + " one renderable camera in container") sel_cam = [ c.name for c in cameras if rt.classOf(c) in rt.Camera.classes] From e3e8770ffefb25a2b89388f70f51d385a10b0cb5 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 19 Oct 2023 20:31:06 +0800 Subject: [PATCH 45/47] restore the function code for test --- openpype/pipeline/farm/pyblish_functions.py | 25 +++++++++++---------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/openpype/pipeline/farm/pyblish_functions.py b/openpype/pipeline/farm/pyblish_functions.py index 3254fbdfda..c9e013a09a 100644 --- a/openpype/pipeline/farm/pyblish_functions.py +++ b/openpype/pipeline/farm/pyblish_functions.py @@ -578,20 +578,21 @@ def _create_instances_for_aov(instance, skeleton, aov_filter, additional_data, else: group_name = subset - # if there are multiple cameras, we need to add camera name - expected_filepath = col[0] if isinstance(col, (list, tuple)) else col - cams = [cam for cam in cameras if cam in expected_filepath] - for cam in cams: + if isinstance(col, (list, tuple)): + cam = [c for c in cameras if c in col[0]] + else: + # in case of single frame + cam = [c for c in cameras if c in col] + if cam: if aov: - if aov.startswith(cam): - subset_name = '{}_{}_{}'.format(group_name, cam, aov) - else: - subset_name = "{}_{}".format(group_name, aov) + subset_name = '{}_{}_{}'.format(group_name, cam, aov) else: - if aov.startswith(cam): - subset_name = '{}_{}'.format(group_name, cam) - else: - subset_name = '{}'.format(group_name) + subset_name = '{}_{}'.format(group_name, cam) + else: + if aov: + subset_name = '{}_{}'.format(group_name, aov) + else: + subset_name = '{}'.format(group_name) if isinstance(col, (list, tuple)): staging = os.path.dirname(col[0]) From e9005c66184c5b6145a342e5258256c1929b111a Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 31 Oct 2023 12:59:24 +0800 Subject: [PATCH 46/47] make sure subset name conditions are applicable for other hosts such as maya --- openpype/pipeline/farm/pyblish_functions.py | 22 +++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/openpype/pipeline/farm/pyblish_functions.py b/openpype/pipeline/farm/pyblish_functions.py index c9e013a09a..6265449515 100644 --- a/openpype/pipeline/farm/pyblish_functions.py +++ b/openpype/pipeline/farm/pyblish_functions.py @@ -578,16 +578,18 @@ def _create_instances_for_aov(instance, skeleton, aov_filter, additional_data, else: group_name = subset - if isinstance(col, (list, tuple)): - cam = [c for c in cameras if c in col[0]] - else: - # in case of single frame - cam = [c for c in cameras if c in col] - if cam: - if aov: - subset_name = '{}_{}_{}'.format(group_name, cam, aov) - else: - subset_name = '{}_{}'.format(group_name, cam) + # if there are multiple cameras, we need to add camera name + expected_filepath = col[0] if isinstance(col, (list, tuple)) else col + cams = [cam for cam in cameras if cam in expected_filepath] + if cams: + for cam in cams: + if aov: + if not aov.startswith(cam): + subset_name = '{}_{}_{}'.format(group_name, cam, aov) + else: + subset_name = "{}_{}".format(group_name, aov) + else: + subset_name = '{}_{}'.format(group_name, cam) else: if aov: subset_name = '{}_{}'.format(group_name, aov) From 333433057ea2728f1646a20ee602b72c40e5c1ba Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 3 Jan 2024 21:48:38 +0800 Subject: [PATCH 47/47] cosmetic tweaks regarding to Ondrej's comment --- openpype/hosts/max/api/lib_rendersettings.py | 15 ++++++--------- .../plugins/publish/save_scenes_for_cameras.py | 7 +++---- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/openpype/hosts/max/api/lib_rendersettings.py b/openpype/hosts/max/api/lib_rendersettings.py index 166076f008..be50e296eb 100644 --- a/openpype/hosts/max/api/lib_rendersettings.py +++ b/openpype/hosts/max/api/lib_rendersettings.py @@ -80,7 +80,7 @@ class RenderSettings(object): )] except KeyError: aov_separator = "." - output_filename = "{0}..{1}".format(output, img_fmt) + output_filename = f"{output}..{img_fmt}" output_filename = output_filename.replace("{aov_separator}", aov_separator) rt.rendOutputFilename = output_filename @@ -146,13 +146,13 @@ class RenderSettings(object): for i in range(render_elem_num): renderlayer_name = render_elem.GetRenderElement(i) target, renderpass = str(renderlayer_name).split(":") - aov_name = "{0}_{1}..{2}".format(dir, renderpass, ext) + aov_name = f"{dir}_{renderpass}..{ext}" render_elem.SetRenderElementFileName(i, aov_name) def get_render_output(self, container, output_dir): output = os.path.join(output_dir, container) img_fmt = self._project_settings["max"]["RenderSettings"]["image_format"] # noqa - output_filename = "{0}..{1}".format(output, img_fmt) + output_filename = f"{output}..{img_fmt}" return output_filename def get_render_element(self): @@ -181,8 +181,7 @@ class RenderSettings(object): for i in range(render_elem_num): renderlayer_name = render_elem.GetRenderElement(i) target, renderpass = str(renderlayer_name).split(":") - aov_name = "{0}_{1}_{2}..{3}".format( - output, camera, renderpass, img_fmt) + aov_name = f"{output}_{camera}_{renderpass}..{img_fmt}" render_element_list.append(aov_name) return render_element_list @@ -205,8 +204,7 @@ class RenderSettings(object): for i in range(render_elem_num): renderlayer_name = render_elem.GetRenderElement(i) target, renderpass = str(renderlayer_name).split(":") - aov_name = "{0}_{1}_{2}..{3}".format( - directory, camera, renderpass, ext) + aov_name = f"{directory}_{camera}_{renderpass}..{ext}" render_elem.SetRenderElementFileName(i, aov_name) def batch_render_layer(self, container, @@ -224,7 +222,6 @@ class RenderSettings(object): renderlayer = rt.batchRenderMgr.GetView(layer_no) # use camera name as renderlayer name renderlayer.name = cam - renderlayer.outputFilename = "{0}_{1}..{2}".format( - output, cam, img_fmt) + renderlayer.outputFilename = f"{output}_{cam}..{img_fmt}" outputs.append(renderlayer.outputFilename) return outputs diff --git a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py index 79e9088ac7..c39109417b 100644 --- a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py +++ b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py @@ -31,13 +31,12 @@ class SaveScenesForCamera(pyblish.api.InstancePlugin): cameras = instance.data.get("cameras") if not cameras: return - new_folder = "{}_{}".format(current_folder, filename) + new_folder = f"{current_folder}_{filename}" os.makedirs(new_folder, exist_ok=True) for camera in cameras: new_output = RenderSettings().get_batch_render_output(camera) # noqa new_output = new_output.replace("\\", "/") - new_filename = "{}_{}{}".format( - filename, camera, ext) + new_filename = f"{filename}_{camera}{ext}" new_filepath = os.path.join(new_folder, new_filename) new_filepath = new_filepath.replace("\\", "/") camera_scene_files.append(new_filepath) @@ -61,7 +60,7 @@ if render_elem_num > 0: for i in range(render_elem_num): renderlayer_name = render_elem.GetRenderElement(i) target, renderpass = str(renderlayer_name).split(":") - aov_name = directory + "_" + camera + "_" + renderpass + "." + "." + ext # noqa + aov_name = f"{{directory}}_{camera}_{{renderpass}}..{ext}" render_elem.SetRenderElementFileName(i, aov_name) rt.saveMaxFile(new_filepath) """).format(filename=instance.name,