This node is maintained by OpenPype Publisher.
+To remove it use Publisher gui.
+ + """) + node.addKnob(info_knob) + + def check_existing_subset(self, subset_name, instance_data): + """Check if existing subset name already exists.""" + exists = False + for node in nuke.allNodes(recurseGroups=True): + node_data = get_node_data(node, INSTANCE_DATA_KNOB) + if subset_name in node_data.get("subset"): + exists = True + + return exists + + def create_instance_node( + self, + node_name, + knobs=None, + parent=None, + node_type=None + ): + """Create node representing instance. + + Arguments: + node_name (str): Name of the new node. + knobs (OrderedDict): node knobs name and values + parent (str): Name of the parent node. + node_type (str, optional): Nuke node Class. + + Returns: + nuke.Node: Newly created instance node. + + """ + node_type = node_type or "NoOp" + + node_knobs = knobs or {} + + # set parent node + parent_node = nuke.root() + if parent: + parent_node = nuke.toNode(parent) + + try: + with parent_node: + created_node = nuke.createNode(node_type) + created_node["name"].setValue(node_name) + + self.add_info_knob(created_node) + + for key, values in node_knobs.items(): + if key in created_node.knobs(): + created_node["key"].setValue(values) + except Exception as _err: + raise NukeCreatorError("Creating have failed: {}".format(_err)) + + return created_node + + def set_selected_nodes(self, pre_create_data): + if pre_create_data.get("use_selection"): + self.selected_nodes = nuke.selectedNodes() + if self.selected_nodes == []: + raise NukeCreatorError("Creator error: No active selection") + else: + self.selected_nodes = [] + + def create(self, subset_name, instance_data, pre_create_data): + + # make sure selected nodes are added + self.set_selected_nodes(pre_create_data) + + # make sure subset name is unique + if self.check_existing_subset(subset_name, instance_data): + raise NukeCreatorError( + ("subset {} is already published" + "definition.").format(subset_name)) + + try: + instance_node = self.create_instance_node( + subset_name, + node_type=instance_data.pop("node_type", None) + ) + instance = CreatedInstance( + self.family, + subset_name, + instance_data, + self + ) + + instance.transient_data["node"] = instance_node + + self._add_instance_to_context(instance) + + set_node_data( + instance_node, INSTANCE_DATA_KNOB, instance.data_to_store()) + + return instance + + except Exception as er: + six.reraise( + NukeCreatorError, + NukeCreatorError("Creator error: {}".format(er)), + sys.exc_info()[2]) + + def collect_instances(self): + cached_instances = _collect_and_cache_nodes(self) + for (node, data) in cached_instances[self.identifier]: + created_instance = CreatedInstance.from_existing( + data, self + ) + created_instance.transient_data["node"] = node + self._add_instance_to_context(created_instance) + + def update_instances(self, update_list): + for created_inst, _changes in update_list: + instance_node = created_inst.transient_data["node"] + + # in case node is not existing anymore (user erased it manually) + try: + instance_node.fullName() + except ValueError: + self.remove_instances([created_inst]) + continue + + set_node_data( + instance_node, + INSTANCE_DATA_KNOB, + created_inst.data_to_store() + ) + + def remove_instances(self, instances): + for instance in instances: + remove_instance(instance) + self._remove_instance_from_context(instance) + + def get_pre_create_attr_defs(self): + return [ + BoolDef("use_selection", label="Use selection") + ] + + def get_creator_settings(self, project_settings, settings_key=None): + if not settings_key: + settings_key = self.__class__.__name__ + return project_settings["nuke"]["create"][settings_key] + + +class NukeWriteCreator(NukeCreator): + """Add Publishable Write node""" + + identifier = "create_write" + label = "Create Write" + family = "write" + icon = "sign-out" + + def integrate_links(self, node, outputs=True): + # skip if no selection + if not self.selected_node: + return + + # collect dependencies + input_nodes = [self.selected_node] + dependent_nodes = self.selected_node.dependent() if outputs else [] + + # relinking to collected connections + for i, input in enumerate(input_nodes): + node.setInput(i, input) + + # make it nicer in graph + node.autoplace() + + # relink also dependent nodes + for dep_nodes in dependent_nodes: + dep_nodes.setInput(0, node) + + def set_selected_nodes(self, pre_create_data): + if pre_create_data.get("use_selection"): + selected_nodes = nuke.selectedNodes() + if selected_nodes == []: + raise NukeCreatorError("Creator error: No active selection") + elif len(selected_nodes) > 1: + NukeCreatorError("Creator error: Select only one camera node") + self.selected_node = selected_nodes[0] + else: + self.selected_node = None + + def get_pre_create_attr_defs(self): + attr_defs = [ + BoolDef("use_selection", label="Use selection"), + self._get_render_target_enum() + ] + return attr_defs + + def get_instance_attr_defs(self): + attr_defs = [ + self._get_render_target_enum(), + self._get_reviewable_bool() + ] + return attr_defs + + 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" + ) + + def create(self, subset_name, instance_data, pre_create_data): + # make sure selected nodes are added + self.set_selected_nodes(pre_create_data) + + # make sure subset name is unique + if self.check_existing_subset(subset_name, instance_data): + raise NukeCreatorError( + ("subset {} is already published" + "definition.").format(subset_name)) + + instance_node = self.create_instance_node( + subset_name, + instance_data + ) + + try: + instance = CreatedInstance( + self.family, + subset_name, + instance_data, + self + ) + + instance.transient_data["node"] = instance_node + + self._add_instance_to_context(instance) + + set_node_data( + instance_node, INSTANCE_DATA_KNOB, instance.data_to_store()) + + return instance + + except Exception as er: + six.reraise( + NukeCreatorError, + NukeCreatorError("Creator error: {}".format(er)), + sys.exc_info()[2] + ) + + def apply_settings( + self, + project_settings, + system_settings + ): + """Method called on initialization of plugin to apply settings.""" + + # plugin settings + plugin_settings = self.get_creator_settings(project_settings) + + # individual attributes + self.instance_attributes = plugin_settings.get( + "instance_attributes") or self.instance_attributes + self.prenodes = plugin_settings["prenodes"] + self.default_variants = plugin_settings.get( + "default_variants") or self.default_variants + self.temp_rendering_path_template = ( + plugin_settings.get("temp_rendering_path_template") + or self.temp_rendering_path_template + ) class OpenPypeCreator(LegacyCreator): @@ -72,6 +418,41 @@ def process(self): return instance +def get_instance_group_node_childs(instance): + """Return list of instance group node children + + Args: + instance (pyblish.Instance): pyblish instance + + Returns: + list: [nuke.Node] + """ + node = instance.data["transientData"]["node"] + + if node.Class() != "Group": + return + + # collect child nodes + child_nodes = [] + # iterate all nodes + for node in nuke.allNodes(group=node): + # add contained nodes to instance's node list + child_nodes.append(node) + + return child_nodes + + +def get_colorspace_from_node(node): + # Add version data to instance + colorspace = node["colorspace"].value() + + # remove default part of the string + if "default (" in colorspace: + colorspace = re.sub(r"default.\(|\)", "", colorspace) + + return colorspace + + def get_review_presets_config(): settings = get_current_project_settings() review_profiles = ( @@ -173,7 +554,6 @@ def __init__(self, def get_file_info(self): if self.collection: - self.log.debug("Collection: `{}`".format(self.collection)) # get path self.fname = os.path.basename(self.collection.format( "{head}{padding}{tail}")) @@ -308,7 +688,6 @@ def generate_lut(self, **kwargs): # connect self._temp_nodes.append(cms_node) self.previous_node = cms_node - self.log.debug("CMSTestPattern... `{}`".format(self._temp_nodes)) if bake_viewer_process: # Node View Process @@ -341,8 +720,6 @@ def generate_lut(self, **kwargs): # connect gen_lut_node.setInput(0, self.previous_node) self._temp_nodes.append(gen_lut_node) - self.log.debug("GenerateLUT... `{}`".format(self._temp_nodes)) - # ---------- end nodes creation # Export lut file @@ -356,8 +733,6 @@ def generate_lut(self, **kwargs): # ---------- generate representation data self.get_representation_data() - self.log.debug("Representation... `{}`".format(self.data)) - # ---------- Clean up self.clean_nodes() @@ -583,6 +958,7 @@ def generate_mov(self, farm=False, **kwargs): return self.data +@deprecated("openpype.hosts.nuke.api.plugin.NukeWriteCreator") class AbstractWriteRender(OpenPypeCreator): """Abstract creator to gather similar implementation for Write creators""" name = "" @@ -609,7 +985,6 @@ def __init__(self, *args, **kwargs): self.data = data self.nodes = nuke.selectedNodes() - self.log.debug("_ self.data: '{}'".format(self.data)) def process(self): @@ -734,3 +1109,149 @@ def _modify_write_node(self, write_node): node (nuke.Node): group node with data as Knobs """ pass + + +def convert_to_valid_instaces(): + """ Check and convert to latest publisher instances + + Also save as new minor version of workfile. + """ + def family_to_identifier(family): + mapping = { + "render": "create_write_render", + "prerender": "create_write_prerender", + "still": "create_write_image", + "model": "create_model", + "camera": "create_camera", + "nukenodes": "create_backdrop", + "gizmo": "create_gizmo", + "source": "create_source" + + } + return mapping[family] + + from openpype.hosts.nuke.api import workio + + task_name = legacy_io.Session["AVALON_TASK"] + + # save into new workfile + current_file = workio.current_file() + + # add file suffex if not + if "_publisherConvert" not in current_file: + new_workfile = ( + current_file[:-3] + + "_publisherConvert" + + current_file[-3:] + ) + else: + new_workfile = current_file + + path = new_workfile.replace("\\", "/") + nuke.scriptSaveAs(new_workfile, overwrite=1) + nuke.Root()["name"].setValue(path) + nuke.Root()["project_directory"].setValue(os.path.dirname(path)) + nuke.Root().setModified(False) + + _remove_old_knobs(nuke.Root()) + + # loop all nodes and convert + for node in nuke.allNodes(recurseGroups=True): + transfer_data = { + "creator_attributes": {} + } + creator_attr = transfer_data["creator_attributes"] + + if node.Class() in ["Viewer", "Dot"]: + continue + + if get_node_data(node, INSTANCE_DATA_KNOB): + continue + + # get data from avalon knob + avalon_knob_data = get_avalon_knob_data( + node, ["avalon:", "ak:"]) + + if not avalon_knob_data: + continue + + if avalon_knob_data["id"] != "pyblish.avalon.instance": + continue + + transfer_data.update({ + k: v for k, v in avalon_knob_data.items() + if k not in ["families", "creator"] + }) + + transfer_data["task"] = task_name + + family = avalon_knob_data["family"] + # establish families + families_ak = avalon_knob_data.get("families", []) + + if "suspend_publish" in node.knobs(): + creator_attr["suspended_publish"] = ( + node["suspend_publish"].value()) + + # get review knob value + if "review" in node.knobs(): + creator_attr["review"] = ( + node["review"].value()) + + if "publish" in node.knobs(): + transfer_data["active"] = ( + node["publish"].value()) + + # add idetifier + transfer_data["creator_identifier"] = family_to_identifier(family) + + # Add all nodes in group instances. + if node.Class() == "Group": + # only alter families for render family + if families_ak and "write" in families_ak.lower(): + target = node["render"].value() + if target == "Use existing frames": + creator_attr["render_target"] = "frames" + elif target == "Local": + # Local rendering + creator_attr["render_target"] = "local" + elif target == "On farm": + # Farm rendering + creator_attr["render_target"] = "farm" + + if "deadlinePriority" in node.knobs(): + transfer_data["farm_priority"] = ( + node["deadlinePriority"].value()) + if "deadlineChunkSize" in node.knobs(): + creator_attr["farm_chunk"] = ( + node["deadlineChunkSize"].value()) + if "deadlineConcurrentTasks" in node.knobs(): + creator_attr["farm_concurency"] = ( + node["deadlineConcurrentTasks"].value()) + + _remove_old_knobs(node) + + # add new instance knob with transfer data + set_node_data( + node, INSTANCE_DATA_KNOB, transfer_data) + + nuke.scriptSave() + + +def _remove_old_knobs(node): + remove_knobs = [ + "review", "publish", "render", "suspend_publish", "warn", "divd", + "OpenpypeDataGroup", "OpenpypeDataGroup_End", "deadlinePriority", + "deadlineChunkSize", "deadlineConcurrentTasks", "Deadline" + ] + print(node.name()) + + # remove all old knobs + for knob in node.allKnobs(): + try: + if knob.name() in remove_knobs: + node.removeKnob(knob) + elif "avalon" in knob.name(): + node.removeKnob(knob) + except ValueError: + pass diff --git a/openpype/hosts/nuke/plugins/create/convert_legacy.py b/openpype/hosts/nuke/plugins/create/convert_legacy.py new file mode 100644 index 00000000000..d7341c625f4 --- /dev/null +++ b/openpype/hosts/nuke/plugins/create/convert_legacy.py @@ -0,0 +1,49 @@ +from openpype.pipeline.create.creator_plugins import SubsetConvertorPlugin +from openpype.hosts.nuke.api.lib import ( + INSTANCE_DATA_KNOB, + get_node_data, + get_avalon_knob_data +) +from openpype.hosts.nuke.api.plugin import convert_to_valid_instaces + +import nuke + + +class LegacyConverted(SubsetConvertorPlugin): + identifier = "legacy.converter" + + def find_instances(self): + + legacy_found = False + # search for first available legacy item + for node in nuke.allNodes(recurseGroups=True): + + if node.Class() in ["Viewer", "Dot"]: + continue + + if get_node_data(node, INSTANCE_DATA_KNOB): + continue + + # get data from avalon knob + avalon_knob_data = get_avalon_knob_data( + node, ["avalon:", "ak:"], create=False) + + if not avalon_knob_data: + continue + + if avalon_knob_data["id"] != "pyblish.avalon.instance": + continue + + # catch and break + legacy_found = True + break + + if legacy_found: + # if not item do not add legacy instance convertor + self.add_convertor_item("Convert legacy instances") + + def convert(self): + # loop all instances and convert them + convert_to_valid_instaces() + # remove legacy item if all is fine + self.remove_convertor_item() diff --git a/openpype/hosts/nuke/plugins/create/create_backdrop.py b/openpype/hosts/nuke/plugins/create/create_backdrop.py index 0c11b3f2740..ebc66e95a77 100644 --- a/openpype/hosts/nuke/plugins/create/create_backdrop.py +++ b/openpype/hosts/nuke/plugins/create/create_backdrop.py @@ -1,56 +1,57 @@ -import nuke -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - select_nodes, - set_avalon_knob_data +from nukescripts import autoBackdrop + +from openpype.hosts.nuke.api import ( + NukeCreator, + NukeCreatorError, + maintained_selection, + select_nodes + ) -class CreateBackdrop(plugin.OpenPypeCreator): +class CreateBackdrop(NukeCreator): """Add Publishable Backdrop""" - name = "nukenodes" - label = "Create Backdrop" + identifier = "create_backdrop" + label = "Nukenodes (backdrop)" family = "nukenodes" icon = "file-archive-o" - defaults = ["Main"] - - def __init__(self, *args, **kwargs): - super(CreateBackdrop, self).__init__(*args, **kwargs) - self.nodes = nuke.selectedNodes() - self.node_color = "0xdfea5dff" - return - - def process(self): - from nukescripts import autoBackdrop - nodes = list() - if (self.options or {}).get("useSelection"): - nodes = self.nodes - - if len(nodes) >= 1: - select_nodes(nodes) - bckd_node = autoBackdrop() - bckd_node["name"].setValue("{}_BDN".format(self.name)) - bckd_node["tile_color"].setValue(int(self.node_color, 16)) - bckd_node["note_font_size"].setValue(24) - bckd_node["label"].setValue("[{}]".format(self.name)) - # add avalon knobs - instance = set_avalon_knob_data(bckd_node, self.data) - - return instance - else: - msg = str("Please select nodes you " - "wish to add to a container") - self.log.error(msg) - nuke.message(msg) - return - else: - bckd_node = autoBackdrop() - bckd_node["name"].setValue("{}_BDN".format(self.name)) - bckd_node["tile_color"].setValue(int(self.node_color, 16)) - bckd_node["note_font_size"].setValue(24) - bckd_node["label"].setValue("[{}]".format(self.name)) - # add avalon knobs - instance = set_avalon_knob_data(bckd_node, self.data) - - return instance + maintain_selection = True + + # plugin attributes + node_color = "0xdfea5dff" + + def create_instance_node( + self, + node_name, + knobs=None, + parent=None, + node_type=None + ): + with maintained_selection(): + if len(self.selected_nodes) >= 1: + select_nodes(self.selected_nodes) + + created_node = autoBackdrop() + created_node["name"].setValue(node_name) + created_node["tile_color"].setValue(int(self.node_color, 16)) + created_node["note_font_size"].setValue(24) + created_node["label"].setValue("[{}]".format(node_name)) + + self.add_info_knob(created_node) + + return created_node + + def create(self, subset_name, instance_data, pre_create_data): + if self.check_existing_subset(subset_name, instance_data): + raise NukeCreatorError( + ("Subset name '{}' is already used. " + "Please specify different Variant.").format(subset_name)) + + instance = super(CreateBackdrop, self).create( + subset_name, + instance_data, + pre_create_data + ) + + return instance diff --git a/openpype/hosts/nuke/plugins/create/create_camera.py b/openpype/hosts/nuke/plugins/create/create_camera.py index 3b13c80dc4c..dc4a30f513d 100644 --- a/openpype/hosts/nuke/plugins/create/create_camera.py +++ b/openpype/hosts/nuke/plugins/create/create_camera.py @@ -1,55 +1,70 @@ import nuke -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - set_avalon_knob_data +from openpype.hosts.nuke.api import ( + NukeCreator, + NukeCreatorError, + maintained_selection ) -class CreateCamera(plugin.OpenPypeCreator): - """Add Publishable Backdrop""" +class CreateCamera(NukeCreator): + """Add Publishable Camera""" - name = "camera" - label = "Create 3d Camera" + identifier = "create_camera" + label = "Camera (3d)" family = "camera" icon = "camera" - defaults = ["Main"] - - def __init__(self, *args, **kwargs): - super(CreateCamera, self).__init__(*args, **kwargs) - self.nodes = nuke.selectedNodes() - self.node_color = "0xff9100ff" - return - - def process(self): - nodes = list() - if (self.options or {}).get("useSelection"): - nodes = self.nodes - - if len(nodes) >= 1: - # loop selected nodes - for n in nodes: - data = self.data.copy() - if len(nodes) > 1: - # rename subset name only if more - # then one node are selected - subset = self.family + n["name"].value().capitalize() - data["subset"] = subset - - # change node color - n["tile_color"].setValue(int(self.node_color, 16)) - # add avalon knobs - set_avalon_knob_data(n, data) - return True + + # plugin attributes + node_color = "0xff9100ff" + + def create_instance_node( + self, + node_name, + knobs=None, + parent=None, + node_type=None + ): + with maintained_selection(): + if self.selected_nodes: + node = self.selected_nodes[0] + if node.Class() != "Camera3": + raise NukeCreatorError( + "Creator error: Select only camera node type") + created_node = self.selected_nodes[0] else: - msg = str("Please select nodes you " - "wish to add to a container") - self.log.error(msg) - nuke.message(msg) - return + created_node = nuke.createNode("Camera2") + + created_node["tile_color"].setValue( + int(self.node_color, 16)) + + created_node["name"].setValue(node_name) + + self.add_info_knob(created_node) + + return created_node + + def create(self, subset_name, instance_data, pre_create_data): + if self.check_existing_subset(subset_name, instance_data): + raise NukeCreatorError( + ("Subset name '{}' is already used. " + "Please specify different Variant.").format(subset_name)) + + instance = super(CreateCamera, self).create( + subset_name, + instance_data, + pre_create_data + ) + + return instance + + def set_selected_nodes(self, pre_create_data): + if pre_create_data.get("use_selection"): + self.selected_nodes = nuke.selectedNodes() + if self.selected_nodes == []: + raise NukeCreatorError( + "Creator error: No active selection") + elif len(self.selected_nodes) > 1: + raise NukeCreatorError( + "Creator error: Select only one camera node") else: - # if selected is off then create one node - camera_node = nuke.createNode("Camera2") - camera_node["tile_color"].setValue(int(self.node_color, 16)) - # add avalon knobs - instance = set_avalon_knob_data(camera_node, self.data) - return instance + self.selected_nodes = [] diff --git a/openpype/hosts/nuke/plugins/create/create_gizmo.py b/openpype/hosts/nuke/plugins/create/create_gizmo.py index d616f6f7ad7..1869874e226 100644 --- a/openpype/hosts/nuke/plugins/create/create_gizmo.py +++ b/openpype/hosts/nuke/plugins/create/create_gizmo.py @@ -1,87 +1,69 @@ import nuke - -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - maintained_selection, - select_nodes, - set_avalon_knob_data +from openpype.hosts.nuke.api import ( + NukeCreator, + NukeCreatorError, + maintained_selection ) -class CreateGizmo(plugin.OpenPypeCreator): - """Add Publishable "gizmo" group - - The name is symbolically gizmo as presumably - it is something familiar to nuke users as group of nodes - distributed downstream in workflow - """ +class CreateGizmo(NukeCreator): + """Add Publishable Group as gizmo""" - name = "gizmo" - label = "Gizmo" + identifier = "create_gizmo" + label = "Gizmo (group)" family = "gizmo" icon = "file-archive-o" - defaults = ["ViewerInput", "Lut", "Effect"] + default_variants = ["ViewerInput", "Lut", "Effect"] - def __init__(self, *args, **kwargs): - super(CreateGizmo, self).__init__(*args, **kwargs) - self.nodes = nuke.selectedNodes() - self.node_color = "0x7533c1ff" - return + # plugin attributes + node_color = "0x7533c1ff" - def process(self): - if (self.options or {}).get("useSelection"): - nodes = self.nodes - self.log.info(len(nodes)) - if len(nodes) == 1: - select_nodes(nodes) - node = nodes[-1] - # check if Group node - if node.Class() in "Group": - node["name"].setValue("{}_GZM".format(self.name)) - node["tile_color"].setValue(int(self.node_color, 16)) - return set_avalon_knob_data(node, self.data) - else: - msg = ("Please select a group node " - "you wish to publish as the gizmo") - self.log.error(msg) - nuke.message(msg) + def create_instance_node( + self, + node_name, + knobs=None, + parent=None, + node_type=None + ): + with maintained_selection(): + if self.selected_nodes: + node = self.selected_nodes[0] + if node.Class() != "Group": + raise NukeCreatorError( + "Creator error: Select only 'Group' node type") + created_node = node + else: + created_node = nuke.collapseToGroup() - if len(nodes) >= 2: - select_nodes(nodes) - nuke.makeGroup() - gizmo_node = nuke.selectedNode() - gizmo_node["name"].setValue("{}_GZM".format(self.name)) - gizmo_node["tile_color"].setValue(int(self.node_color, 16)) + created_node["tile_color"].setValue( + int(self.node_color, 16)) - # add sticky node with guide - with gizmo_node: - sticky = nuke.createNode("StickyNote") - sticky["label"].setValue( - "Add following:\n- set Input" - " nodes\n- set one Output1\n" - "- create User knobs on the group") + created_node["name"].setValue(node_name) - # add avalon knobs - return set_avalon_knob_data(gizmo_node, self.data) + self.add_info_knob(created_node) - else: - msg = "Please select nodes you wish to add to the gizmo" - self.log.error(msg) - nuke.message(msg) - return - else: - with maintained_selection(): - gizmo_node = nuke.createNode("Group") - gizmo_node["name"].setValue("{}_GZM".format(self.name)) - gizmo_node["tile_color"].setValue(int(self.node_color, 16)) + return created_node + + def create(self, subset_name, instance_data, pre_create_data): + if self.check_existing_subset(subset_name, instance_data): + raise NukeCreatorError( + ("Subset name '{}' is already used. " + "Please specify different Variant.").format(subset_name)) - # add sticky node with guide - with gizmo_node: - sticky = nuke.createNode("StickyNote") - sticky["label"].setValue( - "Add following:\n- add Input" - " nodes\n- add one Output1\n" - "- create User knobs on the group") + instance = super(CreateGizmo, self).create( + subset_name, + instance_data, + pre_create_data + ) - # add avalon knobs - return set_avalon_knob_data(gizmo_node, self.data) + return instance + + def set_selected_nodes(self, pre_create_data): + if pre_create_data.get("use_selection"): + self.selected_nodes = nuke.selectedNodes() + if self.selected_nodes == []: + raise NukeCreatorError("Creator error: No active selection") + elif len(self.selected_nodes) > 1: + NukeCreatorError("Creator error: Select only one 'Group' node") + else: + self.selected_nodes = [] diff --git a/openpype/hosts/nuke/plugins/create/create_model.py b/openpype/hosts/nuke/plugins/create/create_model.py index 15a4e3ab8a0..53b3a582880 100644 --- a/openpype/hosts/nuke/plugins/create/create_model.py +++ b/openpype/hosts/nuke/plugins/create/create_model.py @@ -1,87 +1,69 @@ import nuke -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - set_avalon_knob_data +from openpype.hosts.nuke.api import ( + NukeCreator, + NukeCreatorError, + maintained_selection ) -class CreateModel(plugin.OpenPypeCreator): - """Add Publishable Model Geometry""" +class CreateModel(NukeCreator): + """Add Publishable Camera""" - name = "model" - label = "Create 3d Model" + identifier = "create_model" + label = "Model (3d)" family = "model" icon = "cube" - defaults = ["Main"] + default_variants = ["Main"] - def __init__(self, *args, **kwargs): - super(CreateModel, self).__init__(*args, **kwargs) - self.nodes = nuke.selectedNodes() - self.node_color = "0xff3200ff" - return + # plugin attributes + node_color = "0xff3200ff" - def process(self): - nodes = list() - if (self.options or {}).get("useSelection"): - nodes = self.nodes - for n in nodes: - n['selected'].setValue(0) - end_nodes = list() + def create_instance_node( + self, + node_name, + knobs=None, + parent=None, + node_type=None + ): + with maintained_selection(): + if self.selected_nodes: + node = self.selected_nodes[0] + if node.Class() != "Scene": + raise NukeCreatorError( + "Creator error: Select only 'Scene' node type") + created_node = node + else: + created_node = nuke.createNode("Scene") - # get the latest nodes in tree for selecion - for n in nodes: - x = n - end = 0 - while end == 0: - try: - x = x.dependent()[0] - except: - end_node = x - end = 1 - end_nodes.append(end_node) + created_node["tile_color"].setValue( + int(self.node_color, 16)) - # set end_nodes - end_nodes = list(set(end_nodes)) + created_node["name"].setValue(node_name) - # check if nodes is 3d nodes - for n in end_nodes: - n['selected'].setValue(1) - sn = nuke.createNode("Scene") - if not sn.input(0): - end_nodes.remove(n) - nuke.delete(sn) + self.add_info_knob(created_node) - # loop over end nodes - for n in end_nodes: - n['selected'].setValue(1) + return created_node - self.nodes = nuke.selectedNodes() - nodes = self.nodes - if len(nodes) >= 1: - # loop selected nodes - for n in nodes: - data = self.data.copy() - if len(nodes) > 1: - # rename subset name only if more - # then one node are selected - subset = self.family + n["name"].value().capitalize() - data["subset"] = subset + def create(self, subset_name, instance_data, pre_create_data): + if self.check_existing_subset(subset_name, instance_data): + raise NukeCreatorError( + ("Subset name '{}' is already used. " + "Please specify different Variant.").format(subset_name)) - # change node color - n["tile_color"].setValue(int(self.node_color, 16)) - # add avalon knobs - set_avalon_knob_data(n, data) - return True - else: - msg = str("Please select nodes you " - "wish to add to a container") - self.log.error(msg) - nuke.message(msg) - return + instance = super(CreateModel, self).create( + subset_name, + instance_data, + pre_create_data + ) + + return instance + + def set_selected_nodes(self, pre_create_data): + if pre_create_data.get("use_selection"): + self.selected_nodes = nuke.selectedNodes() + if self.selected_nodes == []: + raise NukeCreatorError("Creator error: No active selection") + elif len(self.selected_nodes) > 1: + NukeCreatorError("Creator error: Select only one 'Scene' node") else: - # if selected is off then create one node - model_node = nuke.createNode("WriteGeo") - model_node["tile_color"].setValue(int(self.node_color, 16)) - # add avalon knobs - instance = set_avalon_knob_data(model_node, self.data) - return instance + self.selected_nodes = [] diff --git a/openpype/hosts/nuke/plugins/create/create_read.py b/openpype/hosts/nuke/plugins/create/create_read.py deleted file mode 100644 index 87a9dff0f86..00000000000 --- a/openpype/hosts/nuke/plugins/create/create_read.py +++ /dev/null @@ -1,57 +0,0 @@ -from collections import OrderedDict - -import nuke - -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - set_avalon_knob_data -) - - -class CrateRead(plugin.OpenPypeCreator): - # change this to template preset - name = "ReadCopy" - label = "Create Read Copy" - hosts = ["nuke"] - family = "source" - families = family - icon = "film" - defaults = ["Effect", "Backplate", "Fire", "Smoke"] - - def __init__(self, *args, **kwargs): - super(CrateRead, self).__init__(*args, **kwargs) - self.nodes = nuke.selectedNodes() - data = OrderedDict() - data['family'] = self.family - data['families'] = self.families - - for k, v in self.data.items(): - if k not in data.keys(): - data.update({k: v}) - - self.data = data - - def process(self): - self.name = self.data["subset"] - nodes = self.nodes - - if not nodes or len(nodes) == 0: - msg = "Please select Read node" - self.log.error(msg) - nuke.message(msg) - else: - count_reads = 0 - for node in nodes: - if node.Class() != 'Read': - continue - avalon_data = self.data - avalon_data['subset'] = "{}".format(self.name) - set_avalon_knob_data(node, avalon_data) - node['tile_color'].setValue(16744935) - count_reads += 1 - - if count_reads < 1: - msg = "Please select Read node" - self.log.error(msg) - nuke.message(msg) - return diff --git a/openpype/hosts/nuke/plugins/create/create_source.py b/openpype/hosts/nuke/plugins/create/create_source.py new file mode 100644 index 00000000000..35fe42c16b9 --- /dev/null +++ b/openpype/hosts/nuke/plugins/create/create_source.py @@ -0,0 +1,91 @@ +import nuke +import six +import sys +from openpype.hosts.nuke.api import ( + INSTANCE_DATA_KNOB, + NukeCreator, + NukeCreatorError, + set_node_data +) +from openpype.pipeline import ( + CreatedInstance +) + + +class CreateSource(NukeCreator): + """Add Publishable Read with source""" + + identifier = "create_source" + label = "Source (read)" + family = "source" + icon = "film" + default_variants = ["Effect", "Backplate", "Fire", "Smoke"] + + # plugin attributes + node_color = "0xff9100ff" + + def create_instance_node( + self, + node_name, + read_node + ): + read_node["tile_color"].setValue( + int(self.node_color, 16)) + read_node["name"].setValue(node_name) + self.add_info_knob(read_node) + return read_node + + def create(self, subset_name, instance_data, pre_create_data): + + # make sure selected nodes are added + self.set_selected_nodes(pre_create_data) + + try: + for read_node in self.selected_nodes: + if read_node.Class() != 'Read': + continue + + node_name = read_node.name() + _subset_name = subset_name + node_name + + # make sure subset name is unique + if self.check_existing_subset(_subset_name, instance_data): + raise NukeCreatorError( + ("subset {} is already published" + "definition.").format(_subset_name)) + + instance_node = self.create_instance_node( + _subset_name, + read_node + ) + instance = CreatedInstance( + self.family, + _subset_name, + instance_data, + self + ) + + instance.transient_data["node"] = instance_node + + self._add_instance_to_context(instance) + + set_node_data( + instance_node, + INSTANCE_DATA_KNOB, + instance.data_to_store() + ) + + except Exception as er: + six.reraise( + NukeCreatorError, + NukeCreatorError("Creator error: {}".format(er)), + sys.exc_info()[2]) + + def set_selected_nodes(self, pre_create_data): + if pre_create_data.get("use_selection"): + self.selected_nodes = nuke.selectedNodes() + if self.selected_nodes == []: + raise NukeCreatorError("Creator error: No active selection") + else: + NukeCreatorError( + "Creator error: only supprted with active selection") diff --git a/openpype/hosts/nuke/plugins/create/create_write_image.py b/openpype/hosts/nuke/plugins/create/create_write_image.py new file mode 100644 index 00000000000..cf70063abc5 --- /dev/null +++ b/openpype/hosts/nuke/plugins/create/create_write_image.py @@ -0,0 +1,176 @@ +import nuke +import sys +import six + +from openpype.pipeline import ( + CreatedInstance +) +from openpype.lib import ( + BoolDef, + NumberDef, + UISeparatorDef, + EnumDef +) +from openpype.hosts.nuke import api as napi + + +class CreateWriteImage(napi.NukeWriteCreator): + identifier = "create_write_image" + label = "Image (write)" + family = "image" + icon = "sign-out" + + instance_attributes = [ + "use_range_limit" + ] + default_variants = [ + "StillFrame", + "MPFrame", + "LayoutFrame" + ] + temp_rendering_path_template = ( + "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}") + + def get_pre_create_attr_defs(self): + attr_defs = [ + BoolDef( + "use_selection", + default=True, + label="Use selection" + ), + self._get_render_target_enum(), + UISeparatorDef(), + self._get_frame_source_number() + ] + return attr_defs + + def _get_render_target_enum(self): + rendering_targets = { + "local": "Local machine rendering", + "frames": "Use existing frames" + } + + return EnumDef( + "render_target", + items=rendering_targets, + label="Render target" + ) + + def _get_frame_source_number(self): + return NumberDef( + "active_frame", + label="Active frame", + default=nuke.frame() + ) + + def get_instance_attr_defs(self): + attr_defs = [ + self._get_render_target_enum(), + self._get_reviewable_bool() + ] + return attr_defs + + def create_instance_node(self, subset_name, instance_data): + linked_knobs_ = [] + if "use_range_limit" in self.instance_attributes: + linked_knobs_ = ["channels", "___", "first", "last", "use_limit"] + + # add fpath_template + write_data = { + "creator": self.__class__.__name__, + "subset": subset_name, + "fpath_template": self.temp_rendering_path_template + } + write_data.update(instance_data) + + created_node = napi.create_write_node( + subset_name, + write_data, + input=self.selected_node, + prenodes=self.prenodes, + linked_knobs=linked_knobs_, + **{ + "frame": nuke.frame() + } + ) + self.add_info_knob(created_node) + + self._add_frame_range_limit(created_node, instance_data) + + self.integrate_links(created_node, outputs=True) + + return created_node + + def create(self, subset_name, instance_data, pre_create_data): + subset_name = subset_name.format(**pre_create_data) + + # pass values from precreate to instance + self.pass_pre_attributes_to_instance( + instance_data, + pre_create_data, + [ + "active_frame", + "render_target" + ] + ) + + # make sure selected nodes are added + self.set_selected_nodes(pre_create_data) + + # make sure subset name is unique + if self.check_existing_subset(subset_name, instance_data): + raise napi.NukeCreatorError( + ("subset {} is already published" + "definition.").format(subset_name)) + + instance_node = self.create_instance_node( + subset_name, + instance_data, + ) + + try: + instance = CreatedInstance( + self.family, + subset_name, + instance_data, + self + ) + + instance.transient_data["node"] = instance_node + + self._add_instance_to_context(instance) + + napi.set_node_data( + instance_node, + napi.INSTANCE_DATA_KNOB, + instance.data_to_store() + ) + + return instance + + except Exception as er: + six.reraise( + napi.NukeCreatorError, + napi.NukeCreatorError("Creator error: {}".format(er)), + sys.exc_info()[2] + ) + + def _add_frame_range_limit(self, write_node, instance_data): + if "use_range_limit" not in self.instance_attributes: + return + + active_frame = ( + instance_data["creator_attributes"].get("active_frame")) + + write_node.begin() + for n in nuke.allNodes(): + # get write node + if n.Class() in "Write": + w_node = n + write_node.end() + + w_node["use_limit"].setValue(True) + w_node["first"].setValue(active_frame or nuke.frame()) + w_node["last"].setExpression("first") + + return write_node diff --git a/openpype/hosts/nuke/plugins/create/create_write_prerender.py b/openpype/hosts/nuke/plugins/create/create_write_prerender.py index fec97167fb2..daa2319c4b1 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_prerender.py +++ b/openpype/hosts/nuke/plugins/create/create_write_prerender.py @@ -1,56 +1,179 @@ import nuke +import sys +import six -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - create_write_node, create_write_node_legacy) +from openpype.pipeline import ( + CreatedInstance +) +from openpype.lib import ( + BoolDef, + NumberDef, + UISeparatorDef, + UILabelDef +) +from openpype.hosts.nuke import api as napi -class CreateWritePrerender(plugin.AbstractWriteRender): - # change this to template preset - name = "WritePrerender" - label = "Create Write Prerender" - hosts = ["nuke"] - n_class = "Write" +class CreateWritePrerender(napi.NukeWriteCreator): + identifier = "create_write_prerender" + label = "Prerender (write)" family = "prerender" icon = "sign-out" - # settings - fpath_template = "{work}/render/nuke/{subset}/{subset}.{frame}.{ext}" - defaults = ["Key01", "Bg01", "Fg01", "Branch01", "Part01"] - reviewable = False - use_range_limit = True + instance_attributes = [ + "use_range_limit" + ] + default_variants = [ + "Key01", + "Bg01", + "Fg01", + "Branch01", + "Part01" + ] + temp_rendering_path_template = ( + "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}") - def __init__(self, *args, **kwargs): - super(CreateWritePrerender, self).__init__(*args, **kwargs) + def get_pre_create_attr_defs(self): + attr_defs = [ + BoolDef( + "use_selection", + default=True, + label="Use selection" + ), + self._get_render_target_enum() + ] + return attr_defs + + def get_instance_attr_defs(self): + attr_defs = [ + self._get_render_target_enum(), + self._get_reviewable_bool() + ] + if "farm_rendering" in self.instance_attributes: + attr_defs.extend([ + UISeparatorDef(), + UILabelDef("Farm rendering attributes"), + BoolDef("suspended_publish", label="Suspended publishing"), + NumberDef( + "farm_priority", + label="Priority", + minimum=1, + maximum=99, + default=50 + ), + NumberDef( + "farm_chunk", + label="Chunk size", + minimum=1, + maximum=99, + default=10 + ), + NumberDef( + "farm_concurency", + label="Concurent tasks", + minimum=1, + maximum=10, + default=1 + ) + ]) + return attr_defs + + def create_instance_node(self, subset_name, instance_data): + linked_knobs_ = [] + if "use_range_limit" in self.instance_attributes: + linked_knobs_ = ["channels", "___", "first", "last", "use_limit"] - def _create_write_node(self, selected_node, inputs, outputs, write_data): # add fpath_template - write_data["fpath_template"] = self.fpath_template - write_data["use_range_limit"] = self.use_range_limit - write_data["frame_range"] = ( - nuke.root()["first_frame"].value(), - nuke.root()["last_frame"].value() + write_data = { + "creator": self.__class__.__name__, + "subset": subset_name, + "fpath_template": self.temp_rendering_path_template + } + + write_data.update(instance_data) + + # get width and height + if self.selected_node: + width, height = ( + self.selected_node.width(), self.selected_node.height()) + else: + actual_format = nuke.root().knob('format').value() + width, height = (actual_format.width(), actual_format.height()) + + created_node = napi.create_write_node( + subset_name, + write_data, + input=self.selected_node, + prenodes=self.prenodes, + linked_knobs=linked_knobs_, + **{ + "width": width, + "height": height + } ) + self.add_info_knob(created_node) + + self._add_frame_range_limit(created_node) + + self.integrate_links(created_node, outputs=True) + + return created_node + + def create(self, subset_name, instance_data, pre_create_data): + # pass values from precreate to instance + self.pass_pre_attributes_to_instance( + instance_data, + pre_create_data, + [ + "render_target" + ] + ) + + # make sure selected nodes are added + self.set_selected_nodes(pre_create_data) - if not self.is_legacy(): - return create_write_node( - self.data["subset"], - write_data, - input=selected_node, - review=self.reviewable, - linked_knobs=["channels", "___", "first", "last", "use_limit"] + # make sure subset name is unique + if self.check_existing_subset(subset_name, instance_data): + raise napi.NukeCreatorError( + ("subset {} is already published" + "definition.").format(subset_name)) + + instance_node = self.create_instance_node( + subset_name, + instance_data + ) + + try: + instance = CreatedInstance( + self.family, + subset_name, + instance_data, + self ) - else: - return create_write_node_legacy( - self.data["subset"], - write_data, - input=selected_node, - review=self.reviewable, - linked_knobs=["channels", "___", "first", "last", "use_limit"] + + instance.transient_data["node"] = instance_node + + self._add_instance_to_context(instance) + + napi.set_node_data( + instance_node, + napi.INSTANCE_DATA_KNOB, + instance.data_to_store() ) - def _modify_write_node(self, write_node): - # open group node + return instance + + except Exception as er: + six.reraise( + napi.NukeCreatorError, + napi.NukeCreatorError("Creator error: {}".format(er)), + sys.exc_info()[2] + ) + + def _add_frame_range_limit(self, write_node): + if "use_range_limit" not in self.instance_attributes: + return + write_node.begin() for n in nuke.allNodes(): # get write node @@ -58,9 +181,8 @@ def _modify_write_node(self, write_node): w_node = n write_node.end() - if self.use_range_limit: - w_node["use_limit"].setValue(True) - w_node["first"].setValue(nuke.root()["first_frame"].value()) - w_node["last"].setValue(nuke.root()["last_frame"].value()) + w_node["use_limit"].setValue(True) + w_node["first"].setValue(nuke.root()["first_frame"].value()) + w_node["last"].setValue(nuke.root()["last_frame"].value()) return write_node diff --git a/openpype/hosts/nuke/plugins/create/create_write_render.py b/openpype/hosts/nuke/plugins/create/create_write_render.py index 23846c03325..85133458d10 100644 --- a/openpype/hosts/nuke/plugins/create/create_write_render.py +++ b/openpype/hosts/nuke/plugins/create/create_write_render.py @@ -1,86 +1,160 @@ import nuke +import sys +import six -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - create_write_node, create_write_node_legacy) +from openpype.pipeline import ( + CreatedInstance +) +from openpype.lib import ( + BoolDef, + NumberDef, + UISeparatorDef, + UILabelDef +) +from openpype.hosts.nuke import api as napi -class CreateWriteRender(plugin.AbstractWriteRender): - # change this to template preset - name = "WriteRender" - label = "Create Write Render" - hosts = ["nuke"] - n_class = "Write" +class CreateWriteRender(napi.NukeWriteCreator): + identifier = "create_write_render" + label = "Render (write)" family = "render" icon = "sign-out" - # settings - fpath_template = "{work}/render/nuke/{subset}/{subset}.{frame}.{ext}" - defaults = ["Main", "Mask"] - prenodes = { - "Reformat01": { - "nodeclass": "Reformat", - "dependent": None, - "knobs": [ - { - "type": "text", - "name": "resize", - "value": "none" - }, - { - "type": "bool", - "name": "black_outside", - "value": True - } - ] - } - } + instance_attributes = [ + "reviewable" + ] + default_variants = [ + "Main", + "Mask" + ] + temp_rendering_path_template = ( + "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}") + + def get_pre_create_attr_defs(self): + attr_defs = [ + BoolDef( + "use_selection", + default=True, + label="Use selection" + ), + self._get_render_target_enum() + ] + return attr_defs - def __init__(self, *args, **kwargs): - super(CreateWriteRender, self).__init__(*args, **kwargs) + def get_instance_attr_defs(self): + attr_defs = [ + self._get_render_target_enum(), + self._get_reviewable_bool() + ] + if "farm_rendering" in self.instance_attributes: + attr_defs.extend([ + UISeparatorDef(), + UILabelDef("Farm rendering attributes"), + BoolDef("suspended_publish", label="Suspended publishing"), + NumberDef( + "farm_priority", + label="Priority", + minimum=1, + maximum=99, + default=50 + ), + NumberDef( + "farm_chunk", + label="Chunk size", + minimum=1, + maximum=99, + default=10 + ), + NumberDef( + "farm_concurency", + label="Concurent tasks", + minimum=1, + maximum=10, + default=1 + ) + ]) + return attr_defs - def _create_write_node(self, selected_node, inputs, outputs, write_data): + def create_instance_node(self, subset_name, instance_data): # add fpath_template - write_data["fpath_template"] = self.fpath_template + write_data = { + "creator": self.__class__.__name__, + "subset": subset_name, + "fpath_template": self.temp_rendering_path_template + } + + write_data.update(instance_data) - # add reformat node to cut off all outside of format bounding box # get width and height - try: - width, height = (selected_node.width(), selected_node.height()) - except AttributeError: + if self.selected_node: + width, height = ( + self.selected_node.width(), self.selected_node.height()) + else: actual_format = nuke.root().knob('format').value() width, height = (actual_format.width(), actual_format.height()) - if not self.is_legacy(): - return create_write_node( - self.data["subset"], - write_data, - input=selected_node, - prenodes=self.prenodes, - **{ - "width": width, - "height": height - } - ) - else: - _prenodes = [ - { - "name": "Reformat01", - "class": "Reformat", - "knobs": [ - ("resize", 0), - ("black_outside", 1), - ], - "dependent": None - } + created_node = napi.create_write_node( + subset_name, + write_data, + input=self.selected_node, + prenodes=self.prenodes, + **{ + "width": width, + "height": height + } + ) + self.add_info_knob(created_node) + + self.integrate_links(created_node, outputs=False) + + return created_node + + def create(self, subset_name, instance_data, pre_create_data): + # pass values from precreate to instance + self.pass_pre_attributes_to_instance( + instance_data, + pre_create_data, + [ + "render_target" ] + ) + # make sure selected nodes are added + self.set_selected_nodes(pre_create_data) + + # make sure subset name is unique + if self.check_existing_subset(subset_name, instance_data): + raise napi.NukeCreatorError( + ("subset {} is already published" + "definition.").format(subset_name)) + + instance_node = self.create_instance_node( + subset_name, + instance_data + ) + + try: + instance = CreatedInstance( + self.family, + subset_name, + instance_data, + self + ) + + instance.transient_data["node"] = instance_node + + self._add_instance_to_context(instance) - return create_write_node_legacy( - self.data["subset"], - write_data, - input=selected_node, - prenodes=_prenodes + napi.set_node_data( + instance_node, + napi.INSTANCE_DATA_KNOB, + instance.data_to_store() ) - def _modify_write_node(self, write_node): - return write_node + return instance + + except Exception as er: + six.reraise( + napi.NukeCreatorError, + napi.NukeCreatorError("Creator error: {}".format(er)), + sys.exc_info()[2] + ) diff --git a/openpype/hosts/nuke/plugins/create/create_write_still.py b/openpype/hosts/nuke/plugins/create/create_write_still.py deleted file mode 100644 index bb08e8c2c6d..00000000000 --- a/openpype/hosts/nuke/plugins/create/create_write_still.py +++ /dev/null @@ -1,105 +0,0 @@ -import nuke - -from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.lib import ( - create_write_node, - create_write_node_legacy, - get_created_node_imageio_setting_legacy -) - -# HACK: just to disable still image on projects which -# are not having anatomy imageio preset for CreateWriteStill -# TODO: remove this code as soon as it will be obsolete -imageio_writes = get_created_node_imageio_setting_legacy( - "Write", - "CreateWriteStill", - "stillMain" -) -print(imageio_writes["knobs"]) - - -class CreateWriteStill(plugin.AbstractWriteRender): - # change this to template preset - name = "WriteStillFrame" - label = "Create Write Still Image" - hosts = ["nuke"] - n_class = "Write" - family = "still" - icon = "image" - - # settings - fpath_template = "{work}/render/nuke/{subset}/{subset}.{ext}" - defaults = [ - "ImageFrame", - "MPFrame", - "LayoutFrame" - ] - prenodes = { - "FrameHold01": { - "nodeclass": "FrameHold", - "dependent": None, - "knobs": [ - { - "type": "formatable", - "name": "first_frame", - "template": "{frame}", - "to_type": "number" - } - ] - } - } - - def __init__(self, *args, **kwargs): - super(CreateWriteStill, self).__init__(*args, **kwargs) - - def _create_write_node(self, selected_node, inputs, outputs, write_data): - # add fpath_template - write_data["fpath_template"] = self.fpath_template - - if not self.is_legacy(): - return create_write_node( - self.name, - write_data, - input=selected_node, - review=False, - prenodes=self.prenodes, - farm=False, - linked_knobs=["channels", "___", "first", "last", "use_limit"], - **{ - "frame": nuke.frame() - } - ) - else: - _prenodes = [ - { - "name": "FrameHold01", - "class": "FrameHold", - "knobs": [ - ("first_frame", nuke.frame()) - ], - "dependent": None - } - ] - return create_write_node_legacy( - self.name, - write_data, - input=selected_node, - review=False, - prenodes=_prenodes, - farm=False, - linked_knobs=["channels", "___", "first", "last", "use_limit"] - ) - - def _modify_write_node(self, write_node): - write_node.begin() - for n in nuke.allNodes(): - # get write node - if n.Class() in "Write": - w_node = n - write_node.end() - - w_node["use_limit"].setValue(True) - w_node["first"].setValue(nuke.frame()) - w_node["last"].setValue(nuke.frame()) - - return write_node diff --git a/openpype/hosts/nuke/plugins/create/workfile_creator.py b/openpype/hosts/nuke/plugins/create/workfile_creator.py new file mode 100644 index 00000000000..72ef61e63f2 --- /dev/null +++ b/openpype/hosts/nuke/plugins/create/workfile_creator.py @@ -0,0 +1,69 @@ +import openpype.hosts.nuke.api as api +from openpype.client import get_asset_by_name +from openpype.pipeline import ( + AutoCreator, + CreatedInstance, + legacy_io, +) +from openpype.hosts.nuke.api import ( + INSTANCE_DATA_KNOB, + set_node_data +) +import nuke + + +class WorkfileCreator(AutoCreator): + identifier = "workfile" + family = "workfile" + + default_variant = "Main" + + def get_instance_attr_defs(self): + return [] + + def collect_instances(self): + root_node = nuke.root() + instance_data = api.get_node_data( + root_node, api.INSTANCE_DATA_KNOB + ) + + project_name = legacy_io.Session["AVALON_PROJECT"] + asset_name = legacy_io.Session["AVALON_ASSET"] + task_name = legacy_io.Session["AVALON_TASK"] + host_name = legacy_io.Session["AVALON_APP"] + + asset_doc = get_asset_by_name(project_name, asset_name) + subset_name = self.get_subset_name( + self.default_variant, task_name, asset_doc, + project_name, host_name + ) + instance_data.update({ + "asset": asset_name, + "task": task_name, + "variant": self.default_variant + }) + instance_data.update(self.get_dynamic_data( + self.default_variant, task_name, asset_doc, + project_name, host_name, instance_data + )) + + instance = CreatedInstance( + self.family, subset_name, instance_data, self + ) + instance.transient_data["node"] = root_node + self._add_instance_to_context(instance) + + def update_instances(self, update_list): + for created_inst, _changes in update_list: + instance_node = created_inst.transient_data["node"] + + set_node_data( + instance_node, + INSTANCE_DATA_KNOB, + created_inst.data_to_store() + ) + + def create(self, options=None): + # no need to create if it is created + # in `collect_instances` + pass diff --git a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py index 4efbb88b8c1..8eaefa68541 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/collect_backdrop.py @@ -1,9 +1,9 @@ +from pprint import pformat import pyblish.api from openpype.hosts.nuke.api import lib as pnlib import nuke -@pyblish.api.log class CollectBackdrops(pyblish.api.InstancePlugin): """Collect Backdrop node instance and its content """ @@ -14,8 +14,9 @@ class CollectBackdrops(pyblish.api.InstancePlugin): families = ["nukenodes"] def process(self, instance): + self.log.debug(pformat(instance.data)) - bckn = instance[0] + bckn = instance.data["transientData"]["node"] # define size of the backdrop left = bckn.xpos() @@ -23,6 +24,7 @@ def process(self, instance): right = left + bckn['bdwidth'].value() bottom = top + bckn['bdheight'].value() + instance.data["transientData"]["childNodes"] = [] # iterate all nodes for node in nuke.allNodes(): @@ -37,17 +39,17 @@ def process(self, instance): and (node.ypos() + node.screenHeight() < bottom): # add contained nodes to instance's node list - instance.append(node) + instance.data["transientData"]["childNodes"].append(node) # get all connections from outside of backdrop - nodes = instance[1:] + nodes = instance.data["transientData"]["childNodes"] connections_in, connections_out = pnlib.get_dependent_nodes(nodes) - instance.data["nodeConnectionsIn"] = connections_in - instance.data["nodeConnectionsOut"] = connections_out + instance.data["transientData"]["nodeConnectionsIn"] = connections_in + instance.data["transientData"]["nodeConnectionsOut"] = connections_out # make label nicer instance.data["label"] = "{0} ({1} nodes)".format( - bckn.name(), len(instance) - 1) + bckn.name(), len(instance.data["transientData"]["childNodes"])) instance.data["families"].append(instance.data["family"]) @@ -83,5 +85,4 @@ def process(self, instance): "frameStart": first_frame, "frameEnd": last_frame }) - self.log.info("Backdrop content collected: `{}`".format(instance[:])) self.log.info("Backdrop instance collected: `{}`".format(instance)) diff --git a/openpype/hosts/nuke/plugins/publish/collect_context_data.py b/openpype/hosts/nuke/plugins/publish/collect_context_data.py new file mode 100644 index 00000000000..5a1cdcf49ec --- /dev/null +++ b/openpype/hosts/nuke/plugins/publish/collect_context_data.py @@ -0,0 +1,69 @@ +import os +import nuke +import pyblish.api +import openpype.api as api +import openpype.hosts.nuke.api as napi +from openpype.pipeline import KnownPublishError + + +class CollectContextData(pyblish.api.ContextPlugin): + """Collect current context publish.""" + + order = pyblish.api.CollectorOrder - 0.499 + label = "Collect context data" + hosts = ['nuke'] + + def process(self, context): # sourcery skip: avoid-builtin-shadow + root_node = nuke.root() + + current_file = os.path.normpath(root_node.name()) + + if current_file.lower() == "root": + raise KnownPublishError( + "Workfile is not correct file name. \n" + "Use workfile tool to manage the name correctly." + ) + + # Get frame range + first_frame = int(root_node["first_frame"].getValue()) + last_frame = int(root_node["last_frame"].getValue()) + + # get instance data from root + root_instance_context = napi.get_node_data( + root_node, napi.INSTANCE_DATA_KNOB + ) + + handle_start = root_instance_context["handleStart"] + handle_end = root_instance_context["handleEnd"] + + # Get format + format = root_node['format'].value() + resolution_width = format.width() + resolution_height = format.height() + pixel_aspect = format.pixelAspect() + + script_data = { + "frameStart": first_frame + handle_start, + "frameEnd": last_frame - handle_end, + "resolutionWidth": resolution_width, + "resolutionHeight": resolution_height, + "pixelAspect": pixel_aspect, + + # backward compatibility handles + "handles": handle_start, + "handleStart": handle_start, + "handleEnd": handle_end, + "step": 1, + "fps": root_node['fps'].value(), + + "currentFile": current_file, + "version": int(api.get_version_from_path(current_file)), + + "host": pyblish.api.current_host(), + "hostVersion": nuke.NUKE_VERSION_STRING + } + + context.data["scriptData"] = script_data + context.data.update(script_data) + + self.log.info('Context from Nuke script collected') diff --git a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py index 3db26096ae1..3a877fc194a 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/collect_gizmo.py @@ -2,25 +2,23 @@ import nuke -@pyblish.api.log class CollectGizmo(pyblish.api.InstancePlugin): """Collect Gizmo (group) node instance and its content """ order = pyblish.api.CollectorOrder + 0.22 - label = "Collect Gizmo (Group)" + label = "Collect Gizmo (group)" hosts = ["nuke"] families = ["gizmo"] def process(self, instance): - grpn = instance[0] + gizmo_node = instance.data["transientData"]["node"] # add family to familiess instance.data["families"].insert(0, instance.data["family"]) # make label nicer - instance.data["label"] = "{0} ({1} nodes)".format( - grpn.name(), len(instance) - 1) + instance.data["label"] = gizmo_node.name() # Get frame range handle_start = instance.context.data["handleStart"] @@ -46,5 +44,4 @@ def process(self, instance): "frameStart": first_frame, "frameEnd": last_frame }) - self.log.info("Gizmo content collected: `{}`".format(instance[:])) self.log.info("Gizmo instance collected: `{}`".format(instance)) diff --git a/openpype/hosts/nuke/plugins/publish/collect_instance_data.py b/openpype/hosts/nuke/plugins/publish/collect_instance_data.py new file mode 100644 index 00000000000..3908aef4bcc --- /dev/null +++ b/openpype/hosts/nuke/plugins/publish/collect_instance_data.py @@ -0,0 +1,44 @@ +import nuke +import pyblish.api + + +class CollectInstanceData(pyblish.api.InstancePlugin): + """Collect all nodes with Avalon knob.""" + + order = pyblish.api.CollectorOrder - 0.49 + label = "Collect Instance Data" + hosts = ["nuke", "nukeassist"] + + # presets + sync_workfile_version_on_families = [] + + def process(self, instance): + family = instance.data["family"] + + # Get format + root = nuke.root() + format_ = root['format'].value() + resolution_width = format_.width() + resolution_height = format_.height() + pixel_aspect = format_.pixelAspect() + + # sync workfile version + if family in self.sync_workfile_version_on_families: + self.log.debug( + "Syncing version with workfile for '{}'".format( + family + ) + ) + # get version to instance for integration + instance.data['version'] = instance.context.data['version'] + + instance.data.update({ + "step": 1, + "fps": root['fps'].value(), + "resolutionWidth": resolution_width, + "resolutionHeight": resolution_height, + "pixelAspect": pixel_aspect + + }) + self.log.debug("Collected instance: {}".format( + instance.data)) diff --git a/openpype/hosts/nuke/plugins/publish/collect_model.py b/openpype/hosts/nuke/plugins/publish/collect_model.py index 5fca240553a..9da056052be 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_model.py +++ b/openpype/hosts/nuke/plugins/publish/collect_model.py @@ -2,7 +2,6 @@ import nuke -@pyblish.api.log class CollectModel(pyblish.api.InstancePlugin): """Collect Model node instance and its content """ @@ -14,12 +13,12 @@ class CollectModel(pyblish.api.InstancePlugin): def process(self, instance): - grpn = instance[0] + geo_node = instance.data["transientData"]["node"] # add family to familiess instance.data["families"].insert(0, instance.data["family"]) # make label nicer - instance.data["label"] = grpn.name() + instance.data["label"] = geo_node.name() # Get frame range handle_start = instance.context.data["handleStart"] @@ -45,5 +44,4 @@ def process(self, instance): "frameStart": first_frame, "frameEnd": last_frame }) - self.log.info("Model content collected: `{}`".format(instance[:])) self.log.info("Model instance collected: `{}`".format(instance)) diff --git a/openpype/hosts/nuke/plugins/publish/collect_reads.py b/openpype/hosts/nuke/plugins/publish/collect_reads.py index b79d9646d59..a1144fbcc31 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_reads.py +++ b/openpype/hosts/nuke/plugins/publish/collect_reads.py @@ -2,12 +2,10 @@ import re import nuke import pyblish.api - from openpype.client import get_asset_by_name from openpype.pipeline import legacy_io -@pyblish.api.log class CollectNukeReads(pyblish.api.InstancePlugin): """Collect all read nodes.""" @@ -17,6 +15,8 @@ class CollectNukeReads(pyblish.api.InstancePlugin): families = ["source"] def process(self, instance): + node = instance.data["transientData"]["node"] + project_name = legacy_io.active_project() asset_name = legacy_io.Session["AVALON_ASSET"] asset_doc = get_asset_by_name(project_name, asset_name) @@ -25,7 +25,6 @@ def process(self, instance): self.log.debug("checking instance: {}".format(instance)) - node = instance[0] if node.Class() != "Read": return @@ -99,10 +98,7 @@ def process(self, instance): } instance.data["representations"].append(representation) - transfer = False - if "publish" in node.knobs(): - transfer = node["publish"] - + transfer = node["publish"] if "publish" in node.knobs() else False instance.data['transfer'] = transfer # Add version data to instance diff --git a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py index bfe32d8fd1b..57010876977 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_slate_node.py +++ b/openpype/hosts/nuke/plugins/publish/collect_slate_node.py @@ -8,10 +8,10 @@ class CollectSlate(pyblish.api.InstancePlugin): order = pyblish.api.CollectorOrder + 0.09 label = "Collect Slate Node" hosts = ["nuke"] - families = ["render", "render.local", "render.farm"] + families = ["render"] def process(self, instance): - node = instance[0] + node = instance.data["transientData"]["node"] slate = next((n for n in nuke.allNodes() if "slate" in n.name().lower() @@ -35,7 +35,6 @@ def process(self, instance): instance.data["slateNode"] = slate_node instance.data["slate"] = True instance.data["families"].append("slate") - instance.data["versionData"]["families"].append("slate") self.log.info( "Slate node is in node graph: `{}`".format(slate.name())) self.log.debug( diff --git a/openpype/hosts/nuke/plugins/publish/collect_workfile.py b/openpype/hosts/nuke/plugins/publish/collect_workfile.py new file mode 100644 index 00000000000..852042e6e95 --- /dev/null +++ b/openpype/hosts/nuke/plugins/publish/collect_workfile.py @@ -0,0 +1,40 @@ +import os +import nuke +import pyblish.api + + +class CollectWorkfile(pyblish.api.InstancePlugin): + """Collect current script for publish.""" + + order = pyblish.api.CollectorOrder + label = "Collect Workfile" + hosts = ['nuke'] + families = ["workfile"] + + def process(self, instance): # sourcery skip: avoid-builtin-shadow + + script_data = instance.context.data["scriptData"] + current_file = os.path.normpath(nuke.root().name()) + + # creating instances per write node + staging_dir = os.path.dirname(current_file) + base_name = os.path.basename(current_file) + + # creating representation + representation = { + 'name': 'nk', + 'ext': 'nk', + 'files': base_name, + "stagingDir": staging_dir, + } + + # creating instance data + instance.data.update({ + "name": base_name, + "representations": [representation] + }) + + # adding basic script data + instance.data.update(script_data) + + self.log.info("Collect script version") diff --git a/openpype/hosts/nuke/plugins/publish/collect_writes.py b/openpype/hosts/nuke/plugins/publish/collect_writes.py new file mode 100644 index 00000000000..3054e5a30c5 --- /dev/null +++ b/openpype/hosts/nuke/plugins/publish/collect_writes.py @@ -0,0 +1,186 @@ +import os +from pprint import pformat +import nuke +import pyblish.api +from openpype.hosts.nuke import api as napi + + +class CollectNukeWrites(pyblish.api.InstancePlugin): + """Collect all write nodes.""" + + order = pyblish.api.CollectorOrder - 0.48 + label = "Collect Writes" + hosts = ["nuke", "nukeassist"] + families = ["render", "prerender", "image"] + + def process(self, instance): + self.log.debug(pformat(instance.data)) + creator_attributes = instance.data["creator_attributes"] + instance.data.update(creator_attributes) + + group_node = instance.data["transientData"]["node"] + 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) + ) + if instance.data.get("review"): + instance.data["families"].append("review") + + child_nodes = napi.get_instance_group_node_childs(instance) + instance.data["transientData"]["childNodes"] = child_nodes + + write_node = None + for x in child_nodes: + if x.Class() == "Write": + write_node = x + + if write_node is None: + self.log.warning( + "Created node '{}' is missing write node!".format( + group_node.name() + ) + ) + return + + instance.data["writeNode"] = write_node + self.log.debug("checking instance: {}".format(instance)) + + # Determine defined file type + ext = write_node["file_type"].value() + + # Get frame range + handle_start = instance.context.data["handleStart"] + handle_end = instance.context.data["handleEnd"] + first_frame = int(nuke.root()["first_frame"].getValue()) + last_frame = int(nuke.root()["last_frame"].getValue()) + frame_length = int(last_frame - first_frame + 1) + + if write_node["use_limit"].getValue(): + first_frame = int(write_node["first"].getValue()) + last_frame = int(write_node["last"].getValue()) + + write_file_path = nuke.filename(write_node) + output_dir = os.path.dirname(write_file_path) + + self.log.debug('output dir: {}'.format(output_dir)) + + if render_target == "frames": + representation = { + 'name': ext, + 'ext': ext, + "stagingDir": output_dir, + "tags": [] + } + + # get file path knob + node_file_knob = write_node["file"] + # list file paths based on input frames + expected_paths = list(sorted({ + node_file_knob.evaluate(frame) + for frame in range(first_frame, last_frame + 1) + })) + + # convert only to base names + expected_filenames = [ + os.path.basename(filepath) + for filepath in expected_paths + ] + + # make sure files are existing at folder + collected_frames = [ + filename + for filename in os.listdir(output_dir) + if filename in expected_filenames + ] + + if collected_frames: + collected_frames_len = len(collected_frames) + frame_start_str = "%0{}d".format( + len(str(last_frame))) % first_frame + representation['frameStart'] = frame_start_str + + # in case slate is expected and not yet rendered + self.log.debug("_ frame_length: {}".format(frame_length)) + self.log.debug("_ collected_frames_len: {}".format( + collected_frames_len)) + + # this will only run if slate frame is not already + # rendered from previews publishes + if ( + "slate" in families + and frame_length == collected_frames_len + and family == "render" + ): + frame_slate_str = ( + "{{:0{}d}}".format(len(str(last_frame))) + ).format(first_frame - 1) + + slate_frame = collected_frames[0].replace( + frame_start_str, frame_slate_str) + collected_frames.insert(0, slate_frame) + + if collected_frames_len == 1: + representation['files'] = collected_frames.pop() + else: + representation['files'] = collected_frames + + instance.data["representations"].append(representation) + self.log.info("Publishing rendered frames ...") + + elif render_target == "farm": + farm_priority = creator_attributes.get("farm_priority") + farm_chunk = creator_attributes.get("farm_chunk") + farm_concurency = creator_attributes.get("farm_concurency") + instance.data.update({ + "deadlineChunkSize": farm_chunk or 1, + "deadlinePriority": farm_priority or 50, + "deadlineConcurrentTasks": farm_concurency or 0 + }) + # Farm rendering + instance.data["transfer"] = False + instance.data["farm"] = True + self.log.info("Farm rendering ON ...") + + # get colorspace and add to version data + colorspace = napi.get_colorspace_from_node(write_node) + version_data = { + "colorspace": colorspace + } + + instance.data.update({ + "versionData": version_data, + "path": write_file_path, + "outputDir": output_dir, + "ext": ext, + "colorspace": colorspace + }) + + if family == "render": + instance.data.update({ + "handleStart": handle_start, + "handleEnd": handle_end, + "frameStart": first_frame + handle_start, + "frameEnd": last_frame - handle_end, + "frameStartHandle": first_frame, + "frameEndHandle": last_frame, + }) + else: + instance.data.update({ + "handleStart": 0, + "handleEnd": 0, + "frameStart": first_frame, + "frameEnd": last_frame, + "frameStartHandle": first_frame, + "frameEndHandle": last_frame, + }) + + # make sure rendered sequence on farm will + # be used for exctract review + if not instance.data["review"]: + instance.data["useSequenceForReview"] = False + + self.log.debug("instance.data: {}".format(pformat(instance.data))) diff --git a/openpype/hosts/nuke/plugins/publish/extract_backdrop.py b/openpype/hosts/nuke/plugins/publish/extract_backdrop.py index d1e5c4cc5ab..5166fa4b2c0 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_backdrop.py +++ b/openpype/hosts/nuke/plugins/publish/extract_backdrop.py @@ -26,8 +26,14 @@ class ExtractBackdropNode(publish.Extractor): families = ["nukenodes"] def process(self, instance): - tmp_nodes = list() - nodes = instance[1:] + tmp_nodes = [] + child_nodes = instance.data["transientData"]["childNodes"] + # all connections outside of backdrop + connections_in = instance.data["transientData"]["nodeConnectionsIn"] + connections_out = instance.data["transientData"]["nodeConnectionsOut"] + self.log.debug("_ connections_in: `{}`".format(connections_in)) + self.log.debug("_ connections_out: `{}`".format(connections_out)) + # Define extract output file path stagingdir = self.staging_dir(instance) filename = "{0}.nk".format(instance.name) @@ -35,20 +41,14 @@ def process(self, instance): # maintain selection with maintained_selection(): - # all connections outside of backdrop - connections_in = instance.data["nodeConnectionsIn"] - connections_out = instance.data["nodeConnectionsOut"] - self.log.debug("_ connections_in: `{}`".format(connections_in)) - self.log.debug("_ connections_out: `{}`".format(connections_out)) - - # create input nodes and name them as passing node (*_INP) + # create input child_nodes and name them as passing node (*_INP) for n, inputs in connections_in.items(): for i, input in inputs: inpn = nuke.createNode("Input") inpn["name"].setValue("{}_{}_INP".format(n.name(), i)) n.setInput(i, inpn) inpn.setXYpos(input.xpos(), input.ypos()) - nodes.append(inpn) + child_nodes.append(inpn) tmp_nodes.append(inpn) reset_selection() @@ -63,13 +63,13 @@ def process(self, instance): if d.name() in n.name()), 0), opn) opn.setInput(0, n) opn.autoplace() - nodes.append(opn) + child_nodes.append(opn) tmp_nodes.append(opn) reset_selection() - # select nodes to copy + # select child_nodes to copy reset_selection() - select_nodes(nodes) + select_nodes(child_nodes) # create tmp nk file # save file to the path nuke.nodeCopy(path) @@ -104,6 +104,3 @@ def process(self, instance): self.log.info("Extracted instance '{}' to: {}".format( instance.name, path)) - - self.log.info("Data {}".format( - instance.data)) diff --git a/openpype/hosts/nuke/plugins/publish/extract_camera.py b/openpype/hosts/nuke/plugins/publish/extract_camera.py index b751bfab039..4286f71e834 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_camera.py +++ b/openpype/hosts/nuke/plugins/publish/extract_camera.py @@ -28,6 +28,7 @@ class ExtractCamera(publish.Extractor): ] def process(self, instance): + camera_node = instance.data["transientData"]["node"] handle_start = instance.context.data["handleStart"] handle_end = instance.context.data["handleEnd"] first_frame = int(nuke.root()["first_frame"].getValue()) @@ -38,7 +39,7 @@ def process(self, instance): self.log.info("instance.data: `{}`".format( pformat(instance.data))) - rm_nodes = list() + rm_nodes = [] self.log.info("Crating additional nodes") subset = instance.data["subset"] staging_dir = self.staging_dir(instance) @@ -58,7 +59,7 @@ def process(self, instance): with maintained_selection(): # bake camera with axeses onto word coordinate XYZ rm_n = bakeCameraWithAxeses( - nuke.toNode(instance.data["name"]), output_range) + camera_node, output_range) rm_nodes.append(rm_n) # create scene node diff --git a/openpype/hosts/nuke/plugins/publish/extract_gizmo.py b/openpype/hosts/nuke/plugins/publish/extract_gizmo.py index 3047ad67242..b0b1a9f7b78 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_gizmo.py +++ b/openpype/hosts/nuke/plugins/publish/extract_gizmo.py @@ -19,13 +19,14 @@ class ExtractGizmo(publish.Extractor): """ order = pyblish.api.ExtractorOrder - label = "Extract Gizmo (Group)" + label = "Extract Gizmo (group)" hosts = ["nuke"] families = ["gizmo"] def process(self, instance): - tmp_nodes = list() - orig_grpn = instance[0] + tmp_nodes = [] + orig_grpn = instance.data["transientData"]["node"] + # Define extract output file path stagingdir = self.staging_dir(instance) filename = "{0}.nk".format(instance.name) @@ -54,15 +55,6 @@ def process(self, instance): # convert gizmos to groups pnutils.bake_gizmos_recursively(copy_grpn) - # remove avalonknobs - knobs = copy_grpn.knobs() - avalon_knobs = [k for k in knobs.keys() - for ak in ["avalon:", "ak:"] - if ak in k] - avalon_knobs.append("publish") - for ak in avalon_knobs: - copy_grpn.removeKnob(knobs[ak]) - # add to temporary nodes tmp_nodes.append(copy_grpn) diff --git a/openpype/hosts/nuke/plugins/publish/extract_model.py b/openpype/hosts/nuke/plugins/publish/extract_model.py index d82cb3110b7..814d4041375 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_model.py +++ b/openpype/hosts/nuke/plugins/publish/extract_model.py @@ -36,8 +36,9 @@ def process(self, instance): self.log.info("instance.data: `{}`".format( pformat(instance.data))) - rm_nodes = list() - model_node = instance[0] + rm_nodes = [] + model_node = instance.data["transientData"]["node"] + self.log.info("Crating additional nodes") subset = instance.data["subset"] staging_dir = self.staging_dir(instance) diff --git a/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py b/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py index eb9bc0b4290..e66cfd9018e 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py +++ b/openpype/hosts/nuke/plugins/publish/extract_ouput_node.py @@ -16,13 +16,17 @@ class CreateOutputNode(pyblish.api.ContextPlugin): def process(self, context): # capture selection state with maintained_selection(): - active_node = [node for inst in context - for node in inst - if "ak:family" in node.knobs()] + + active_node = [ + inst.data.get("transientData", {}).get("node") + for inst in context + if inst.data.get("transientData", {}).get("node") + if inst.data.get( + "transientData", {}).get("node").Class() != "Root" + ] if active_node: - self.log.info(active_node) - active_node = active_node[0] + active_node = active_node.pop() self.log.info(active_node) active_node['selected'].setValue(True) diff --git a/openpype/hosts/nuke/plugins/publish/extract_render_local.py b/openpype/hosts/nuke/plugins/publish/extract_render_local.py index 843d5887866..811b2d4ffbb 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_render_local.py +++ b/openpype/hosts/nuke/plugins/publish/extract_render_local.py @@ -23,9 +23,13 @@ class NukeRenderLocal(publish.Extractor): def process(self, instance): families = instance.data["families"] + child_nodes = ( + instance.data.get("transientData", {}).get("childNodes") + or instance + ) node = None - for x in instance: + for x in child_nodes: if x.Class() == "Write": node = x diff --git a/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py b/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py index 19eae9638b9..a1a0e241c07 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/nuke/plugins/publish/extract_thumbnail.py @@ -4,11 +4,7 @@ import pyblish.api from openpype.pipeline import publish -from openpype.hosts.nuke.api import ( - maintained_selection, - get_view_process_node -) - +from openpype.hosts.nuke import api as napi if sys.version_info[0] >= 3: unicode = str @@ -38,7 +34,7 @@ def process(self, instance): if "render.farm" in instance.data["families"]: return - with maintained_selection(): + with napi.maintained_selection(): self.log.debug("instance: {}".format(instance)) self.log.debug("instance.data[families]: {}".format( instance.data["families"])) @@ -69,7 +65,7 @@ def render_thumbnail(self, instance, output_name=None, **kwargs): bake_viewer_input_process_node = kwargs[ "bake_viewer_input_process"] - node = instance[0] # group node + node = instance.data["transientData"]["node"] # group node self.log.info("Creating staging dir...") if "representations" not in instance.data: @@ -144,7 +140,7 @@ def render_thumbnail(self, instance, output_name=None, **kwargs): if bake_viewer_process: if bake_viewer_input_process_node: # get input process and connect it to baking - ipn = get_view_process_node() + ipn = napi.get_view_process_node() if ipn is not None: ipn.setInput(0, previous_node) previous_node = ipn diff --git a/openpype/hosts/nuke/plugins/publish/help/validate_asset_name.xml b/openpype/hosts/nuke/plugins/publish/help/validate_asset_name.xml index 1097909a5fa..0422917e9c4 100644 --- a/openpype/hosts/nuke/plugins/publish/help/validate_asset_name.xml +++ b/openpype/hosts/nuke/plugins/publish/help/validate_asset_name.xml @@ -1,7 +1,7 @@