diff --git a/openpype/hosts/fusion/plugins/create/create_exr_saver.py b/openpype/hosts/fusion/plugins/create/create_exr_saver.py index 4809832cd0..c2adb48bac 100644 --- a/openpype/hosts/fusion/plugins/create/create_exr_saver.py +++ b/openpype/hosts/fusion/plugins/create/create_exr_saver.py @@ -1,5 +1,7 @@ import os +import qtawesome + from openpype.hosts.fusion.api import ( get_current_comp, comp_lock_and_undo_chunk, @@ -19,7 +21,9 @@ class CreateOpenEXRSaver(Creator): name = "openexrDefault" label = "Create OpenEXR Saver" family = "render" - default_variants = ["Main"] + default_variants = ["Main"] + + description = "Fusion Saver to generate EXR image sequence" selected_nodes = [] @@ -27,6 +31,10 @@ class CreateOpenEXRSaver(Creator): file_format = "OpenEXRFormat" + print(subset_name) + print(instance_data) + print(pre_create_data) + comp = get_current_comp() workdir = os.path.normpath(legacy_io.Session["AVALON_WORKDIR"]) @@ -53,17 +61,79 @@ class CreateOpenEXRSaver(Creator): saver[file_format]["Depth"] = 1 # int8 | int16 | float32 | other saver[file_format]["SaveAlpha"] = 0 + # Save all data in a "openpype.{key}" = value data + for key, value in instance_data.items(): + saver.SetData("openpype.{}".format(key), value) + def collect_instances(self): - for instance in list_instances(creator_id=self.identifier): + + comp = get_current_comp() + tools = comp.GetToolList(False, "Saver").values() + + # Allow regular non-managed savers to also be picked up + project = legacy_io.Session["AVALON_PROJECT"] + asset = legacy_io.Session["AVALON_ASSET"] + task = legacy_io.Session["AVALON_TASK"] + + for tool in tools: + + path = tool["Clip"][comp.TIME_UNDEFINED] + fname = os.path.basename(path) + fname, _ext = os.path.splitext(fname) + subset = fname.rstrip(".") + + attrs = tool.GetAttrs() + passthrough = attrs["TOOLB_PassThrough"] + variant = subset[len("render"):] + + # 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 + # unless the instance data is stored on it to begin with + instance = { + # Required data + "project": project, + "asset": asset, + "subset": subset, + "task": task, + "variant": variant, + "active": not passthrough, + "family": self.family, + + # Fusion data + "tool_name": tool.Name + } + + # Use the explicit data on the saver (if any) + data = tool.GetData("openpype") + if data: + instance.update(data) + + # Add instance created_instance = CreatedInstance.from_existing(instance, self) + + # TODO: move this to lifetime data or alike + # (Doing this before CreatedInstance.from_existing wouldn't + # work because `tool` isn't JSON serializable) + created_instance["tool"] = tool + self._add_instance_to_context(created_instance) + def get_icon(self): + return qtawesome.icon("fa.eye", color="white") + def update_instances(self, update_list): + # TODO: Not sure what to do here? print(update_list) def remove_instances(self, instances): for instance in instances: + + # Remove the tool from the scene remove_instance(instance) + # Remove the collected CreatedInstance to remove from UI directly + self._remove_instance_from_context(instance) + def get_pre_create_attr_defs(self): return [] diff --git a/openpype/hosts/fusion/plugins/publish/collect_instances.py b/openpype/hosts/fusion/plugins/publish/collect_instances.py index fe60b83827..e42e7b5f70 100644 --- a/openpype/hosts/fusion/plugins/publish/collect_instances.py +++ b/openpype/hosts/fusion/plugins/publish/collect_instances.py @@ -30,7 +30,7 @@ class CollectInstances(pyblish.api.ContextPlugin): """ order = pyblish.api.CollectorOrder - label = "Collect Instances" + label = "Collect Instances Data" hosts = ["fusion"] def process(self, context): @@ -39,67 +39,47 @@ class CollectInstances(pyblish.api.ContextPlugin): from openpype.hosts.fusion.api.lib import get_frame_path comp = context.data["currentComp"] - - # Get all savers in the comp - tools = comp.GetToolList(False).values() - savers = [tool for tool in tools if tool.ID == "Saver"] - start, end, global_start, global_end = get_comp_render_range(comp) context.data["frameStart"] = int(start) context.data["frameEnd"] = int(end) context.data["frameStartHandle"] = int(global_start) context.data["frameEndHandle"] = int(global_end) - for tool in savers: + # Comp tools by name + tools = {tool.Name: tool for tool in comp.GetToolList(False).values()} + + for instance in context: + + tool_name = instance.data["tool_name"] + tool = tools[tool_name] + path = tool["Clip"][comp.TIME_UNDEFINED] - - tool_attrs = tool.GetAttrs() - active = not tool_attrs["TOOLB_PassThrough"] - - if not path: - self.log.warning("Skipping saver because it " - "has no path set: {}".format(tool.Name)) - continue - filename = os.path.basename(path) head, padding, tail = get_frame_path(filename) ext = os.path.splitext(path)[1] assert tail == ext, ("Tail does not match %s" % ext) - subset = head.rstrip("_. ") # subset is head of the filename # Include start and end render frame in label + subset = instance.data["subset"] label = "{subset} ({start}-{end})".format(subset=subset, start=int(start), end=int(end)) - - instance = context.create_instance(subset) instance.data.update({ - "asset": os.environ["AVALON_ASSET"], # todo: not a constant - "subset": subset, "path": path, "outputDir": os.path.dirname(path), - "ext": ext, # todo: should be redundant + "ext": ext, # todo: should be redundant? "label": label, + # todo: Allow custom frame range per instance "frameStart": context.data["frameStart"], "frameEnd": context.data["frameEnd"], "frameStartHandle": context.data["frameStartHandle"], "frameEndHandle": context.data["frameStartHandle"], "fps": context.data["fps"], "families": ["render", "review"], - "family": "render", - "active": active, - "publish": active # backwards compatibility + "family": "render" }) + # Add tool itself as member instance.append(tool) self.log.info("Found: \"%s\" " % path) - - # Sort/grouped by family (preserving local index) - context[:] = sorted(context, key=self.sort_by_family) - - return context - - def sort_by_family(self, instance): - """Sort by family""" - return instance.data.get("families", instance.data.get("family"))