From 822fa2c745132861b97d64a7b60f51807af7e83c Mon Sep 17 00:00:00 2001 From: wikoreman Date: Thu, 13 Sep 2018 10:50:58 +0200 Subject: [PATCH 01/26] Added collect animation plugin --- .../houdini/publish/collection_animation.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 colorbleed/plugins/houdini/publish/collection_animation.py diff --git a/colorbleed/plugins/houdini/publish/collection_animation.py b/colorbleed/plugins/houdini/publish/collection_animation.py new file mode 100644 index 0000000000..a959d9d5c6 --- /dev/null +++ b/colorbleed/plugins/houdini/publish/collection_animation.py @@ -0,0 +1,30 @@ +import pyblish.api + + +class CollectAnimation(pyblish.api.InstancePlugin): + """Collect the animation data for the data base + + Data collected: + - start frame + - end frame + - nr of steps + + """ + + label = "Collect Animation" + families = ["colorbleed.pointcache"] + + def process(self, instance): + + node = instance[0] + + # Get animation parameters for data + parameters = {"f1": "startFrame", + "f2": "endFrame", + "f3": "steps"} + + data = {} + for par, translation in parameters.items(): + data[translation] = node.parm(par).eval() + + instance.data.update(data) From b494ce0041eecf92eb270d204276933ccaf0f845 Mon Sep 17 00:00:00 2001 From: wikoreman Date: Thu, 13 Sep 2018 10:54:39 +0200 Subject: [PATCH 02/26] Allow node settings to dictate output settings --- colorbleed/plugins/houdini/publish/extract_alembic.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/colorbleed/plugins/houdini/publish/extract_alembic.py b/colorbleed/plugins/houdini/publish/extract_alembic.py index 098020b905..f8ae69a635 100644 --- a/colorbleed/plugins/houdini/publish/extract_alembic.py +++ b/colorbleed/plugins/houdini/publish/extract_alembic.py @@ -19,15 +19,14 @@ class ExtractAlembic(colorbleed.api.Extractor): file_name = "{}.abc".format(instance.data["subset"]) tmp_filepath = os.path.join(staging_dir, file_name) - start_frame = float(instance.data["startFrame"]) - end_frame = float(instance.data["endFrame"]) - ropnode = instance[0] - attributes = {"filename": tmp_filepath, - "trange": 2} + # Set file name to staging dir + file name + attributes = {"filename": tmp_filepath} + + # We run the render with the input settings set by the user with lib.attribute_values(ropnode, attributes): - ropnode.render(frame_range=(start_frame, end_frame, 1)) + ropnode.render() if "files" not in instance.data: instance.data["files"] = [] From 940e0b3458dc65ff4f1d271791bb20b32c0a0ae5 Mon Sep 17 00:00:00 2001 From: wikoreman Date: Thu, 13 Sep 2018 10:56:31 +0200 Subject: [PATCH 03/26] Set extra parameters --- .../plugins/houdini/create/create_pointcache.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/colorbleed/plugins/houdini/create/create_pointcache.py b/colorbleed/plugins/houdini/create/create_pointcache.py index 93cd83a6b3..4995912d8e 100644 --- a/colorbleed/plugins/houdini/create/create_pointcache.py +++ b/colorbleed/plugins/houdini/create/create_pointcache.py @@ -1,7 +1,5 @@ from collections import OrderedDict -import hou - from avalon import houdini @@ -22,9 +20,9 @@ class CreatePointCache(houdini.Creator): # Set node type to create for output data["node_type"] = "alembic" - # Collect animation data for point cache exporting - start, end = hou.playbar.timelineRange() - data["startFrame"] = start - data["endFrame"] = end - self.data = data + + def process(self): + instance = super(CreatePointCache, self).process() + instance.setParms({"build_from_path": 1, + "path_attrib": "path"}) From 559e910190c6302da292a80af485d2f8760cc39c Mon Sep 17 00:00:00 2001 From: wikoreman Date: Thu, 13 Sep 2018 15:31:06 +0200 Subject: [PATCH 04/26] Improved flexibility, assume sop path points to output node --- .../houdini/publish/validate_outnode_exists.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/colorbleed/plugins/houdini/publish/validate_outnode_exists.py b/colorbleed/plugins/houdini/publish/validate_outnode_exists.py index 479579a8f0..011a1f63e7 100644 --- a/colorbleed/plugins/houdini/publish/validate_outnode_exists.py +++ b/colorbleed/plugins/houdini/publish/validate_outnode_exists.py @@ -29,13 +29,21 @@ class ValidatOutputNodeExists(pyblish.api.InstancePlugin): result = set() node = instance[0] - sop_path = node.parm("sop_path").eval() - if not sop_path.endswith("OUT"): - cls.log.error("SOP Path does not end path at output node") - result.add(node.path()) + if node.type().name() == "alembic": + soppath_parm = "sop_path" + else: + # Fall back to geometry node + soppath_parm = "soppath" - if hou.node(sop_path) is None: + sop_path = node.parm(soppath_parm).eval() + output_node = hou.node(sop_path) + + if output_node is None: cls.log.error("Node at '%s' does not exist" % sop_path) result.add(node.path()) + if output_node.type().name() != "output": + cls.log.error("SOP Path does not end path at output node") + result.add(node.path()) + return result From e9ec64b7ac9f5746ef5cdad8992744ff5ed0a2cb Mon Sep 17 00:00:00 2001 From: wikoreman Date: Thu, 13 Sep 2018 16:05:00 +0200 Subject: [PATCH 05/26] Added instnace for vdb --- .../houdini/create/create_vbd_cache.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 colorbleed/plugins/houdini/create/create_vbd_cache.py diff --git a/colorbleed/plugins/houdini/create/create_vbd_cache.py b/colorbleed/plugins/houdini/create/create_vbd_cache.py new file mode 100644 index 0000000000..0ba9431403 --- /dev/null +++ b/colorbleed/plugins/houdini/create/create_vbd_cache.py @@ -0,0 +1,23 @@ +from collections import OrderedDict + +from avalon import houdini + + +class CreateVDBCache(houdini.Creator): + """Alembic pointcache for animated data""" + + name = "vbdcache" + label = "VDB Cache" + family = "colorbleed.vbdcache" + icon = "cloud" + + def __init__(self, *args, **kwargs): + super(CreateVDBCache, self).__init__(*args, **kwargs) + + # create an ordered dict with the existing data first + data = OrderedDict(**self.data) + + # Set node type to create for output + data["node_type"] = "geometry" + + self.data = data From be890bf95af61ee0481a0e8320e8b1bf7431eca9 Mon Sep 17 00:00:00 2001 From: wikoreman Date: Thu, 13 Sep 2018 16:51:45 +0200 Subject: [PATCH 06/26] Refactored plugins to match Creator logic --- .../plugins/houdini/create/create_pointcache.py | 13 +++++++++++-- .../plugins/houdini/create/create_vbd_cache.py | 9 +++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/colorbleed/plugins/houdini/create/create_pointcache.py b/colorbleed/plugins/houdini/create/create_pointcache.py index 4995912d8e..9169135245 100644 --- a/colorbleed/plugins/houdini/create/create_pointcache.py +++ b/colorbleed/plugins/houdini/create/create_pointcache.py @@ -24,5 +24,14 @@ class CreatePointCache(houdini.Creator): def process(self): instance = super(CreatePointCache, self).process() - instance.setParms({"build_from_path": 1, - "path_attrib": "path"}) + + parms = {"build_from_path": 1, + "path_attrib": "path", + "use_sop_path": True, + "filename": "$HIP/%s.abc" % self.name} + + if self.nodes: + node = self.nodes[0] + parms.update({"sop_path": "%s/OUT" % node.path()}) + + instance.setParms(parms) diff --git a/colorbleed/plugins/houdini/create/create_vbd_cache.py b/colorbleed/plugins/houdini/create/create_vbd_cache.py index 0ba9431403..c76ebd05c1 100644 --- a/colorbleed/plugins/houdini/create/create_vbd_cache.py +++ b/colorbleed/plugins/houdini/create/create_vbd_cache.py @@ -21,3 +21,12 @@ class CreateVDBCache(houdini.Creator): data["node_type"] = "geometry" self.data = data + + def process(self): + instance = super(CreateVDBCache, self).process() + + parms = {} + if self.nodes: + parms.update({"soppath": self.nodes[0].path()}) + + instance.setParms() From cb63ec54c572137c5a9ee9af13a5ebe0ebf031f6 Mon Sep 17 00:00:00 2001 From: wikoreman Date: Thu, 13 Sep 2018 16:52:55 +0200 Subject: [PATCH 07/26] Refactored class name --- colorbleed/plugins/houdini/publish/collect_current_file.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/colorbleed/plugins/houdini/publish/collect_current_file.py b/colorbleed/plugins/houdini/publish/collect_current_file.py index e8612bdc12..7852943b34 100644 --- a/colorbleed/plugins/houdini/publish/collect_current_file.py +++ b/colorbleed/plugins/houdini/publish/collect_current_file.py @@ -3,7 +3,7 @@ import hou import pyblish.api -class CollectMayaCurrentFile(pyblish.api.ContextPlugin): +class CollectHoudiniCurrentFile(pyblish.api.ContextPlugin): """Inject the current working file into context""" order = pyblish.api.CollectorOrder - 0.5 From 7e424816f97e41f3a89cedc177818e51d459c4e7 Mon Sep 17 00:00:00 2001 From: wikoreman Date: Fri, 14 Sep 2018 09:38:16 +0200 Subject: [PATCH 08/26] Removed staging dir to support large write cache --- .../plugins/houdini/publish/extract_alembic.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/colorbleed/plugins/houdini/publish/extract_alembic.py b/colorbleed/plugins/houdini/publish/extract_alembic.py index f8ae69a635..29450d0824 100644 --- a/colorbleed/plugins/houdini/publish/extract_alembic.py +++ b/colorbleed/plugins/houdini/publish/extract_alembic.py @@ -2,7 +2,6 @@ import os import pyblish.api import colorbleed.api -from colorbleed.houdini import lib class ExtractAlembic(colorbleed.api.Extractor): @@ -14,19 +13,14 @@ class ExtractAlembic(colorbleed.api.Extractor): def process(self, instance): - staging_dir = self.staging_dir(instance) - - file_name = "{}.abc".format(instance.data["subset"]) - tmp_filepath = os.path.join(staging_dir, file_name) - ropnode = instance[0] - # Set file name to staging dir + file name - attributes = {"filename": tmp_filepath} + # Get the filename from the filename parameter + # `.eval()` will make sure all tokens are resolved + file_name = os.path.basename(ropnode.parm("filename").eval()) - # We run the render with the input settings set by the user - with lib.attribute_values(ropnode, attributes): - ropnode.render() + # We run the render + ropnode.render() if "files" not in instance.data: instance.data["files"] = [] From 13aa727f5ab21afe8d4893100095a18404bdcdb2 Mon Sep 17 00:00:00 2001 From: wikoreman Date: Fri, 14 Sep 2018 09:39:29 +0200 Subject: [PATCH 09/26] Passed argument to setParm, added sop ouput --- colorbleed/plugins/houdini/create/create_vbd_cache.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/colorbleed/plugins/houdini/create/create_vbd_cache.py b/colorbleed/plugins/houdini/create/create_vbd_cache.py index c76ebd05c1..65cac4a7fd 100644 --- a/colorbleed/plugins/houdini/create/create_vbd_cache.py +++ b/colorbleed/plugins/houdini/create/create_vbd_cache.py @@ -25,8 +25,8 @@ class CreateVDBCache(houdini.Creator): def process(self): instance = super(CreateVDBCache, self).process() - parms = {} + parms = {"sopoutput": "$HIP/geo/%s.$F.vdb" % self.name} if self.nodes: parms.update({"soppath": self.nodes[0].path()}) - instance.setParms() + instance.setParms(parms) From 13f43f1925b023577711924790e685f14b7e75cf Mon Sep 17 00:00:00 2001 From: wikoreman Date: Fri, 14 Sep 2018 10:16:13 +0200 Subject: [PATCH 10/26] Added host and order --- .../plugins/houdini/publish/collection_animation.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/colorbleed/plugins/houdini/publish/collection_animation.py b/colorbleed/plugins/houdini/publish/collection_animation.py index a959d9d5c6..835e52eb68 100644 --- a/colorbleed/plugins/houdini/publish/collection_animation.py +++ b/colorbleed/plugins/houdini/publish/collection_animation.py @@ -11,8 +11,10 @@ class CollectAnimation(pyblish.api.InstancePlugin): """ - label = "Collect Animation" + order = pyblish.api.CollectorOrder families = ["colorbleed.pointcache"] + hosts = ["houdini"] + label = "Collect Animation" def process(self, instance): @@ -23,8 +25,7 @@ class CollectAnimation(pyblish.api.InstancePlugin): "f2": "endFrame", "f3": "steps"} - data = {} - for par, translation in parameters.items(): - data[translation] = node.parm(par).eval() + data = {name: node.parm(par).eval() for par, name in + parameters.items()} instance.data.update(data) From 61faa08752bc2507fe9f468be286f6cfa6629681 Mon Sep 17 00:00:00 2001 From: wikoreman Date: Fri, 14 Sep 2018 10:46:26 +0200 Subject: [PATCH 11/26] Fixed family name typo, added frame padding of 4 for frames --- colorbleed/plugins/houdini/create/create_vbd_cache.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/colorbleed/plugins/houdini/create/create_vbd_cache.py b/colorbleed/plugins/houdini/create/create_vbd_cache.py index 65cac4a7fd..b103a046fa 100644 --- a/colorbleed/plugins/houdini/create/create_vbd_cache.py +++ b/colorbleed/plugins/houdini/create/create_vbd_cache.py @@ -8,7 +8,7 @@ class CreateVDBCache(houdini.Creator): name = "vbdcache" label = "VDB Cache" - family = "colorbleed.vbdcache" + family = "colorbleed.vdbcache" icon = "cloud" def __init__(self, *args, **kwargs): @@ -25,7 +25,7 @@ class CreateVDBCache(houdini.Creator): def process(self): instance = super(CreateVDBCache, self).process() - parms = {"sopoutput": "$HIP/geo/%s.$F.vdb" % self.name} + parms = {"sopoutput": "$HIP/geo/%s.$F4.vdb" % self.name} if self.nodes: parms.update({"soppath": self.nodes[0].path()}) From 7d162aa5bb8727e70bdbc2f8ec3a551be6a51509 Mon Sep 17 00:00:00 2001 From: wikoreman Date: Fri, 14 Sep 2018 13:01:54 +0200 Subject: [PATCH 12/26] Check for animation data --- .../houdini/publish/collect_instances.py | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/colorbleed/plugins/houdini/publish/collect_instances.py b/colorbleed/plugins/houdini/publish/collect_instances.py index 5f77b9d805..0e5301a6a1 100644 --- a/colorbleed/plugins/houdini/publish/collect_instances.py +++ b/colorbleed/plugins/houdini/publish/collect_instances.py @@ -24,8 +24,8 @@ class CollectInstances(pyblish.api.ContextPlugin): """ + order = pyblish.api.CollectorOrder - 0.01 label = "Collect Instances" - order = pyblish.api.CollectorOrder hosts = ["houdini"] def process(self, context): @@ -51,7 +51,17 @@ class CollectInstances(pyblish.api.ContextPlugin): if "active" in data: data["publish"] = data["active"] - instance = context.create_instance(data.get("name", node.name())) + data.update(self.get_frame_data(node)) + + # Create nice name + # All nodes in the Outputs graph have the 'Valid Frame Range' + # attribute, we check here if any frames are set + label = data.get("name", node.name()) + if "startFrame" in data: + frames = "[{startFrame} - {endFrame}]".format(**data) + label = "{} {}".format(label, frames) + + instance = context.create_instance(label) instance[:] = [node] instance.data.update(data) @@ -66,3 +76,27 @@ class CollectInstances(pyblish.api.ContextPlugin): context[:] = sorted(context, key=sort_by_family) return context + + def get_frame_data(self, node): + """Get the frame data: start frame, end frame and steps + Args: + node(hou.Node) + + Returns: + dict + + """ + + data = {} + + if node.parm("trange") is None: + return data + + if node.parm("trange").eval() == 0: + return data + + data["startFrame"] = node.parm("f1").eval() + data["endFrame"] = node.parm("f2").eval() + data["steps"] = node.parm("f3").eval() + + return data From 4abee5618c16cf7a130df3b1070248557ae98e18 Mon Sep 17 00:00:00 2001 From: wikoreman Date: Fri, 14 Sep 2018 13:27:48 +0200 Subject: [PATCH 13/26] Collect currently set output of render node --- .../houdini/publish/collect_output_node.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 colorbleed/plugins/houdini/publish/collect_output_node.py diff --git a/colorbleed/plugins/houdini/publish/collect_output_node.py b/colorbleed/plugins/houdini/publish/collect_output_node.py new file mode 100644 index 0000000000..dbfe8a5890 --- /dev/null +++ b/colorbleed/plugins/houdini/publish/collect_output_node.py @@ -0,0 +1,27 @@ +import pyblish.api + + +class CollectOutputNode(pyblish.api.InstancePlugin): + """Collect the out node which of the instance""" + + order = pyblish.api.CollectorOrder + families = ["*"] + hosts = ["houdini"] + label = "Collect Output Node" + + def process(self, instance): + + import hou + + node = instance[0] + + # Get sop path + if node.type().name() == "alembic": + sop_path_parm = "sop_path" + else: + sop_path_parm = "soppath" + + sop_path = node.parm(sop_path_parm).eval() + out_node = hou.node(sop_path) + + instance.data["output_node"] = out_node From 7001766c93aafd61485c90f16ef2ea5e64887151 Mon Sep 17 00:00:00 2001 From: wikoreman Date: Fri, 14 Sep 2018 13:28:06 +0200 Subject: [PATCH 14/26] Generic checks for output node --- .../houdini/publish/validate_output_node.py | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 colorbleed/plugins/houdini/publish/validate_output_node.py diff --git a/colorbleed/plugins/houdini/publish/validate_output_node.py b/colorbleed/plugins/houdini/publish/validate_output_node.py new file mode 100644 index 0000000000..be7551cf0d --- /dev/null +++ b/colorbleed/plugins/houdini/publish/validate_output_node.py @@ -0,0 +1,43 @@ +import pyblish.api + + +class ValidateOutputNode(pyblish.api.InstancePlugin): + """Validate if output node: + - exists + - is of type 'output' + - has an input""" + + order = pyblish.api.ValidatorOrder + families = ["*"] + hosts = ["houdini"] + label = "Validate Output Node" + + def process(self, instance): + + invalid = self.get_invalid(instance) + if invalid: + raise RuntimeError("Output node(s) `%s` are incorrect" % invalid) + + @classmethod + def get_invalid(cls, instance): + + output_node = instance.data["output_node"] + + if output_node is None: + node = instance[0] + cls.log.error("Output node at '%s' does not exist, see source" % + node.path()) + + return node.path() + + # Check if type is correct + if output_node.type().name() != "output": + cls.log.error("Output node `%s` is not if type `output`" % + output_node.path()) + return output_node.path() + + # Check if node has incoming connections + if not output_node.inputConnections(): + cls.log.error("Output node `%s` has no incoming connections" + % output_node.path()) + return output_node.path() From c94d59994597d8aefd40620d7a3b7b003470f7e7 Mon Sep 17 00:00:00 2001 From: wikoreman Date: Fri, 14 Sep 2018 13:28:23 +0200 Subject: [PATCH 15/26] Check for vdb output --- .../houdini/publish/valiate_vdb_input_node.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 colorbleed/plugins/houdini/publish/valiate_vdb_input_node.py diff --git a/colorbleed/plugins/houdini/publish/valiate_vdb_input_node.py b/colorbleed/plugins/houdini/publish/valiate_vdb_input_node.py new file mode 100644 index 0000000000..25a8d86ce3 --- /dev/null +++ b/colorbleed/plugins/houdini/publish/valiate_vdb_input_node.py @@ -0,0 +1,47 @@ +import pyblish.api +import colorbleed.api + + +class ValidateVDBInputNode(pyblish.api.InstancePlugin): + """Validate that the node connected to the output node is of type VDB + + Regardless of the amount of VDBs create the output will need to have an + equal amount of VDBs, points, primitives and vertices + + A VDB is an inherited type of Prim, holds the following data: + - Primitives: 1 + - Points: 1 + - Vertices: 1 + - VDBs: 1 + + """ + + order = colorbleed.api.ValidateContentsOrder + 0.1 + families = ["colorbleed.vdbcache"] + hosts = ["houdini"] + label = "Validate Input Node (VDB)" + + def process(self, instance): + invalid = self.get_invalid(instance) + if invalid: + raise RuntimeError("Node connected to the output node is not" + "of type VDB!") + + @classmethod + def get_invalid(cls, instance): + + node = instance.data["output_node"] + + prims = node.geometry().prims() + nr_of_prims = len(prims) + + nr_of_points = len(node.geometry().points()) + if nr_of_points != nr_of_prims: + cls.log.error("The number of primitives and points do not match") + return [instance] + + for prim in prims: + # print(">>", prim.name()) + if prim.numVertices() != 1: + cls.log.error("Found primitive with more than 1 vertex!") + return [instance] From 925dcdf4bc2379648e7e03ecfb909809ce512667 Mon Sep 17 00:00:00 2001 From: wikoreman Date: Fri, 14 Sep 2018 13:28:50 +0200 Subject: [PATCH 16/26] Fixed typo --- colorbleed/plugins/houdini/publish/validate_mkpaths_toggled.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/colorbleed/plugins/houdini/publish/validate_mkpaths_toggled.py b/colorbleed/plugins/houdini/publish/validate_mkpaths_toggled.py index 8dcc6e0509..7e298ce952 100644 --- a/colorbleed/plugins/houdini/publish/validate_mkpaths_toggled.py +++ b/colorbleed/plugins/houdini/publish/validate_mkpaths_toggled.py @@ -2,7 +2,7 @@ import pyblish.api import colorbleed.api -class ValidatIntermediateDirectoriesChecked(pyblish.api.InstancePlugin): +class ValidateIntermediateDirectoriesChecked(pyblish.api.InstancePlugin): """Validate if node attribute Create intermediate Directories is turned on Rules: From c7584523e559627b6178d014565fc3f063b78cdf Mon Sep 17 00:00:00 2001 From: wikoreman Date: Fri, 14 Sep 2018 13:29:07 +0200 Subject: [PATCH 17/26] Extractor for VDB ROPs --- .../houdini/publish/extract_vdb_cache.py | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 colorbleed/plugins/houdini/publish/extract_vdb_cache.py diff --git a/colorbleed/plugins/houdini/publish/extract_vdb_cache.py b/colorbleed/plugins/houdini/publish/extract_vdb_cache.py new file mode 100644 index 0000000000..ad85a5daf0 --- /dev/null +++ b/colorbleed/plugins/houdini/publish/extract_vdb_cache.py @@ -0,0 +1,42 @@ +import os +import re + +import pyblish.api +import colorbleed.api + + +class ExtractVDBCache(colorbleed.api.Extractor): + + order = pyblish.api.ExtractorOrder + 0.1 + label = "Extract VDB Cache" + families = ["colorbleed.vdbcache"] + hosts = ["houdini"] + + def process(self, instance): + + ropnode = instance[0] + + # Get the filename from the filename parameter + # `.eval()` will make sure all tokens are resolved + output = ropnode.parm("sopoutput").eval() + staging_dir = os.path.dirname(output) + instance.data["stagingDir"] = staging_dir + + # Replace the 4 digits to match file sequence token '%04d' if we have + # a sequence of frames + file_name = os.path.basename(output) + has_frame = re.match("\w\.(d+)\.vdb", file_name) + if has_frame: + frame_nr = has_frame.group() + file_name.replace(frame_nr, "%04d") + + # We run the render + self.log.info( + "Starting render: {startFrame} - {endFrame}".format(**instance.data) + ) + ropnode.render() + + if "files" not in instance.data: + instance.data["files"] = [] + + instance.data["files"].append(file_name) From f1bf3d806626dc40148578893e2a2b4affe23052 Mon Sep 17 00:00:00 2001 From: wikoreman Date: Fri, 14 Sep 2018 16:54:39 +0200 Subject: [PATCH 18/26] Removed commented line --- colorbleed/plugins/houdini/publish/valiate_vdb_input_node.py | 1 - 1 file changed, 1 deletion(-) diff --git a/colorbleed/plugins/houdini/publish/valiate_vdb_input_node.py b/colorbleed/plugins/houdini/publish/valiate_vdb_input_node.py index 25a8d86ce3..24606046fa 100644 --- a/colorbleed/plugins/houdini/publish/valiate_vdb_input_node.py +++ b/colorbleed/plugins/houdini/publish/valiate_vdb_input_node.py @@ -41,7 +41,6 @@ class ValidateVDBInputNode(pyblish.api.InstancePlugin): return [instance] for prim in prims: - # print(">>", prim.name()) if prim.numVertices() != 1: cls.log.error("Found primitive with more than 1 vertex!") return [instance] From d91ca5c1d4cc766d00332e422fc45c3c59531b67 Mon Sep 17 00:00:00 2001 From: wikoreman Date: Fri, 14 Sep 2018 17:18:21 +0200 Subject: [PATCH 19/26] Added alembic output node validator --- .../publish/validate_alembic_input_node.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 colorbleed/plugins/houdini/publish/validate_alembic_input_node.py diff --git a/colorbleed/plugins/houdini/publish/validate_alembic_input_node.py b/colorbleed/plugins/houdini/publish/validate_alembic_input_node.py new file mode 100644 index 0000000000..91f9e9f97e --- /dev/null +++ b/colorbleed/plugins/houdini/publish/validate_alembic_input_node.py @@ -0,0 +1,37 @@ +import pyblish.api +import colorbleed.api + + +class ValidateAlembicInputNode(pyblish.api.InstancePlugin): + """Validate that the node connected to the output is correct + + The connected node cannot be of the following types for Alembic: + - VDB + - Volumne + + """ + + order = colorbleed.api.ValidateContentsOrder + 0.1 + families = ["colorbleed.pointcache"] + hosts = ["houdini"] + label = "Validate Input Node (Abc)" + + def process(self, instance): + invalid = self.get_invalid(instance) + if invalid: + raise RuntimeError("Node connected to the output node incorrect") + + @classmethod + def get_invalid(cls, instance): + + invalid_nodes = ["VDB", "Volume"] + node = instance.data["output_node"] + + prims = node.geometry().prims() + + for prim in prims: + prim_type = prim.type().name() + if prim_type in invalid_nodes: + cls.log.error("Found a primitive which is of type '%s' !" + % prim_type) + return [instance] From 5ddc333999fc81a4027fcdf7fbf1d4f7c94dbfb7 Mon Sep 17 00:00:00 2001 From: wikoreman Date: Fri, 14 Sep 2018 17:18:43 +0200 Subject: [PATCH 20/26] Set staging dir to what user has entered --- colorbleed/plugins/houdini/publish/extract_alembic.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/colorbleed/plugins/houdini/publish/extract_alembic.py b/colorbleed/plugins/houdini/publish/extract_alembic.py index 29450d0824..f66b5bde72 100644 --- a/colorbleed/plugins/houdini/publish/extract_alembic.py +++ b/colorbleed/plugins/houdini/publish/extract_alembic.py @@ -17,9 +17,14 @@ class ExtractAlembic(colorbleed.api.Extractor): # Get the filename from the filename parameter # `.eval()` will make sure all tokens are resolved - file_name = os.path.basename(ropnode.parm("filename").eval()) + output = ropnode.parm("filename").eval() + staging_dir = os.path.dirname(output) + instance.data["stagingDir"] = staging_dir + + file_name = os.path.basename(output) # We run the render + self.log.info("Writing alembic '%s' to '%s'" % (file_name, staging_dir)) ropnode.render() if "files" not in instance.data: From d7ca17c4f94b0a3c0cd91bf0229e3a2a93ffd773 Mon Sep 17 00:00:00 2001 From: wikoreman Date: Mon, 17 Sep 2018 09:30:35 +0200 Subject: [PATCH 21/26] Added new family --- colorbleed/plugins/global/publish/integrate.py | 1 + 1 file changed, 1 insertion(+) diff --git a/colorbleed/plugins/global/publish/integrate.py b/colorbleed/plugins/global/publish/integrate.py index 2418971546..6917b43f6f 100644 --- a/colorbleed/plugins/global/publish/integrate.py +++ b/colorbleed/plugins/global/publish/integrate.py @@ -30,6 +30,7 @@ class IntegrateAsset(pyblish.api.InstancePlugin): "colorbleed.mayaAscii", "colorbleed.model", "colorbleed.pointcache", + "colorbleed.vdbcache", "colorbleed.setdress", "colorbleed.rig", "colorbleed.yetiRig", From f03a6b31c4cfb3a908287de0ae5a974252f844cc Mon Sep 17 00:00:00 2001 From: wikoreman Date: Mon, 17 Sep 2018 09:32:09 +0200 Subject: [PATCH 22/26] Updated doc strings --- colorbleed/plugins/maya/load/load_alembic.py | 2 +- colorbleed/plugins/maya/load/load_camera.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/colorbleed/plugins/maya/load/load_alembic.py b/colorbleed/plugins/maya/load/load_alembic.py index afea761ab8..d34530a8d5 100644 --- a/colorbleed/plugins/maya/load/load_alembic.py +++ b/colorbleed/plugins/maya/load/load_alembic.py @@ -2,7 +2,7 @@ import colorbleed.maya.plugin class AbcLoader(colorbleed.maya.plugin.ReferenceLoader): - """Specific loader of Alembic for the avalon.animation family""" + """Specific loader of Alembic for the colorbleed.animation family""" families = ["colorbleed.animation", "colorbleed.pointcache"] diff --git a/colorbleed/plugins/maya/load/load_camera.py b/colorbleed/plugins/maya/load/load_camera.py index 1d66433a6f..067c4c0cde 100644 --- a/colorbleed/plugins/maya/load/load_camera.py +++ b/colorbleed/plugins/maya/load/load_camera.py @@ -2,7 +2,7 @@ import colorbleed.maya.plugin class CameraLoader(colorbleed.maya.plugin.ReferenceLoader): - """Specific loader of Alembic for the avalon.animation family""" + """Specific loader of Alembic for the colorbleed.camera family""" families = ["colorbleed.camera"] label = "Reference camera" From b229fc20cd78a9f1f971f82eac804f4a2d8fabc7 Mon Sep 17 00:00:00 2001 From: wikoreman Date: Mon, 17 Sep 2018 10:09:54 +0200 Subject: [PATCH 23/26] Added VDB cache loader --- .../plugins/maya/load/load_vdb_to_vray.py | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 colorbleed/plugins/maya/load/load_vdb_to_vray.py diff --git a/colorbleed/plugins/maya/load/load_vdb_to_vray.py b/colorbleed/plugins/maya/load/load_vdb_to_vray.py new file mode 100644 index 0000000000..45294845d4 --- /dev/null +++ b/colorbleed/plugins/maya/load/load_vdb_to_vray.py @@ -0,0 +1,64 @@ +from avalon import api +# import colorbleed.maya.plugin + + +class LoadVDBtoVRay(api.Loader): + + families = ["colorbleed.vdbcache"] + representations = ["vdb"] + + name = "Load VDB to VRay" + icon = "cloud" + color = "orange" + + def load(self, context, name, namespace, data): + + # import pprint + from maya import cmds + import avalon.maya.lib as lib + from avalon.maya.pipeline import containerise + + # Check if viewport drawing engine is Open GL Core (compat) + render_engine = None + compatible = "OpenGLCoreProfileCompat" + if cmds.optionVar(exists="vp2RenderingEngine"): + render_engine = cmds.optionVar(query="vp2RenderingEngine") + + if not render_engine or render_engine != compatible: + raise RuntimeError("Current scene's settings are incompatible." + "See Preferences > Display > Viewport 2.0 to " + "set the render engine to '%s'" % compatible) + + asset = context['asset'] + version = context["version"] + + asset_name = asset["name"] + namespace = namespace or lib.unique_namespace( + asset_name + "_", + prefix="_" if asset_name[0].isdigit() else "", + suffix="_", + ) + + # Root group + label = "{}:{}".format(namespace, name) + root = cmds.group(name=label, empty=True) + + # Create VR + grid_node = cmds.createNode("VRayVolumeGrid", + name="{}VVGShape".format(label), + parent=root) + + # Set attributes + cmds.setAttr("{}.inFile".format(grid_node), self.fname, type="string") + cmds.setAttr("{}.inReadOffset".format(grid_node), + version["startFrames"]) + + nodes = [root, grid_node] + self[:] = nodes + + return containerise( + name=name, + namespace=namespace, + nodes=nodes, + context=context, + loader=self.__class__.__name__) From 27992f68e1b540a4fb31a275903996a42556267c Mon Sep 17 00:00:00 2001 From: wikoreman Date: Tue, 18 Sep 2018 13:09:15 +0200 Subject: [PATCH 24/26] Added load alembic camera --- .../plugins/houdini/load/load_camera.py | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 colorbleed/plugins/houdini/load/load_camera.py diff --git a/colorbleed/plugins/houdini/load/load_camera.py b/colorbleed/plugins/houdini/load/load_camera.py new file mode 100644 index 0000000000..f827244c6b --- /dev/null +++ b/colorbleed/plugins/houdini/load/load_camera.py @@ -0,0 +1,119 @@ +from avalon import api + +from avalon.houdini import pipeline, lib + + +class CameraLoader(api.Loader): + """Specific loader of Alembic for the avalon.animation family""" + + families = ["colorbleed.camera"] + label = "Load Camera (abc)" + representations = ["abc"] + order = -10 + + icon = "code-fork" + color = "orange" + + def load(self, context, name=None, namespace=None, data=None): + + import os + import hou + + # Format file name, Houdini only wants forward slashes + file_path = os.path.normpath(self.fname) + file_path = file_path.replace("\\", "/") + + # Get the root node + obj = hou.node("/obj") + + # Create a unique name + counter = 1 + asset_name = context["asset"]["name"] + + namespace = namespace if namespace else asset_name + formatted = "{}_{}".format(namespace, name) if namespace else name + node_name = "{0}_{1:03d}".format(formatted, counter) + + children = lib.children_as_string(hou.node("/obj")) + while node_name in children: + counter += 1 + node_name = "{0}_{1:03d}".format(formatted, counter) + + # Create a archive node + container = self.create_and_connect(obj, "alembicarchive", node_name) + + # TODO: add FPS of project / asset + container.setParms({"fileName": file_path, + "channelRef": True}) + + # Apply some magic + container.parm("buildHierarchy").pressButton() + container.moveToGoodPosition() + + # Create an alembic xform node + nodes = [container] + + self[:] = nodes + + return pipeline.containerise(node_name, + namespace, + nodes, + context, + self.__class__.__name__) + + def update(self, container, representation): + + node = container["node"] + + # Update the file path + file_path = api.get_representation_path(representation) + file_path = file_path.replace("\\", "/") + + # Update attributes + node.setParms({"fileName": file_path, + "representation": str(representation["_id"])}) + + # Rebuild + node.parm("buildHierarchy").pressButton() + + def remove(self, container): + + node = container["node"] + node.destroy() + + def create_and_connect(self, node, node_type, name=None): + """Create a node within a node which and connect it to the input + + Args: + node(hou.Node): parent of the new node + node_type(str) name of the type of node, eg: 'alembic' + name(str, Optional): name of the node + + Returns: + hou.Node + + """ + + import hou + + try: + + if name: + new_node = node.createNode(node_type, node_name=name) + else: + new_node = node.createNode(node_type) + + new_node.moveToGoodPosition() + + try: + input_node = next(i for i in node.allItems() if + isinstance(i, hou.SubnetIndirectInput)) + except StopIteration: + return new_node + + new_node.setInput(0, input_node) + return new_node + + except Exception: + raise RuntimeError("Could not created node type `%s` in node `%s`" + % (node_type, node)) From 3f933d07367c1db68c79e596a525cc6666bf1f44 Mon Sep 17 00:00:00 2001 From: wikoreman Date: Tue, 18 Sep 2018 14:16:02 +0200 Subject: [PATCH 25/26] Renamed plugin, added colorbleed.model --- colorbleed/plugins/houdini/load/load_alembic.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/colorbleed/plugins/houdini/load/load_alembic.py b/colorbleed/plugins/houdini/load/load_alembic.py index 5043ba5a0d..94e3894d05 100644 --- a/colorbleed/plugins/houdini/load/load_alembic.py +++ b/colorbleed/plugins/houdini/load/load_alembic.py @@ -6,8 +6,10 @@ from avalon.houdini import pipeline, lib class AbcLoader(api.Loader): """Specific loader of Alembic for the avalon.animation family""" - families = ["colorbleed.animation", "colorbleed.pointcache"] - label = "Load Animation" + families = ["colorbleed.model", + "colorbleed.animation", + "colorbleed.pointcache"] + label = "Load Alembic" representations = ["abc"] order = -10 icon = "code-fork" From ad0f846a028da00e37bb71df1d8fe9c43758364f Mon Sep 17 00:00:00 2001 From: wikoreman Date: Tue, 18 Sep 2018 14:23:35 +0200 Subject: [PATCH 26/26] Refactored parameter evaluation --- colorbleed/plugins/houdini/publish/collect_instances.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/colorbleed/plugins/houdini/publish/collect_instances.py b/colorbleed/plugins/houdini/publish/collect_instances.py index 0e5301a6a1..effd6e392e 100644 --- a/colorbleed/plugins/houdini/publish/collect_instances.py +++ b/colorbleed/plugins/houdini/publish/collect_instances.py @@ -92,11 +92,11 @@ class CollectInstances(pyblish.api.ContextPlugin): if node.parm("trange") is None: return data - if node.parm("trange").eval() == 0: + if node.evalParm("trange") == 0: return data - data["startFrame"] = node.parm("f1").eval() - data["endFrame"] = node.parm("f2").eval() - data["steps"] = node.parm("f3").eval() + data["startFrame"] = node.evalParm("f1") + data["endFrame"] = node.evalParm("f2") + data["steps"] = node.evalParm("f3") return data