From 55dab6dc0c01cddf7b920e363e554e0439f78875 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 23 Nov 2023 19:29:39 +0800 Subject: [PATCH 1/3] add loader for redshift proxy family(contributed by big Roy) --- .../plugins/load/load_redshift_proxy.py | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 openpype/hosts/houdini/plugins/load/load_redshift_proxy.py diff --git a/openpype/hosts/houdini/plugins/load/load_redshift_proxy.py b/openpype/hosts/houdini/plugins/load/load_redshift_proxy.py new file mode 100644 index 0000000000..914154be06 --- /dev/null +++ b/openpype/hosts/houdini/plugins/load/load_redshift_proxy.py @@ -0,0 +1,131 @@ +import os +from openpype.pipeline import ( + load, + get_representation_path, +) +from openpype.hosts.houdini.api import pipeline + +import clique +import hou + + +class RedshiftProxyLoader(load.LoaderPlugin): + """Load Redshift Proxy""" + + families = ["redshiftproxy"] + label = "Load Redshift Proxy" + representations = ["rs"] + order = -10 + icon = "code-fork" + color = "orange" + + def load(self, context, name=None, namespace=None, data=None): + + # Get the root node + obj = hou.node("/obj") + + # Define node name + namespace = namespace if namespace else context["asset"]["name"] + node_name = "{}_{}".format(namespace, name) if namespace else name + + # Create a new geo node + container = obj.createNode("geo", node_name=node_name) + + # Check whether the Redshift parameters exist - if not, then likely + # redshift is not set up or initialized correctly + if not container.parm("RS_objprop_proxy_enable"): + container.destroy() + raise RuntimeError("Unable to initialize geo node with Redshift " + "attributes. Make sure you have the Redshift " + "plug-in set up correctly for Houdini.") + + # Enable by default + container.setParms({ + "RS_objprop_proxy_enable": True, + "RS_objprop_proxy_file": self.format_path(self.fname) + }) + + # Remove the file node, it only loads static meshes + # Houdini 17 has removed the file node from the geo node + file_node = container.node("file1") + if file_node: + file_node.destroy() + + # Add this stub node inside so it previews ok + proxy_sop = container.createNode("redshift_proxySOP", + node_name=node_name) + proxy_sop.setDisplayFlag(True) + + nodes = [container, proxy_sop] + + self[:] = nodes + + return pipeline.containerise( + node_name, + namespace, + nodes, + context, + self.__class__.__name__, + suffix="", + ) + + def update(self, container, representation): + + # Update the file path + file_path = get_representation_path(representation) + + node = container["node"] + node.setParms({ + "RS_objprop_proxy_file": self.format_path(file_path) + }) + + # Update attribute + node.setParms({"representation": str(representation["_id"])}) + + def remove(self, container): + + node = container["node"] + node.destroy() + + def format_path(self, path): + """Format using $F{padding} token if sequence, otherwise just path.""" + + # Find all frames in the folder + ext = ".rs" + folder = os.path.dirname(path) + frames = [f for f in os.listdir(folder) if f.endswith(ext)] + + # Get the collection of frames to detect frame padding + patterns = [clique.PATTERNS["frames"]] + collections, remainder = clique.assemble(frames, + minimum_items=1, + patterns=patterns) + self.log.debug("Detected collections: {}".format(collections)) + self.log.debug("Detected remainder: {}".format(remainder)) + + if not collections and remainder: + if len(remainder) != 1: + raise ValueError("Frames not correctly detected " + "in: {}".format(remainder)) + + # A single frame without frame range detected + return os.path.normpath(path).replace("\\", "/") + + # Frames detected with a valid "frame" number pattern + # Then we don't want to have any remainder files found + assert len(collections) == 1 and not remainder + collection = collections[0] + + num_frames = len(collection.indexes) + if num_frames == 1: + # Return the input path without dynamic $F variable + result = path + else: + # More than a single frame detected - use $F{padding} + fname = "{}$F{}{}".format(collection.head, + collection.padding, + collection.tail) + result = os.path.join(folder, fname) + + # Format file name, Houdini only wants forward slashes + return os.path.normpath(result).replace("\\", "/") From 323d2409d349cbb5339457661d0ba4211f256722 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 24 Nov 2023 17:14:49 +0800 Subject: [PATCH 2/3] unified the code style of the loader with other loaders such as ass and bgeo loader --- .../plugins/load/load_redshift_proxy.py | 64 +++++++------------ 1 file changed, 22 insertions(+), 42 deletions(-) diff --git a/openpype/hosts/houdini/plugins/load/load_redshift_proxy.py b/openpype/hosts/houdini/plugins/load/load_redshift_proxy.py index 914154be06..8a3cc04eab 100644 --- a/openpype/hosts/houdini/plugins/load/load_redshift_proxy.py +++ b/openpype/hosts/houdini/plugins/load/load_redshift_proxy.py @@ -5,7 +5,6 @@ from openpype.pipeline import ( ) from openpype.hosts.houdini.api import pipeline -import clique import hou @@ -42,7 +41,8 @@ class RedshiftProxyLoader(load.LoaderPlugin): # Enable by default container.setParms({ "RS_objprop_proxy_enable": True, - "RS_objprop_proxy_file": self.format_path(self.fname) + "RS_objprop_proxy_file": self.format_path( + self.fname, context["representation"]) }) # Remove the file node, it only loads static meshes @@ -76,7 +76,8 @@ class RedshiftProxyLoader(load.LoaderPlugin): node = container["node"] node.setParms({ - "RS_objprop_proxy_file": self.format_path(file_path) + "RS_objprop_proxy_file": self.format_path( + file_path, representation) }) # Update attribute @@ -87,45 +88,24 @@ class RedshiftProxyLoader(load.LoaderPlugin): node = container["node"] node.destroy() - def format_path(self, path): - """Format using $F{padding} token if sequence, otherwise just path.""" + @staticmethod + def format_path(path, representation): + """Format file path correctly for single redshift proxy + or redshift proxy sequence.""" + import re + if not os.path.exists(path): + raise RuntimeError("Path does not exist: %s" % path) - # Find all frames in the folder - ext = ".rs" - folder = os.path.dirname(path) - frames = [f for f in os.listdir(folder) if f.endswith(ext)] - - # Get the collection of frames to detect frame padding - patterns = [clique.PATTERNS["frames"]] - collections, remainder = clique.assemble(frames, - minimum_items=1, - patterns=patterns) - self.log.debug("Detected collections: {}".format(collections)) - self.log.debug("Detected remainder: {}".format(remainder)) - - if not collections and remainder: - if len(remainder) != 1: - raise ValueError("Frames not correctly detected " - "in: {}".format(remainder)) - - # A single frame without frame range detected - return os.path.normpath(path).replace("\\", "/") - - # Frames detected with a valid "frame" number pattern - # Then we don't want to have any remainder files found - assert len(collections) == 1 and not remainder - collection = collections[0] - - num_frames = len(collection.indexes) - if num_frames == 1: - # Return the input path without dynamic $F variable - result = path + is_sequence = bool(representation["context"].get("frame")) + # The path is either a single file or sequence in a folder. + if not is_sequence: + filename = path else: - # More than a single frame detected - use $F{padding} - fname = "{}$F{}{}".format(collection.head, - collection.padding, - collection.tail) - result = os.path.join(folder, fname) + filename = re.sub(r"(.*)\.(\d+)\.(rs.*)", "\\1.$F4.\\3", path) - # Format file name, Houdini only wants forward slashes - return os.path.normpath(result).replace("\\", "/") + filename = os.path.join(path, filename) + + filename = os.path.normpath(filename) + filename = filename.replace("\\", "/") + + return filename From 9ae1e7950915adab798840520455618c32f18cf0 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 24 Nov 2023 18:35:07 +0800 Subject: [PATCH 3/3] replace deprecated self.fname by self.filepath_from_context --- .../plugins/load/load_redshift_proxy.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/openpype/hosts/houdini/plugins/load/load_redshift_proxy.py b/openpype/hosts/houdini/plugins/load/load_redshift_proxy.py index 8a3cc04eab..efd7c6d0ca 100644 --- a/openpype/hosts/houdini/plugins/load/load_redshift_proxy.py +++ b/openpype/hosts/houdini/plugins/load/load_redshift_proxy.py @@ -1,9 +1,11 @@ import os +import re from openpype.pipeline import ( load, get_representation_path, ) from openpype.hosts.houdini.api import pipeline +from openpype.pipeline.load import LoadError import hou @@ -34,15 +36,16 @@ class RedshiftProxyLoader(load.LoaderPlugin): # redshift is not set up or initialized correctly if not container.parm("RS_objprop_proxy_enable"): container.destroy() - raise RuntimeError("Unable to initialize geo node with Redshift " - "attributes. Make sure you have the Redshift " - "plug-in set up correctly for Houdini.") + raise LoadError("Unable to initialize geo node with Redshift " + "attributes. Make sure you have the Redshift " + "plug-in set up correctly for Houdini.") # Enable by default container.setParms({ "RS_objprop_proxy_enable": True, "RS_objprop_proxy_file": self.format_path( - self.fname, context["representation"]) + self.filepath_from_context(context), + context["representation"]) }) # Remove the file node, it only loads static meshes @@ -92,18 +95,16 @@ class RedshiftProxyLoader(load.LoaderPlugin): def format_path(path, representation): """Format file path correctly for single redshift proxy or redshift proxy sequence.""" - import re if not os.path.exists(path): raise RuntimeError("Path does not exist: %s" % path) is_sequence = bool(representation["context"].get("frame")) # The path is either a single file or sequence in a folder. - if not is_sequence: - filename = path - else: + if is_sequence: filename = re.sub(r"(.*)\.(\d+)\.(rs.*)", "\\1.$F4.\\3", path) - filename = os.path.join(path, filename) + else: + filename = path filename = os.path.normpath(filename) filename = filename.replace("\\", "/")