Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Publish component builder LOP usd while maintaining hierarchical structure #163

Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
69d9398
Remove `usd` because it should only care about `usdrop` and `usdrender`
BigRoy Nov 5, 2024
0cc329d
Implement rudimentary draft implementation of a "Component Builder" p…
BigRoy Nov 5, 2024
f6d4841
Merge branch 'develop' into enhancement/147-ay-7047_publishing-compon…
BigRoy Nov 5, 2024
1761d8d
Remove trailing `s` from creator identifier because it's odd
BigRoy Nov 5, 2024
908a06b
Merge branch 'enhancement/147-ay-7047_publishing-component-builder-us…
BigRoy Nov 5, 2024
b1ffc35
Simplify code
BigRoy Nov 5, 2024
54a25de
Cleanup code
BigRoy Nov 5, 2024
c3b7859
Remove unused import
BigRoy Nov 5, 2024
6047c8e
Merge branch 'develop' into enhancement/147-ay-7047_publishing-compon…
BigRoy Nov 11, 2024
0dcb84e
Update client/ayon_houdini/plugins/create/create_usd_componentbuilder.py
BigRoy Nov 11, 2024
c52e956
Update client/ayon_houdini/plugins/create/create_usd_componentbuilder.py
BigRoy Nov 11, 2024
825435e
Merge branch 'develop' into enhancement/147-ay-7047_publishing-compon…
MustafaJafar Nov 12, 2024
e87fc95
Merge branch 'develop' into enhancement/147-ay-7047_publishing-compon…
BigRoy Nov 13, 2024
e85dd1c
Merge branch 'develop' into enhancement/147-ay-7047_publishing-compon…
MustafaJafar Nov 19, 2024
b9e410f
Merge branch 'develop' into enhancement/147-ay-7047_publishing-compon…
MustafaJafar Nov 22, 2024
e196c35
Merge branch 'develop' into enhancement/147-ay-7047_publishing-compon…
BigRoy Dec 5, 2024
c68ee57
Merge branch 'develop' into enhancement/147-ay-7047_publishing-compon…
antirotor Dec 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions client/ayon_houdini/plugins/create/create_usd_componentbuilder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import inspect

from ayon_houdini.api import plugin
from ayon_core.pipeline import CreatedInstance, CreatorError

import hou


class CreateUSDComponentBuilder(plugin.HoudiniCreator):
identifier = "io.ayon.creators.houdini.componentbuilder"
label = "USD Component Builder LOPs"
product_type = "usd"
icon = "cubes"
description = "Create USD from Component Builder LOPs"

def get_detail_description(self):
return inspect.cleandoc("""
Creates a USD publish from a Component Output LOP that is part of
a solaris component builder network.

The created USD will contain the component builder LOPs and all its
dependencies inside the single product.

To use it, select a Component Output LOP and click "Create" for
this creator. It will generate an instance for each selected
Component Output LOP.
""")

def create(self, product_name, instance_data, pre_create_data):
nodes = hou.selectedNodes()
builders = [
node for node in nodes if node.type().name() == "componentoutput"
BigRoy marked this conversation as resolved.
Show resolved Hide resolved
]
BigRoy marked this conversation as resolved.
Show resolved Hide resolved
for builder in builders:
self.create_for_instance_node(product_name, instance_data, builder)

def create_for_instance_node(
self, product_name, instance_data, instance_node):

try:
self.customize_node_look(instance_node)
instance_data["instance_node"] = instance_node.path()
instance_data["instance_id"] = instance_node.path()
instance_data["families"] = self.get_publish_families()
instance = CreatedInstance(
self.product_type,
product_name,
instance_data,
self)
self._add_instance_to_context(instance)
self.imprint(instance_node, instance.data_to_store())
except hou.Error as er:
raise CreatorError("Creator error: {}".format(er)) from er

BigRoy marked this conversation as resolved.
Show resolved Hide resolved
# Lock any parameters in this list
to_lock = [
# Lock some AYON attributes
"productType",
"id",
]
self.lock_parameters(instance_node, to_lock)

def get_network_categories(self):
# Do not expose via tab menu because currently it does not create any
# node, but only 'imprints' on an existing node.
return []

def get_publish_families(self):
return ["usd", "componentbuilder"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import os
from typing import List, Tuple
from pathlib import Path

import pyblish.api

from ayon_core.pipeline import AYONPyblishPluginMixin, PublishError
from ayon_houdini.api import plugin

import hou
from pxr import Sdf, UsdUtils


def compute_all_dependencies(
filepath: str) -> Tuple[list[Sdf.Layer], list[str], list[str]]:
"""Compute all dependencies for the given USD file."""
# Only separated here for better type hints on returned values
return UsdUtils.ComputeAllDependencies(filepath)


class CollectComponentBuilderLOPs(plugin.HoudiniInstancePlugin,
AYONPyblishPluginMixin):

# Run after `CollectResourcesPath`
order = pyblish.api.CollectorOrder + 0.496
families = ["componentbuilder"]
label = "Collect Componentbuilder LOPs"

def process(self, instance):

node = hou.node(instance.data["instance_node"])

# Render the component builder LOPs
# TODO: Do we want this? or use existing frames? Usually a Collector
# should not 'extract' but in this case we need the resulting USD
# file.
node.cook(force=True) # required to clear existing errors
node.parm("execute").pressButton()
MustafaJafar marked this conversation as resolved.
Show resolved Hide resolved

errors = node.errors()
if errors:
for error in errors:
self.log.error(error)
raise PublishError(f"Failed to save to disk '{node.path()}'")

# Define the main asset usd file
filepath = node.evalParm("lopoutput")
representations = instance.data.setdefault("representations", [])
representations.append({
"name": "usd",
"ext": "usd",
"files": os.path.basename(filepath),
"stagingDir": os.path.dirname(filepath),
})

# Get all its files and dependencies
# TODO: Ignore any files that are not 'relative' to the USD file
layers, assets, unresolved_paths = compute_all_dependencies(filepath)
paths: List[str] = []
paths.extend(layer.realPath for layer in layers)
paths.extend(assets)

# Skip unresolved paths, but warn about them
for unresolved in unresolved_paths:
self.log.warning(f"Cannot be resolved: {unresolved}")

self.log.debug(f"Collecting USD: {filepath}")
src_root_dir = os.path.dirname(filepath)

# Used to compare resolved paths against
filepath = Path(filepath)

# We keep the relative paths to the USD file
transfers = instance.data.setdefault("transfers", [])
publish_root = instance.data["publishDir"]
for src in paths:

if filepath == Path(src):
continue

relative_path = os.path.relpath(src, start=src_root_dir)
self.log.debug(f"Collected dependency: {relative_path}")
dest = os.path.normpath(os.path.join(publish_root, relative_path))
transfers.append((src, dest))
BigRoy marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 0 additions & 2 deletions client/ayon_houdini/plugins/publish/collect_output_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ class CollectOutputSOPPath(plugin.HoudiniInstancePlugin):
"camera",
"vdbcache",
"imagesequence",
"usd",
"usdrender",
"redshiftproxy",
"staticMesh",
"model",
Expand Down