From a15d8fde0145dc9e7d5fb41a248f7b25af5d3592 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 12 Apr 2023 15:01:49 +0200 Subject: [PATCH 1/7] Specify per Creator where it is listed in Tab search + Add a null node in COP2 or SOP network when generated there --- .../hosts/houdini/api/creator_node_shelves.py | 57 +++++++++++++++---- .../plugins/create/create_alembic_camera.py | 8 +++ .../plugins/create/create_composite.py | 16 +++++- .../plugins/create/create_pointcache.py | 9 +++ .../plugins/create/create_vbd_cache.py | 8 +++ 5 files changed, 87 insertions(+), 11 deletions(-) diff --git a/openpype/hosts/houdini/api/creator_node_shelves.py b/openpype/hosts/houdini/api/creator_node_shelves.py index 3638e14296..bc02b258b7 100644 --- a/openpype/hosts/houdini/api/creator_node_shelves.py +++ b/openpype/hosts/houdini/api/creator_node_shelves.py @@ -12,26 +12,35 @@ import tempfile import logging import os +from openpype.client import get_asset_by_name from openpype.pipeline import registered_host from openpype.pipeline.create import CreateContext from openpype.resources import get_openpype_icon_filepath import hou +import stateutils +import soptoolutils +import cop2toolutils + log = logging.getLogger(__name__) CREATE_SCRIPT = """ from openpype.hosts.houdini.api.creator_node_shelves import create_interactive -create_interactive("{identifier}") +create_interactive("{identifier}", **kwargs) """ -def create_interactive(creator_identifier): +def create_interactive(creator_identifier, **kwargs): """Create a Creator using its identifier interactively. This is used by the generated shelf tools as callback when a user selects the creator from the node tab search menu. + The `kwargs` should be what Houdini passes to the tool create scripts + context. For more information see: + https://www.sidefx.com/docs/houdini/hom/tool_script.html#arguments + Args: creator_identifier (str): The creator identifier of the Creator plugin to create. @@ -58,6 +67,33 @@ def create_interactive(creator_identifier): host = registered_host() context = CreateContext(host) + creator = context.manual_creators.get(creator_identifier) + if not creator: + raise RuntimeError("Invalid creator identifier: " + "{}".format(creator_identifier)) + + pane = stateutils.activePane(kwargs) + if isinstance(pane, hou.NetworkEditor): + pwd = pane.pwd() + subset_name = creator.get_subset_name( + variant=variant, + task_name=context.get_current_task_name(), + asset_doc=get_asset_by_name( + project_name=context.get_current_project_name(), + asset_name=context.get_current_asset_name() + ), + project_name=context.get_current_project_name(), + host_name=context.host_name + ) + + tool_fn = { + hou.sopNodeTypeCategory(): soptoolutils.genericTool, + hou.cop2NodeTypeCategory(): cop2toolutils.genericTool + }.get(pwd.childTypeCategory()) + + if tool_fn != None: + out_null = tool_fn(kwargs, "null") + out_null.setName("OUT_{}".format(subset_name), unique_name=True) before = context.instances_by_id.copy() @@ -135,12 +171,17 @@ def install(): log.debug("Writing OpenPype Creator nodes to shelf: {}".format(filepath)) tools = [] + + default_network_categories = [hou.ropNodeTypeCategory()] with shelves_change_block(): for identifier, creator in create_context.manual_creators.items(): - # TODO: Allow the creator plug-in itself to override the categories - # for where they are shown, by e.g. defining - # `Creator.get_network_categories()` + # Allow the creator plug-in itself to override the categories + # for where they are shown with `Creator.get_network_categories()` + if hasattr(creator, "get_network_categories"): + network_categories = creator.get_network_categories() + else: + network_categories = default_network_categories key = "openpype_create.{}".format(identifier) log.debug(f"Registering {key}") @@ -153,17 +194,13 @@ def install(): creator.label ), "help_url": None, - "network_categories": [ - hou.ropNodeTypeCategory(), - hou.sopNodeTypeCategory() - ], + "network_categories": network_categories, "viewer_categories": [], "cop_viewer_categories": [], "network_op_type": None, "viewer_op_type": None, "locations": ["OpenPype"] } - label = "Create {}".format(creator.label) tool = hou.shelves.tool(key) if tool: diff --git a/openpype/hosts/houdini/plugins/create/create_alembic_camera.py b/openpype/hosts/houdini/plugins/create/create_alembic_camera.py index fec64eb4a1..8c8a5e9eed 100644 --- a/openpype/hosts/houdini/plugins/create/create_alembic_camera.py +++ b/openpype/hosts/houdini/plugins/create/create_alembic_camera.py @@ -3,6 +3,8 @@ from openpype.hosts.houdini.api import plugin from openpype.pipeline import CreatedInstance, CreatorError +import hou + class CreateAlembicCamera(plugin.HoudiniCreator): """Single baked camera from Alembic ROP.""" @@ -47,3 +49,9 @@ class CreateAlembicCamera(plugin.HoudiniCreator): self.lock_parameters(instance_node, to_lock) instance_node.parm("trange").set(1) + + def get_network_categories(self): + return [ + hou.ropNodeTypeCategory(), + hou.objNodeTypeCategory() + ] diff --git a/openpype/hosts/houdini/plugins/create/create_composite.py b/openpype/hosts/houdini/plugins/create/create_composite.py index 45af2b0630..9d4f7969bb 100644 --- a/openpype/hosts/houdini/plugins/create/create_composite.py +++ b/openpype/hosts/houdini/plugins/create/create_composite.py @@ -1,7 +1,9 @@ # -*- coding: utf-8 -*- """Creator plugin for creating composite sequences.""" from openpype.hosts.houdini.api import plugin -from openpype.pipeline import CreatedInstance +from openpype.pipeline import CreatedInstance, CreatorError + +import hou class CreateCompositeSequence(plugin.HoudiniCreator): @@ -35,8 +37,20 @@ class CreateCompositeSequence(plugin.HoudiniCreator): "copoutput": filepath } + if self.selected_nodes: + if len(self.selected_nodes) > 1: + raise CreatorError("More than one item selected.") + path = self.selected_nodes[0].path() + parms["coppath"] = path + instance_node.setParms(parms) # Lock any parameters in this list to_lock = ["prim_to_detail_pattern"] self.lock_parameters(instance_node, to_lock) + + def get_network_categories(self): + return [ + hou.ropNodeTypeCategory(), + hou.cop2NodeTypeCategory() + ] diff --git a/openpype/hosts/houdini/plugins/create/create_pointcache.py b/openpype/hosts/houdini/plugins/create/create_pointcache.py index 6b6b277422..6efa96a42b 100644 --- a/openpype/hosts/houdini/plugins/create/create_pointcache.py +++ b/openpype/hosts/houdini/plugins/create/create_pointcache.py @@ -3,6 +3,8 @@ from openpype.hosts.houdini.api import plugin from openpype.pipeline import CreatedInstance +import hou + class CreatePointCache(plugin.HoudiniCreator): """Alembic ROP to pointcache""" @@ -49,3 +51,10 @@ class CreatePointCache(plugin.HoudiniCreator): # Lock any parameters in this list to_lock = ["prim_to_detail_pattern"] self.lock_parameters(instance_node, to_lock) + + def get_network_categories(self): + return [ + hou.ropNodeTypeCategory(), + hou.sopNodeTypeCategory() + ] + diff --git a/openpype/hosts/houdini/plugins/create/create_vbd_cache.py b/openpype/hosts/houdini/plugins/create/create_vbd_cache.py index 1a5011745f..c015cebd49 100644 --- a/openpype/hosts/houdini/plugins/create/create_vbd_cache.py +++ b/openpype/hosts/houdini/plugins/create/create_vbd_cache.py @@ -3,6 +3,8 @@ from openpype.hosts.houdini.api import plugin from openpype.pipeline import CreatedInstance +import hou + class CreateVDBCache(plugin.HoudiniCreator): """OpenVDB from Geometry ROP""" @@ -34,3 +36,9 @@ class CreateVDBCache(plugin.HoudiniCreator): parms["soppath"] = self.selected_nodes[0].path() instance_node.setParms(parms) + + def get_network_categories(self): + return [ + hou.ropNodeTypeCategory(), + hou.sopNodeTypeCategory() + ] From c6a0b7ff4546bddd687a617cdb05edd4e88f5447 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 12 Apr 2023 15:23:37 +0200 Subject: [PATCH 2/7] Shush hound --- openpype/hosts/houdini/api/creator_node_shelves.py | 2 +- openpype/hosts/houdini/plugins/create/create_pointcache.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/openpype/hosts/houdini/api/creator_node_shelves.py b/openpype/hosts/houdini/api/creator_node_shelves.py index bc02b258b7..cd14090104 100644 --- a/openpype/hosts/houdini/api/creator_node_shelves.py +++ b/openpype/hosts/houdini/api/creator_node_shelves.py @@ -91,7 +91,7 @@ def create_interactive(creator_identifier, **kwargs): hou.cop2NodeTypeCategory(): cop2toolutils.genericTool }.get(pwd.childTypeCategory()) - if tool_fn != None: + if tool_fn is not None: out_null = tool_fn(kwargs, "null") out_null.setName("OUT_{}".format(subset_name), unique_name=True) diff --git a/openpype/hosts/houdini/plugins/create/create_pointcache.py b/openpype/hosts/houdini/plugins/create/create_pointcache.py index 6efa96a42b..df74070fee 100644 --- a/openpype/hosts/houdini/plugins/create/create_pointcache.py +++ b/openpype/hosts/houdini/plugins/create/create_pointcache.py @@ -57,4 +57,3 @@ class CreatePointCache(plugin.HoudiniCreator): hou.ropNodeTypeCategory(), hou.sopNodeTypeCategory() ] - From ef192d3edd1da53736ed54f176e662923c718e7b Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 20 Apr 2023 12:16:40 +0200 Subject: [PATCH 3/7] Add `get_network_categories` to `CreateUSD` --- openpype/hosts/houdini/plugins/create/create_usd.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/houdini/plugins/create/create_usd.py b/openpype/hosts/houdini/plugins/create/create_usd.py index 51ed8237c5..e05d254863 100644 --- a/openpype/hosts/houdini/plugins/create/create_usd.py +++ b/openpype/hosts/houdini/plugins/create/create_usd.py @@ -3,6 +3,8 @@ from openpype.hosts.houdini.api import plugin from openpype.pipeline import CreatedInstance +import hou + class CreateUSD(plugin.HoudiniCreator): """Universal Scene Description""" @@ -13,7 +15,6 @@ class CreateUSD(plugin.HoudiniCreator): enabled = False def create(self, subset_name, instance_data, pre_create_data): - import hou # noqa instance_data.pop("active", None) instance_data.update({"node_type": "usd"}) @@ -43,3 +44,9 @@ class CreateUSD(plugin.HoudiniCreator): "id", ] self.lock_parameters(instance_node, to_lock) + + def get_network_categories(self): + return [ + hou.ropNodeTypeCategory(), + hou.lopNodeTypeCategory() + ] From 96b1b3e19d6a3e7dd7387b4477224c208eeaba90 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 20 Apr 2023 12:28:44 +0200 Subject: [PATCH 4/7] Implement `get_network_categories` on Houdini base creator plugin --- .../hosts/houdini/api/creator_node_shelves.py | 13 ++++++++----- openpype/hosts/houdini/api/plugin.py | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/houdini/api/creator_node_shelves.py b/openpype/hosts/houdini/api/creator_node_shelves.py index cd14090104..8a15d902b5 100644 --- a/openpype/hosts/houdini/api/creator_node_shelves.py +++ b/openpype/hosts/houdini/api/creator_node_shelves.py @@ -172,16 +172,19 @@ def install(): log.debug("Writing OpenPype Creator nodes to shelf: {}".format(filepath)) tools = [] - default_network_categories = [hou.ropNodeTypeCategory()] with shelves_change_block(): for identifier, creator in create_context.manual_creators.items(): # Allow the creator plug-in itself to override the categories # for where they are shown with `Creator.get_network_categories()` - if hasattr(creator, "get_network_categories"): - network_categories = creator.get_network_categories() - else: - network_categories = default_network_categories + if not hasattr(creator, "get_network_categories"): + log.debug("Creator {} has no `get_network_categories` method " + "and will not be added to TAB search.") + continue + + network_categories = creator.get_network_categories() + if not network_categories: + continue key = "openpype_create.{}".format(identifier) log.debug(f"Registering {key}") diff --git a/openpype/hosts/houdini/api/plugin.py b/openpype/hosts/houdini/api/plugin.py index 340a7f0770..1e7eaa7e22 100644 --- a/openpype/hosts/houdini/api/plugin.py +++ b/openpype/hosts/houdini/api/plugin.py @@ -276,3 +276,19 @@ class HoudiniCreator(NewCreator, HoudiniCreatorBase): color = hou.Color((0.616, 0.871, 0.769)) node.setUserData('nodeshape', shape) node.setColor(color) + + def get_network_categories(self): + """Return in which network view type this creator should show. + + The node type categories returned here will be used to define where + the creator will show up in the TAB search for nodes in Houdini's + Network View. + + This can be overridden in inherited classes to define where that + particular Creator should be visible in the TAB search. + + Returns: + list: List of houdini node type categories + + """ + return [hou.ropNodeTypeCategory()] From 3cbeda17a8cfefb31fdf2b35314b53779334867c Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 20 Apr 2023 12:29:08 +0200 Subject: [PATCH 5/7] Support auto `null` node in LOPs --- openpype/hosts/houdini/api/creator_node_shelves.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/houdini/api/creator_node_shelves.py b/openpype/hosts/houdini/api/creator_node_shelves.py index 8a15d902b5..96e843b3a9 100644 --- a/openpype/hosts/houdini/api/creator_node_shelves.py +++ b/openpype/hosts/houdini/api/creator_node_shelves.py @@ -20,6 +20,7 @@ from openpype.resources import get_openpype_icon_filepath import hou import stateutils import soptoolutils +import loptoolutils import cop2toolutils @@ -88,7 +89,8 @@ def create_interactive(creator_identifier, **kwargs): tool_fn = { hou.sopNodeTypeCategory(): soptoolutils.genericTool, - hou.cop2NodeTypeCategory(): cop2toolutils.genericTool + hou.cop2NodeTypeCategory(): cop2toolutils.genericTool, + hou.lopNodeTypeCategory(): loptoolutils.genericTool }.get(pwd.childTypeCategory()) if tool_fn is not None: From 0941469c248c5d0503c8c40fadb0b1a280b55d94 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 20 Apr 2023 12:31:37 +0200 Subject: [PATCH 6/7] Move variable to module level --- openpype/hosts/houdini/api/creator_node_shelves.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/houdini/api/creator_node_shelves.py b/openpype/hosts/houdini/api/creator_node_shelves.py index 96e843b3a9..1cc28add86 100644 --- a/openpype/hosts/houdini/api/creator_node_shelves.py +++ b/openpype/hosts/houdini/api/creator_node_shelves.py @@ -26,6 +26,13 @@ import cop2toolutils log = logging.getLogger(__name__) +CATEGORY_GENERIC_TOOL = { + hou.sopNodeTypeCategory(): soptoolutils.genericTool, + hou.cop2NodeTypeCategory(): cop2toolutils.genericTool, + hou.lopNodeTypeCategory(): loptoolutils.genericTool +} + + CREATE_SCRIPT = """ from openpype.hosts.houdini.api.creator_node_shelves import create_interactive create_interactive("{identifier}", **kwargs) @@ -87,12 +94,7 @@ def create_interactive(creator_identifier, **kwargs): host_name=context.host_name ) - tool_fn = { - hou.sopNodeTypeCategory(): soptoolutils.genericTool, - hou.cop2NodeTypeCategory(): cop2toolutils.genericTool, - hou.lopNodeTypeCategory(): loptoolutils.genericTool - }.get(pwd.childTypeCategory()) - + tool_fn = CATEGORY_GENERIC_TOOL.get(pwd.childTypeCategory()) if tool_fn is not None: out_null = tool_fn(kwargs, "null") out_null.setName("OUT_{}".format(subset_name), unique_name=True) From 9012b9f18f45562c03ecbf7c9d1ac807a0019f93 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 20 Apr 2023 12:34:14 +0200 Subject: [PATCH 7/7] Add todo for later --- openpype/hosts/houdini/api/creator_node_shelves.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openpype/hosts/houdini/api/creator_node_shelves.py b/openpype/hosts/houdini/api/creator_node_shelves.py index 1cc28add86..7c6122cffe 100644 --- a/openpype/hosts/houdini/api/creator_node_shelves.py +++ b/openpype/hosts/houdini/api/creator_node_shelves.py @@ -80,6 +80,10 @@ def create_interactive(creator_identifier, **kwargs): raise RuntimeError("Invalid creator identifier: " "{}".format(creator_identifier)) + # TODO: Once more elaborate unique create behavior should exist per Creator + # instead of per network editor area then we should move this from here + # to a method on the Creators for which this could be the default + # implementation. pane = stateutils.activePane(kwargs) if isinstance(pane, hou.NetworkEditor): pwd = pane.pwd()