From 0483714dcb55f2f7b2db5892c640ef6b673f393f Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Mon, 13 Mar 2023 17:49:44 +0100 Subject: [PATCH 01/20] Change "Maya" to Fusion in comment --- openpype/hosts/fusion/api/action.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/fusion/api/action.py b/openpype/hosts/fusion/api/action.py index 1750920950..ff5dd14caa 100644 --- a/openpype/hosts/fusion/api/action.py +++ b/openpype/hosts/fusion/api/action.py @@ -6,12 +6,13 @@ from openpype.pipeline.publish import get_errored_instances_from_context class SelectInvalidAction(pyblish.api.Action): - """Select invalid nodes in Maya when plug-in failed. + """Select invalid nodes in Fusion when plug-in failed. To retrieve the invalid nodes this assumes a static `get_invalid()` method is available on the plugin. """ + label = "Select invalid" on = "failed" # This action is only available on a failed plug-in icon = "search" # Icon from Awesome Icon @@ -31,8 +32,10 @@ class SelectInvalidAction(pyblish.api.Action): if isinstance(invalid_nodes, (list, tuple)): invalid.extend(invalid_nodes) else: - self.log.warning("Plug-in returned to be invalid, " - "but has no selectable nodes.") + self.log.warning( + "Plug-in returned to be invalid, " + "but has no selectable nodes." + ) if not invalid: # Assume relevant comp is current comp and clear selection @@ -51,4 +54,6 @@ class SelectInvalidAction(pyblish.api.Action): for tool in invalid: flow.Select(tool, True) names.add(tool.Name) - self.log.info("Selecting invalid tools: %s" % ", ".join(sorted(names))) + self.log.info( + "Selecting invalid tools: %s" % ", ".join(sorted(names)) + ) From ea7390d1d3e91385cd7f723c3067cebabf5cca03 Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Mon, 13 Mar 2023 17:50:56 +0100 Subject: [PATCH 02/20] Added create and instance attr to Create plugin Where they get it from should be moved into another folder so other plugins can get the same data. --- .../fusion/plugins/create/create_saver.py | 83 +++++++++++++------ 1 file changed, 56 insertions(+), 27 deletions(-) diff --git a/openpype/hosts/fusion/plugins/create/create_saver.py b/openpype/hosts/fusion/plugins/create/create_saver.py index e581bac20f..56085b0a06 100644 --- a/openpype/hosts/fusion/plugins/create/create_saver.py +++ b/openpype/hosts/fusion/plugins/create/create_saver.py @@ -4,29 +4,34 @@ import qtawesome from openpype.hosts.fusion.api import ( get_current_comp, - comp_lock_and_undo_chunk + comp_lock_and_undo_chunk, ) -from openpype.lib import BoolDef +from openpype.lib import ( + BoolDef, + EnumDef, +) from openpype.pipeline import ( legacy_io, Creator, - CreatedInstance + CreatedInstance, +) +from openpype.client import ( + get_asset_by_name, ) -from openpype.client import get_asset_by_name class CreateSaver(Creator): identifier = "io.openpype.creators.fusion.saver" - name = "saver" - label = "Saver" + label = "Render (saver)" + name = "render" family = "render" - default_variants = ["Main"] - + default_variants = ["Main", "Mask"] description = "Fusion Saver to generate image sequence" - def create(self, subset_name, instance_data, pre_create_data): + instance_attributes = ["reviewable"] + def create(self, subset_name, instance_data, pre_create_data): # TODO: Add pre_create attributes to choose file format? file_format = "OpenEXRFormat" @@ -58,7 +63,8 @@ class CreateSaver(Creator): family=self.family, subset_name=subset_name, data=instance_data, - creator=self) + creator=self, + ) # Insert the transient data instance.transient_data["tool"] = saver @@ -68,11 +74,9 @@ class CreateSaver(Creator): return instance def collect_instances(self): - comp = get_current_comp() tools = comp.GetToolList(False, "Saver").values() for tool in tools: - data = self.get_managed_tool_data(tool) if not data: data = self._collect_unmanaged_saver(tool) @@ -90,7 +94,6 @@ class CreateSaver(Creator): def update_instances(self, update_list): for created_inst, _changes in update_list: - new_data = created_inst.data_to_store() tool = created_inst.transient_data["tool"] self._update_tool_with_data(tool, new_data) @@ -139,7 +142,6 @@ class CreateSaver(Creator): tool.SetAttrs({"TOOLS_Name": subset}) def _collect_unmanaged_saver(self, tool): - # TODO: this should not be done this way - this should actually # get the data as stored on the tool explicitly (however) # that would disallow any 'regular saver' to be collected @@ -153,8 +155,7 @@ class CreateSaver(Creator): asset = legacy_io.Session["AVALON_ASSET"] task = legacy_io.Session["AVALON_TASK"] - asset_doc = get_asset_by_name(project_name=project, - asset_name=asset) + asset_doc = get_asset_by_name(project_name=project, asset_name=asset) path = tool["Clip"][comp.TIME_UNDEFINED] fname = os.path.basename(path) @@ -178,21 +179,20 @@ class CreateSaver(Creator): "variant": variant, "active": not passthrough, "family": self.family, - # Unique identifier for instance and this creator "id": "pyblish.avalon.instance", - "creator_identifier": self.identifier + "creator_identifier": self.identifier, } def get_managed_tool_data(self, tool): """Return data of the tool if it matches creator identifier""" - data = tool.GetData('openpype') + data = tool.GetData("openpype") if not isinstance(data, dict): return required = { "id": "pyblish.avalon.instance", - "creator_identifier": self.identifier + "creator_identifier": self.identifier, } for key, value in required.items(): if key not in data or data[key] != value: @@ -205,11 +205,40 @@ class CreateSaver(Creator): return data - def get_instance_attr_defs(self): - return [ - BoolDef( - "review", - default=True, - label="Review" - ) + def get_pre_create_attr_defs(self): + """Settings for create page""" + attr_defs = [ + self._get_render_target_enum(), + self._get_reviewable_bool(), ] + return attr_defs + + def get_instance_attr_defs(self): + """Settings for publish page""" + attr_defs = [ + self._get_render_target_enum(), + self._get_reviewable_bool(), + ] + return attr_defs + + # These functions below should be moved to another file + # so it can be used by other plugins. plugin.py ? + + def _get_render_target_enum(self): + rendering_targets = { + "local": "Local machine rendering", + "frames": "Use existing frames", + } + if "farm_rendering" in self.instance_attributes: + rendering_targets["farm"] = "Farm rendering" + + return EnumDef( + "render_target", items=rendering_targets, label="Render target" + ) + + def _get_reviewable_bool(self): + return BoolDef( + "review", + default=("reviewable" in self.instance_attributes), + label="Review", + ) From 0414045f362bdd6c2ecfeb5851b82f129de4f710 Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Mon, 13 Mar 2023 17:54:02 +0100 Subject: [PATCH 03/20] Split the render into render and review data --- .../plugins/publish/collect_render_target.py | 44 --------------- .../fusion/plugins/publish/collect_renders.py | 42 ++++++++++++++ ...ender_local.py => extract_render_local.py} | 46 ++-------------- .../plugins/publish/extract_review_data.py | 55 +++++++++++++++++++ 4 files changed, 102 insertions(+), 85 deletions(-) delete mode 100644 openpype/hosts/fusion/plugins/publish/collect_render_target.py create mode 100644 openpype/hosts/fusion/plugins/publish/collect_renders.py rename openpype/hosts/fusion/plugins/publish/{render_local.py => extract_render_local.py} (59%) create mode 100644 openpype/hosts/fusion/plugins/publish/extract_review_data.py diff --git a/openpype/hosts/fusion/plugins/publish/collect_render_target.py b/openpype/hosts/fusion/plugins/publish/collect_render_target.py deleted file mode 100644 index 39017f32e0..0000000000 --- a/openpype/hosts/fusion/plugins/publish/collect_render_target.py +++ /dev/null @@ -1,44 +0,0 @@ -import pyblish.api - - -class CollectFusionRenderMode(pyblish.api.InstancePlugin): - """Collect current comp's render Mode - - Options: - local - farm - - Note that this value is set for each comp separately. When you save the - comp this information will be stored in that file. If for some reason the - available tool does not visualize which render mode is set for the - current comp, please run the following line in the console (Py2) - - comp.GetData("openpype.rendermode") - - This will return the name of the current render mode as seen above under - Options. - - """ - - order = pyblish.api.CollectorOrder + 0.4 - label = "Collect Render Mode" - hosts = ["fusion"] - families = ["render"] - - def process(self, instance): - """Collect all image sequence tools""" - options = ["local", "farm"] - - comp = instance.context.data.get("currentComp") - if not comp: - raise RuntimeError("No comp previously collected, unable to " - "retrieve Fusion version.") - - rendermode = comp.GetData("openpype.rendermode") or "local" - assert rendermode in options, "Must be supported render mode" - - self.log.info("Render mode: {0}".format(rendermode)) - - # Append family - family = "render.{0}".format(rendermode) - instance.data["families"].append(family) diff --git a/openpype/hosts/fusion/plugins/publish/collect_renders.py b/openpype/hosts/fusion/plugins/publish/collect_renders.py new file mode 100644 index 0000000000..cdd37b3b65 --- /dev/null +++ b/openpype/hosts/fusion/plugins/publish/collect_renders.py @@ -0,0 +1,42 @@ +import pyblish.api +from pprint import pformat + + +class CollectFusionRenders(pyblish.api.InstancePlugin): + """Collect current comp's render Mode + + Options: + local + farm + + Note that this value is set for each comp separately. When you save the + comp this information will be stored in that file. If for some reason the + available tool does not visualize which render mode is set for the + current comp, please run the following line in the console (Py2) + + comp.GetData("openpype.rendermode") + + This will return the name of the current render mode as seen above under + Options. + + """ + + order = pyblish.api.CollectorOrder + 0.4 + label = "Collect Renders" + hosts = ["fusion"] + families = ["render"] + + def process(self, instance): + self.log.debug(pformat(instance.data)) + + saver_node = instance.data["transientData"]["tool"] + render_target = instance.data["render_target"] + family = instance.data["family"] + families = instance.data["families"] + + # add targeted family to families + instance.data["families"].append( + "{}.{}".format(family, render_target) + ) + + self.log.debug(pformat(instance.data)) diff --git a/openpype/hosts/fusion/plugins/publish/render_local.py b/openpype/hosts/fusion/plugins/publish/extract_render_local.py similarity index 59% rename from openpype/hosts/fusion/plugins/publish/render_local.py rename to openpype/hosts/fusion/plugins/publish/extract_render_local.py index 7d5f1a40c7..62625c899a 100644 --- a/openpype/hosts/fusion/plugins/publish/render_local.py +++ b/openpype/hosts/fusion/plugins/publish/extract_render_local.py @@ -4,16 +4,12 @@ from openpype.pipeline import publish from openpype.hosts.fusion.api import comp_lock_and_undo_chunk -class Fusionlocal(pyblish.api.InstancePlugin, - publish.ColormanagedPyblishPluginMixin): - """Render the current Fusion composition locally. +class FusionRenderLocal( + pyblish.api.InstancePlugin, publish.ColormanagedPyblishPluginMixin +): + """Render the current Fusion composition locally.""" - Extract the result of savers by starting a comp render - This will run the local render of Fusion. - - """ - - order = pyblish.api.ExtractorOrder - 0.1 + order = pyblish.api.ExtractorOrder - 0.2 label = "Render Local" hosts = ["fusion"] families = ["render.local"] @@ -33,38 +29,6 @@ class Fusionlocal(pyblish.api.InstancePlugin, ) ) - frame_start = context.data["frameStartHandle"] - frame_end = context.data["frameEndHandle"] - path = instance.data["path"] - output_dir = instance.data["outputDir"] - - basename = os.path.basename(path) - head, ext = os.path.splitext(basename) - files = [ - f"{head}{str(frame).zfill(4)}{ext}" - for frame in range(frame_start, frame_end + 1) - ] - repre = { - "name": ext[1:], - "ext": ext[1:], - "frameStart": f"%0{len(str(frame_end))}d" % frame_start, - "files": files, - "stagingDir": output_dir, - } - - self.set_representation_colorspace( - representation=repre, - context=context, - ) - - if "representations" not in instance.data: - instance.data["representations"] = [] - instance.data["representations"].append(repre) - - # review representation - if instance.data.get("review", False): - repre["tags"] = ["review", "ftrackreview"] - def render_once(self, context): """Render context comp only once, even with more render instances""" diff --git a/openpype/hosts/fusion/plugins/publish/extract_review_data.py b/openpype/hosts/fusion/plugins/publish/extract_review_data.py new file mode 100644 index 0000000000..d9416771f6 --- /dev/null +++ b/openpype/hosts/fusion/plugins/publish/extract_review_data.py @@ -0,0 +1,55 @@ +import os +import pyblish.api +from openpype.pipeline.publish import ( + ColormanagedPyblishPluginMixin, +) + + +class FusionExtractReviewData( + pyblish.api.InstancePlugin, ColormanagedPyblishPluginMixin +): + """ + Extract the result of savers by starting a comp render + This will run the local render of Fusion. + """ + + order = pyblish.api.ExtractorOrder - 0.1 + label = "Extract Review Data" + hosts = ["fusion"] + families = ["review"] + + def process(self, instance): + context = instance.context + + frame_start = context.data["frameStartHandle"] + frame_end = context.data["frameEndHandle"] + path = instance.data["path"] + output_dir = instance.data["outputDir"] + + basename = os.path.basename(path) + head, ext = os.path.splitext(basename) + files = [ + f"{head}{str(frame).zfill(4)}{ext}" + for frame in range(frame_start, frame_end + 1) + ] + repre = { + "name": ext[1:], + "ext": ext[1:], + "frameStart": f"%0{len(str(frame_end))}d" % frame_start, + "files": files, + "stagingDir": output_dir, + } + + self.set_representation_colorspace( + representation=repre, + context=context, + ) + + # review representation + if instance.data.get("review", False): + repre["tags"] = ["review"] + + # add the repre to the instance + if "representations" not in instance.data: + instance.data["representations"] = [] + instance.data["representations"].append(repre) From ba8d03715229693745ef5df4525c6eb0fc156bf2 Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Mon, 13 Mar 2023 17:54:47 +0100 Subject: [PATCH 04/20] Validate that frames for "use existing frames" do exist --- .../validate_local_frames_existence.py | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 openpype/hosts/fusion/plugins/publish/validate_local_frames_existence.py diff --git a/openpype/hosts/fusion/plugins/publish/validate_local_frames_existence.py b/openpype/hosts/fusion/plugins/publish/validate_local_frames_existence.py new file mode 100644 index 0000000000..d80e11e078 --- /dev/null +++ b/openpype/hosts/fusion/plugins/publish/validate_local_frames_existence.py @@ -0,0 +1,71 @@ +import os +import pyblish.api + +from openpype.pipeline.publish import RepairAction +from openpype.pipeline import PublishValidationError + +from openpype.hosts.fusion.api.action import SelectInvalidAction + + +class ValidateLocalFramesExistence(pyblish.api.InstancePlugin): + """Checks if files for savers that's set to publish existing frames exists""" + + order = pyblish.api.ValidatorOrder + label = "Validate Existing Frames Exists" + families = ["render"] + hosts = ["fusion"] + actions = [RepairAction, SelectInvalidAction] + + @classmethod + def get_invalid(cls, instance): + active = instance.data.get("active", instance.data.get("publish")) + if not active: + return [] + + if instance.data.get("render_target") == "frames": + tool = instance[0] + + frame_start = instance.data["frameStart"] + frame_end = instance.data["frameEnd"] + path = instance.data["path"] + output_dir = instance.data["outputDir"] + + basename = os.path.basename(path) + head, ext = os.path.splitext(basename) + files = [ + f"{head}{str(frame).zfill(4)}{ext}" + for frame in range(frame_start, frame_end + 1) + ] + + non_existing_frames = [] + + for file in files: + cls.log.error(file) + if not os.path.exists(os.path.join(output_dir, file)): + non_existing_frames.append(file) + + if len(non_existing_frames) > 0: + cls.log.error( + "Some of {}'s files does not exist".format(tool.Name) + ) + return [tool, output_dir, non_existing_frames] + + def process(self, instance): + invalid = self.get_invalid(instance) + if invalid: + raise PublishValidationError( + "{} is set to publish existing frames but " + "some frames are missing in the folder:\n\n{}" + "The missing file(s) are:\n\n{}".format( + invalid[0].Name, + invalid[1], + "\n\n".join(invalid[2]), + ), + title=self.label, + ) + + @classmethod + def repair(cls, instance): + invalid = cls.get_invalid(instance) + for tool in invalid: + tool.SetInput("CreateDir", 1.0) From a15e29afaf5ff8e78296f36cea9f06d036e1cccf Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Mon, 13 Mar 2023 17:55:04 +0100 Subject: [PATCH 05/20] Fixed repair-button to show up on review tab --- .../plugins/publish/validate_create_folder_checked.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/fusion/plugins/publish/validate_create_folder_checked.py b/openpype/hosts/fusion/plugins/publish/validate_create_folder_checked.py index ba943abacb..53dea2af71 100644 --- a/openpype/hosts/fusion/plugins/publish/validate_create_folder_checked.py +++ b/openpype/hosts/fusion/plugins/publish/validate_create_folder_checked.py @@ -14,11 +14,10 @@ class ValidateCreateFolderChecked(pyblish.api.InstancePlugin): """ order = pyblish.api.ValidatorOrder - actions = [RepairAction] label = "Validate Create Folder Checked" families = ["render"] hosts = ["fusion"] - actions = [SelectInvalidAction] + actions = [RepairAction, SelectInvalidAction] @classmethod def get_invalid(cls, instance): @@ -29,7 +28,9 @@ class ValidateCreateFolderChecked(pyblish.api.InstancePlugin): tool = instance[0] create_dir = tool.GetInput("CreateDir") if create_dir == 0.0: - cls.log.error("%s has Create Folder turned off" % instance[0].Name) + cls.log.error( + "%s has Create Folder turned off" % instance[0].Name + ) return [tool] def process(self, instance): @@ -37,7 +38,8 @@ class ValidateCreateFolderChecked(pyblish.api.InstancePlugin): if invalid: raise PublishValidationError( "Found Saver with Create Folder During Render checked off", - title=self.label) + title=self.label, + ) @classmethod def repair(cls, instance): From 73b6ee58ae61b6ee88d6cd6bd28f78c6610220f1 Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Mon, 13 Mar 2023 17:57:09 +0100 Subject: [PATCH 06/20] Remove old Render Mode menu --- openpype/hosts/fusion/api/menu.py | 12 -- .../hosts/fusion/scripts/set_rendermode.py | 112 ------------------ 2 files changed, 124 deletions(-) delete mode 100644 openpype/hosts/fusion/scripts/set_rendermode.py diff --git a/openpype/hosts/fusion/api/menu.py b/openpype/hosts/fusion/api/menu.py index 343f5f803a..ba3ce6798d 100644 --- a/openpype/hosts/fusion/api/menu.py +++ b/openpype/hosts/fusion/api/menu.py @@ -60,7 +60,6 @@ class OpenPypeMenu(QtWidgets.QWidget): publish_btn = QtWidgets.QPushButton("Publish...", self) manager_btn = QtWidgets.QPushButton("Manage...", self) libload_btn = QtWidgets.QPushButton("Library...", self) - rendermode_btn = QtWidgets.QPushButton("Set render mode...", self) set_framerange_btn = QtWidgets.QPushButton("Set Frame Range", self) set_resolution_btn = QtWidgets.QPushButton("Set Resolution", self) duplicate_with_inputs_btn = QtWidgets.QPushButton( @@ -91,7 +90,6 @@ class OpenPypeMenu(QtWidgets.QWidget): layout.addWidget(set_framerange_btn) layout.addWidget(set_resolution_btn) - layout.addWidget(rendermode_btn) layout.addSpacing(20) @@ -108,7 +106,6 @@ class OpenPypeMenu(QtWidgets.QWidget): load_btn.clicked.connect(self.on_load_clicked) manager_btn.clicked.connect(self.on_manager_clicked) libload_btn.clicked.connect(self.on_libload_clicked) - rendermode_btn.clicked.connect(self.on_rendermode_clicked) duplicate_with_inputs_btn.clicked.connect( self.on_duplicate_with_inputs_clicked ) @@ -162,15 +159,6 @@ class OpenPypeMenu(QtWidgets.QWidget): def on_libload_clicked(self): host_tools.show_library_loader() - def on_rendermode_clicked(self): - if self.render_mode_widget is None: - window = set_rendermode.SetRenderMode() - window.setStyleSheet(load_stylesheet()) - window.show() - self.render_mode_widget = window - else: - self.render_mode_widget.show() - def on_duplicate_with_inputs_clicked(self): duplicate_with_inputs.duplicate_with_input_connections() diff --git a/openpype/hosts/fusion/scripts/set_rendermode.py b/openpype/hosts/fusion/scripts/set_rendermode.py deleted file mode 100644 index 9d2bfef310..0000000000 --- a/openpype/hosts/fusion/scripts/set_rendermode.py +++ /dev/null @@ -1,112 +0,0 @@ -from qtpy import QtWidgets -import qtawesome -from openpype.hosts.fusion.api import get_current_comp - - -_help = {"local": "Render the comp on your own machine and publish " - "it from that the destination folder", - "farm": "Submit a Fusion render job to a Render farm to use all other" - " computers and add a publish job"} - - -class SetRenderMode(QtWidgets.QWidget): - - def __init__(self, parent=None): - QtWidgets.QWidget.__init__(self, parent) - - self._comp = get_current_comp() - self._comp_name = self._get_comp_name() - - self.setWindowTitle("Set Render Mode") - self.setFixedSize(300, 175) - - layout = QtWidgets.QVBoxLayout() - - # region comp info - comp_info_layout = QtWidgets.QHBoxLayout() - - update_btn = QtWidgets.QPushButton(qtawesome.icon("fa.refresh", - color="white"), "") - update_btn.setFixedWidth(25) - update_btn.setFixedHeight(25) - - comp_information = QtWidgets.QLineEdit() - comp_information.setEnabled(False) - - comp_info_layout.addWidget(comp_information) - comp_info_layout.addWidget(update_btn) - # endregion comp info - - # region modes - mode_options = QtWidgets.QComboBox() - mode_options.addItems(_help.keys()) - - mode_information = QtWidgets.QTextEdit() - mode_information.setReadOnly(True) - # endregion modes - - accept_btn = QtWidgets.QPushButton("Accept") - - layout.addLayout(comp_info_layout) - layout.addWidget(mode_options) - layout.addWidget(mode_information) - layout.addWidget(accept_btn) - - self.setLayout(layout) - - self.comp_information = comp_information - self.update_btn = update_btn - - self.mode_options = mode_options - self.mode_information = mode_information - - self.accept_btn = accept_btn - - self.connections() - self.update() - - # Force updated render mode help text - self._update_rendermode_info() - - def connections(self): - """Build connections between code and buttons""" - - self.update_btn.clicked.connect(self.update) - self.accept_btn.clicked.connect(self._set_comp_rendermode) - self.mode_options.currentIndexChanged.connect( - self._update_rendermode_info) - - def update(self): - """Update all information in the UI""" - - self._comp = get_current_comp() - self._comp_name = self._get_comp_name() - self.comp_information.setText(self._comp_name) - - # Update current comp settings - mode = self._get_comp_rendermode() - index = self.mode_options.findText(mode) - self.mode_options.setCurrentIndex(index) - - def _update_rendermode_info(self): - rendermode = self.mode_options.currentText() - self.mode_information.setText(_help[rendermode]) - - def _get_comp_name(self): - return self._comp.GetAttrs("COMPS_Name") - - def _get_comp_rendermode(self): - return self._comp.GetData("openpype.rendermode") or "local" - - def _set_comp_rendermode(self): - rendermode = self.mode_options.currentText() - self._comp.SetData("openpype.rendermode", rendermode) - - self._comp.Print("Updated render mode to '%s'\n" % rendermode) - self.hide() - - def _validation(self): - ui_mode = self.mode_options.currentText() - comp_mode = self._get_comp_rendermode() - - return comp_mode == ui_mode From 075ea125894262ad87597f46e78d3f54e8997d13 Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Mon, 13 Mar 2023 18:01:33 +0100 Subject: [PATCH 07/20] Remove reference to set_rendermode (forgot to delete it in last push) --- openpype/hosts/fusion/api/menu.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/fusion/api/menu.py b/openpype/hosts/fusion/api/menu.py index ba3ce6798d..92f38a64c2 100644 --- a/openpype/hosts/fusion/api/menu.py +++ b/openpype/hosts/fusion/api/menu.py @@ -6,7 +6,6 @@ from openpype.tools.utils import host_tools from openpype.style import load_stylesheet from openpype.lib import register_event_callback from openpype.hosts.fusion.scripts import ( - set_rendermode, duplicate_with_inputs, ) from openpype.hosts.fusion.api.lib import ( From 10ff798ed59e72f006f4aac8df09a8bb119c647b Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Tue, 14 Mar 2023 17:18:56 +0100 Subject: [PATCH 08/20] Fixed "Select invalid" --- .../validate_local_frames_existence.py | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/openpype/hosts/fusion/plugins/publish/validate_local_frames_existence.py b/openpype/hosts/fusion/plugins/publish/validate_local_frames_existence.py index d80e11e078..c1cba795e1 100644 --- a/openpype/hosts/fusion/plugins/publish/validate_local_frames_existence.py +++ b/openpype/hosts/fusion/plugins/publish/validate_local_frames_existence.py @@ -8,7 +8,9 @@ from openpype.hosts.fusion.api.action import SelectInvalidAction class ValidateLocalFramesExistence(pyblish.api.InstancePlugin): - """Checks if files for savers that's set to publish existing frames exists""" + """Checks if files for savers that's set + to publish existing frames exists + """ order = pyblish.api.ValidatorOrder label = "Validate Existing Frames Exists" @@ -17,7 +19,7 @@ class ValidateLocalFramesExistence(pyblish.api.InstancePlugin): actions = [RepairAction, SelectInvalidAction] @classmethod - def get_invalid(cls, instance): + def get_invalid(cls, instance, non_existing_frames=[]): active = instance.data.get("active", instance.data.get("publish")) if not active: return [] @@ -37,29 +39,27 @@ class ValidateLocalFramesExistence(pyblish.api.InstancePlugin): for frame in range(frame_start, frame_end + 1) ] - non_existing_frames = [] - for file in files: - cls.log.error(file) if not os.path.exists(os.path.join(output_dir, file)): + cls.log.error( + f"Missing file: {os.path.join(output_dir, file)}" + ) non_existing_frames.append(file) if len(non_existing_frames) > 0: - cls.log.error( - "Some of {}'s files does not exist".format(tool.Name) - ) - return [tool, output_dir, non_existing_frames] + cls.log.error(f"Some of {tool.Name}'s files does not exist") + return [tool] def process(self, instance): - invalid = self.get_invalid(instance) + non_existing_frames = [] + invalid = self.get_invalid(instance, non_existing_frames) if invalid: raise PublishValidationError( "{} is set to publish existing frames but " - "some frames are missing in the folder:\n\n{}" + "some frames are missing. " "The missing file(s) are:\n\n{}".format( invalid[0].Name, - invalid[1], - "\n\n".join(invalid[2]), + "\n\n".join(non_existing_frames), ), title=self.label, ) From 9741d47fbc7c03d20cbc775f61ae19e321bb631c Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Tue, 14 Mar 2023 17:19:19 +0100 Subject: [PATCH 09/20] Added crude repair functionality --- .../publish/validate_local_frames_existence.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/fusion/plugins/publish/validate_local_frames_existence.py b/openpype/hosts/fusion/plugins/publish/validate_local_frames_existence.py index c1cba795e1..4b50e0b837 100644 --- a/openpype/hosts/fusion/plugins/publish/validate_local_frames_existence.py +++ b/openpype/hosts/fusion/plugins/publish/validate_local_frames_existence.py @@ -67,5 +67,14 @@ class ValidateLocalFramesExistence(pyblish.api.InstancePlugin): @classmethod def repair(cls, instance): invalid = cls.get_invalid(instance) - for tool in invalid: - tool.SetInput("CreateDir", 1.0) + if invalid: + data = invalid[0].GetData("openpype") + + # Change render target to local to render locally + data["creator_attributes"]["render_target"] = "local" + + invalid[0].SetData("openpype", data) + cls.log.error( + f"Reload the publisher and {invalid[0].Name} " + "will be set to render locally" + ) From 1e9670f54dd9121527438c25649c53016fd4ea92 Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Tue, 14 Mar 2023 17:19:43 +0100 Subject: [PATCH 10/20] Fixed docstring and removed unused variables --- .../fusion/plugins/publish/collect_renders.py | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/openpype/hosts/fusion/plugins/publish/collect_renders.py b/openpype/hosts/fusion/plugins/publish/collect_renders.py index cdd37b3b65..be405d2495 100644 --- a/openpype/hosts/fusion/plugins/publish/collect_renders.py +++ b/openpype/hosts/fusion/plugins/publish/collect_renders.py @@ -3,21 +3,11 @@ from pprint import pformat class CollectFusionRenders(pyblish.api.InstancePlugin): - """Collect current comp's render Mode + """Collect current saver node's render Mode Options: - local - farm - - Note that this value is set for each comp separately. When you save the - comp this information will be stored in that file. If for some reason the - available tool does not visualize which render mode is set for the - current comp, please run the following line in the console (Py2) - - comp.GetData("openpype.rendermode") - - This will return the name of the current render mode as seen above under - Options. + local (Render locally) + frames (Use existing frames) """ @@ -29,10 +19,8 @@ class CollectFusionRenders(pyblish.api.InstancePlugin): def process(self, instance): self.log.debug(pformat(instance.data)) - saver_node = instance.data["transientData"]["tool"] render_target = instance.data["render_target"] family = instance.data["family"] - families = instance.data["families"] # add targeted family to families instance.data["families"].append( From 191882424047cb517f0fc97171819dcca6d84093 Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Tue, 14 Mar 2023 17:56:11 +0100 Subject: [PATCH 11/20] Moved the review representation back to render_local.py --- .../plugins/publish/extract_render_local.py | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/openpype/hosts/fusion/plugins/publish/extract_render_local.py b/openpype/hosts/fusion/plugins/publish/extract_render_local.py index 62625c899a..ea801107c1 100644 --- a/openpype/hosts/fusion/plugins/publish/extract_render_local.py +++ b/openpype/hosts/fusion/plugins/publish/extract_render_local.py @@ -29,6 +29,41 @@ class FusionRenderLocal( ) ) + # Generate the frame list + frame_start = context.data["frameStartHandle"] + frame_end = context.data["frameEndHandle"] + path = instance.data["path"] + output_dir = instance.data["outputDir"] + + basename = os.path.basename(path) + head, ext = os.path.splitext(basename) + files = [ + f"{head}{str(frame).zfill(4)}{ext}" + for frame in range(frame_start, frame_end + 1) + ] + repre = { + "name": ext[1:], + "ext": ext[1:], + "frameStart": f"%0{len(str(frame_end))}d" % frame_start, + "files": files, + "stagingDir": output_dir, + } + + # Get the colorspace represenation + self.set_representation_colorspace( + representation=repre, + context=context, + ) + + # review representation + if instance.data.get("review", False): + repre["tags"] = ["review"] + + # add the repre to the instance + if "representations" not in instance.data: + instance.data["representations"] = [] + instance.data["representations"].append(repre) + def render_once(self, context): """Render context comp only once, even with more render instances""" From c7ae8b53201b5a0f223aec38cc2244b305581607 Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Tue, 14 Mar 2023 17:57:45 +0100 Subject: [PATCH 12/20] Collect all frames for "using existing frames" savers --- ...iew_data.py => collect_existing_frames.py} | 20 ++++++------------- ... => validate_existing_frames_existence.py} | 0 2 files changed, 6 insertions(+), 14 deletions(-) rename openpype/hosts/fusion/plugins/publish/{extract_review_data.py => collect_existing_frames.py} (74%) rename openpype/hosts/fusion/plugins/publish/{validate_local_frames_existence.py => validate_existing_frames_existence.py} (100%) diff --git a/openpype/hosts/fusion/plugins/publish/extract_review_data.py b/openpype/hosts/fusion/plugins/publish/collect_existing_frames.py similarity index 74% rename from openpype/hosts/fusion/plugins/publish/extract_review_data.py rename to openpype/hosts/fusion/plugins/publish/collect_existing_frames.py index d9416771f6..7c5f7cd55d 100644 --- a/openpype/hosts/fusion/plugins/publish/extract_review_data.py +++ b/openpype/hosts/fusion/plugins/publish/collect_existing_frames.py @@ -1,22 +1,14 @@ -import os import pyblish.api -from openpype.pipeline.publish import ( - ColormanagedPyblishPluginMixin, -) +import os -class FusionExtractReviewData( - pyblish.api.InstancePlugin, ColormanagedPyblishPluginMixin -): - """ - Extract the result of savers by starting a comp render - This will run the local render of Fusion. - """ +class CollectFusionRenders(pyblish.api.InstancePlugin): + """Collect all frames needed to publish existing frames""" - order = pyblish.api.ExtractorOrder - 0.1 - label = "Extract Review Data" + order = pyblish.api.CollectorOrder + 0.5 + label = "Collect Existing Frames" hosts = ["fusion"] - families = ["review"] + families = ["render.frames"] def process(self, instance): context = instance.context diff --git a/openpype/hosts/fusion/plugins/publish/validate_local_frames_existence.py b/openpype/hosts/fusion/plugins/publish/validate_existing_frames_existence.py similarity index 100% rename from openpype/hosts/fusion/plugins/publish/validate_local_frames_existence.py rename to openpype/hosts/fusion/plugins/publish/validate_existing_frames_existence.py From 1754ef32672256b1661669d510c1c83e6fa5f403 Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Tue, 14 Mar 2023 18:06:37 +0100 Subject: [PATCH 13/20] Fixed mutable data structure problem --- .../plugins/publish/validate_existing_frames_existence.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/fusion/plugins/publish/validate_existing_frames_existence.py b/openpype/hosts/fusion/plugins/publish/validate_existing_frames_existence.py index 4b50e0b837..a43d2c691a 100644 --- a/openpype/hosts/fusion/plugins/publish/validate_existing_frames_existence.py +++ b/openpype/hosts/fusion/plugins/publish/validate_existing_frames_existence.py @@ -19,7 +19,10 @@ class ValidateLocalFramesExistence(pyblish.api.InstancePlugin): actions = [RepairAction, SelectInvalidAction] @classmethod - def get_invalid(cls, instance, non_existing_frames=[]): + def get_invalid(cls, instance, non_existing_frames=None): + if non_existing_frames is None: + non_existing_frames = [] + active = instance.data.get("active", instance.data.get("publish")) if not active: return [] From 1dec179dc766d341a56b37baf3e07f6d092aca98 Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Sat, 18 Mar 2023 19:29:20 +0100 Subject: [PATCH 14/20] Changed the name from existing to expected frames --- ...ollect_existing_frames.py => collect_expected_frames.py} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename openpype/hosts/fusion/plugins/publish/{collect_existing_frames.py => collect_expected_frames.py} (88%) diff --git a/openpype/hosts/fusion/plugins/publish/collect_existing_frames.py b/openpype/hosts/fusion/plugins/publish/collect_expected_frames.py similarity index 88% rename from openpype/hosts/fusion/plugins/publish/collect_existing_frames.py rename to openpype/hosts/fusion/plugins/publish/collect_expected_frames.py index 7c5f7cd55d..485ca0c9a4 100644 --- a/openpype/hosts/fusion/plugins/publish/collect_existing_frames.py +++ b/openpype/hosts/fusion/plugins/publish/collect_expected_frames.py @@ -2,11 +2,11 @@ import pyblish.api import os -class CollectFusionRenders(pyblish.api.InstancePlugin): - """Collect all frames needed to publish existing frames""" +class CollectFusionExpectedFrames(pyblish.api.InstancePlugin): + """Collect all frames needed to publish expected frames""" order = pyblish.api.CollectorOrder + 0.5 - label = "Collect Existing Frames" + label = "Collect Expected Frames" hosts = ["fusion"] families = ["render.frames"] From aad3325e046de74696ba93bd8b2d592b423a3d8b Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Sat, 18 Mar 2023 19:29:32 +0100 Subject: [PATCH 15/20] Cleaned up code --- openpype/hosts/fusion/plugins/publish/collect_renders.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/openpype/hosts/fusion/plugins/publish/collect_renders.py b/openpype/hosts/fusion/plugins/publish/collect_renders.py index be405d2495..7f38e68447 100644 --- a/openpype/hosts/fusion/plugins/publish/collect_renders.py +++ b/openpype/hosts/fusion/plugins/publish/collect_renders.py @@ -1,5 +1,4 @@ import pyblish.api -from pprint import pformat class CollectFusionRenders(pyblish.api.InstancePlugin): @@ -17,8 +16,6 @@ class CollectFusionRenders(pyblish.api.InstancePlugin): families = ["render"] def process(self, instance): - self.log.debug(pformat(instance.data)) - render_target = instance.data["render_target"] family = instance.data["family"] @@ -26,5 +23,3 @@ class CollectFusionRenders(pyblish.api.InstancePlugin): instance.data["families"].append( "{}.{}".format(family, render_target) ) - - self.log.debug(pformat(instance.data)) From f2e782368fe5a135c1d01f4ee6a85fe8840e0f94 Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Sat, 18 Mar 2023 19:30:13 +0100 Subject: [PATCH 16/20] Changed to dot notation for clearer code --- ...nce.py => validate_expected_frames_existence.py} | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) rename openpype/hosts/fusion/plugins/publish/{validate_existing_frames_existence.py => validate_expected_frames_existence.py} (87%) diff --git a/openpype/hosts/fusion/plugins/publish/validate_existing_frames_existence.py b/openpype/hosts/fusion/plugins/publish/validate_expected_frames_existence.py similarity index 87% rename from openpype/hosts/fusion/plugins/publish/validate_existing_frames_existence.py rename to openpype/hosts/fusion/plugins/publish/validate_expected_frames_existence.py index a43d2c691a..e74eb82366 100644 --- a/openpype/hosts/fusion/plugins/publish/validate_existing_frames_existence.py +++ b/openpype/hosts/fusion/plugins/publish/validate_expected_frames_existence.py @@ -9,11 +9,11 @@ from openpype.hosts.fusion.api.action import SelectInvalidAction class ValidateLocalFramesExistence(pyblish.api.InstancePlugin): """Checks if files for savers that's set - to publish existing frames exists + to publish expected frames exists """ order = pyblish.api.ValidatorOrder - label = "Validate Existing Frames Exists" + label = "Validate Expected Frames Exists" families = ["render"] hosts = ["fusion"] actions = [RepairAction, SelectInvalidAction] @@ -71,13 +71,12 @@ class ValidateLocalFramesExistence(pyblish.api.InstancePlugin): def repair(cls, instance): invalid = cls.get_invalid(instance) if invalid: - data = invalid[0].GetData("openpype") + tool = invalid[0] # Change render target to local to render locally - data["creator_attributes"]["render_target"] = "local" + tool.SetData("openpype.creator_attributes.render_target", "local") - invalid[0].SetData("openpype", data) - cls.log.error( - f"Reload the publisher and {invalid[0].Name} " + cls.log.info( + f"Reload the publisher and {tool.Name} " "will be set to render locally" ) From 0401f40ac941b0fba6f31c954aeb98da380d6301 Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Sat, 18 Mar 2023 19:50:11 +0100 Subject: [PATCH 17/20] Collect frames in expected_frames instead of in redner_local --- .../publish/collect_expected_frames.py | 7 +++- .../plugins/publish/extract_render_local.py | 39 +------------------ 2 files changed, 6 insertions(+), 40 deletions(-) diff --git a/openpype/hosts/fusion/plugins/publish/collect_expected_frames.py b/openpype/hosts/fusion/plugins/publish/collect_expected_frames.py index 485ca0c9a4..0ba777629f 100644 --- a/openpype/hosts/fusion/plugins/publish/collect_expected_frames.py +++ b/openpype/hosts/fusion/plugins/publish/collect_expected_frames.py @@ -1,14 +1,17 @@ import pyblish.api +from openpype.pipeline import publish import os -class CollectFusionExpectedFrames(pyblish.api.InstancePlugin): +class CollectFusionExpectedFrames( + pyblish.api.InstancePlugin, publish.ColormanagedPyblishPluginMixin +): """Collect all frames needed to publish expected frames""" order = pyblish.api.CollectorOrder + 0.5 label = "Collect Expected Frames" hosts = ["fusion"] - families = ["render.frames"] + families = ["render"] def process(self, instance): context = instance.context diff --git a/openpype/hosts/fusion/plugins/publish/extract_render_local.py b/openpype/hosts/fusion/plugins/publish/extract_render_local.py index ea801107c1..673c5a3ce3 100644 --- a/openpype/hosts/fusion/plugins/publish/extract_render_local.py +++ b/openpype/hosts/fusion/plugins/publish/extract_render_local.py @@ -4,9 +4,7 @@ from openpype.pipeline import publish from openpype.hosts.fusion.api import comp_lock_and_undo_chunk -class FusionRenderLocal( - pyblish.api.InstancePlugin, publish.ColormanagedPyblishPluginMixin -): +class FusionRenderLocal(pyblish.api.InstancePlugin): """Render the current Fusion composition locally.""" order = pyblish.api.ExtractorOrder - 0.2 @@ -29,41 +27,6 @@ class FusionRenderLocal( ) ) - # Generate the frame list - frame_start = context.data["frameStartHandle"] - frame_end = context.data["frameEndHandle"] - path = instance.data["path"] - output_dir = instance.data["outputDir"] - - basename = os.path.basename(path) - head, ext = os.path.splitext(basename) - files = [ - f"{head}{str(frame).zfill(4)}{ext}" - for frame in range(frame_start, frame_end + 1) - ] - repre = { - "name": ext[1:], - "ext": ext[1:], - "frameStart": f"%0{len(str(frame_end))}d" % frame_start, - "files": files, - "stagingDir": output_dir, - } - - # Get the colorspace represenation - self.set_representation_colorspace( - representation=repre, - context=context, - ) - - # review representation - if instance.data.get("review", False): - repre["tags"] = ["review"] - - # add the repre to the instance - if "representations" not in instance.data: - instance.data["representations"] = [] - instance.data["representations"].append(repre) - def render_once(self, context): """Render context comp only once, even with more render instances""" From 519cd3050888478202e7e2328fb3894ca5a7ab0a Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Sat, 18 Mar 2023 19:50:49 +0100 Subject: [PATCH 18/20] Removed code that should never be able to happen --- .../fusion/plugins/publish/validate_create_folder_checked.py | 4 ---- .../plugins/publish/validate_expected_frames_existence.py | 4 ---- 2 files changed, 8 deletions(-) diff --git a/openpype/hosts/fusion/plugins/publish/validate_create_folder_checked.py b/openpype/hosts/fusion/plugins/publish/validate_create_folder_checked.py index 53dea2af71..8a91f23578 100644 --- a/openpype/hosts/fusion/plugins/publish/validate_create_folder_checked.py +++ b/openpype/hosts/fusion/plugins/publish/validate_create_folder_checked.py @@ -21,10 +21,6 @@ class ValidateCreateFolderChecked(pyblish.api.InstancePlugin): @classmethod def get_invalid(cls, instance): - active = instance.data.get("active", instance.data.get("publish")) - if not active: - return [] - tool = instance[0] create_dir = tool.GetInput("CreateDir") if create_dir == 0.0: diff --git a/openpype/hosts/fusion/plugins/publish/validate_expected_frames_existence.py b/openpype/hosts/fusion/plugins/publish/validate_expected_frames_existence.py index e74eb82366..c208b8ef15 100644 --- a/openpype/hosts/fusion/plugins/publish/validate_expected_frames_existence.py +++ b/openpype/hosts/fusion/plugins/publish/validate_expected_frames_existence.py @@ -23,10 +23,6 @@ class ValidateLocalFramesExistence(pyblish.api.InstancePlugin): if non_existing_frames is None: non_existing_frames = [] - active = instance.data.get("active", instance.data.get("publish")) - if not active: - return [] - if instance.data.get("render_target") == "frames": tool = instance[0] From 6e13275054fc3aaedb3f5d487ef45330aee615b9 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 21 Mar 2023 16:29:46 +0100 Subject: [PATCH 19/20] Cleanup unused imports --- openpype/hosts/fusion/plugins/publish/extract_render_local.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/hosts/fusion/plugins/publish/extract_render_local.py b/openpype/hosts/fusion/plugins/publish/extract_render_local.py index 673c5a3ce3..16a582032f 100644 --- a/openpype/hosts/fusion/plugins/publish/extract_render_local.py +++ b/openpype/hosts/fusion/plugins/publish/extract_render_local.py @@ -1,6 +1,4 @@ -import os import pyblish.api -from openpype.pipeline import publish from openpype.hosts.fusion.api import comp_lock_and_undo_chunk From 6433b1f270420f84a8742467dc34a51b71996e92 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 21 Mar 2023 16:52:13 +0100 Subject: [PATCH 20/20] Render only the local saver tools instead of all active savers in the comp --- .../plugins/publish/extract_render_local.py | 63 ++++++++++++++++--- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/openpype/hosts/fusion/plugins/publish/extract_render_local.py b/openpype/hosts/fusion/plugins/publish/extract_render_local.py index 16a582032f..5a0140c525 100644 --- a/openpype/hosts/fusion/plugins/publish/extract_render_local.py +++ b/openpype/hosts/fusion/plugins/publish/extract_render_local.py @@ -1,7 +1,43 @@ +import logging +import contextlib import pyblish.api from openpype.hosts.fusion.api import comp_lock_and_undo_chunk +log = logging.getLogger(__name__) + + +@contextlib.contextmanager +def enabled_savers(comp, savers): + """Enable only the `savers` in Comp during the context. + + Any Saver tool in the passed composition that is not in the savers list + will be set to passthrough during the context. + + Args: + comp (object): Fusion composition object. + savers (list): List of Saver tool objects. + + """ + passthrough_key = "TOOLB_PassThrough" + original_states = {} + enabled_save_names = {saver.Name for saver in savers} + try: + all_savers = comp.GetToolList(False, "Saver").values() + for saver in all_savers: + original_state = saver.GetAttrs()[passthrough_key] + original_states[saver] = original_state + + # The passthrough state we want to set (passthrough != enabled) + state = saver.Name not in enabled_save_names + if state != original_state: + saver.SetAttrs({passthrough_key: state}) + yield + finally: + for saver, original_state in original_states.items(): + saver.SetAttrs({"TOOLB_PassThrough": original_state}) + + class FusionRenderLocal(pyblish.api.InstancePlugin): """Render the current Fusion composition locally.""" @@ -32,6 +68,16 @@ class FusionRenderLocal(pyblish.api.InstancePlugin): # to speed up the rendering. The check below makes sure that we only # execute the rendering once and not for each instance. key = f"__hasRun{self.__class__.__name__}" + + savers_to_render = [ + # Get the saver tool from the instance + instance[0] for instance in context if + # Only active instances + instance.data.get("publish", True) and + # Only render.local instances + "render.local" in instance.data["families"] + ] + if key not in context.data: # We initialize as false to indicate it wasn't successful yet # so we can keep track of whether Fusion succeeded @@ -44,15 +90,18 @@ class FusionRenderLocal(pyblish.api.InstancePlugin): self.log.info("Starting Fusion render") self.log.info(f"Start frame: {frame_start}") self.log.info(f"End frame: {frame_end}") + saver_names = ", ".join(saver.Name for saver in savers_to_render) + self.log.info(f"Rendering tools: {saver_names}") with comp_lock_and_undo_chunk(current_comp): - result = current_comp.Render( - { - "Start": frame_start, - "End": frame_end, - "Wait": True, - } - ) + with enabled_savers(current_comp, savers_to_render): + result = current_comp.Render( + { + "Start": frame_start, + "End": frame_end, + "Wait": True, + } + ) context.data[key] = bool(result)