🎨 workfile auto-creator

This commit is contained in:
Ondřej Samohel 2022-10-24 14:48:30 +02:00
parent 7a2e6bdf78
commit c27f4cbbf4
No known key found for this signature in database
GPG key ID: 02376E18990A97C6
3 changed files with 124 additions and 46 deletions

View file

@ -35,6 +35,9 @@ class Creator(LegacyCreator):
when hovering over a node. The information is visible under the name of
the node.
Deprecated:
This creator is deprecated and will be removed in future version.
"""
defaults = ['Main']
@ -91,12 +94,35 @@ class Creator(LegacyCreator):
sys.exc_info()[2])
@six.add_metaclass(ABCMeta)
class HoudiniCreator(NewCreator):
selected_nodes = []
class HoudiniCreatorBase(object):
@staticmethod
def cache_instances(shared_data):
"""Cache instances for Creators to shared data.
Create `houdini_cached_instances` key when needed in shared data and
fill it with all collected instances from the scene under its
respective creator identifiers.
Args:
Dict[str, Any]: Shared data.
Return:
Dict[str, Any]: Shared data dictionary.
"""
if shared_data.get("houdini_cached_instances") is None:
shared_data["houdini_cached_instances"] = {}
cached_instances = lsattr("id", "pyblish.avalon.instance")
for i in cached_instances:
creator_id = i.parm("creator_identifier").eval()
if creator_id not in shared_data["houdini_cached_instances"]:
shared_data["houdini_cached_instances"][creator_id] = [i]
else:
shared_data["houdini_cached_instances"][creator_id].append(i) # noqa
return shared_data
@staticmethod
def _create_instance_node(
def create_instance_node(
node_name, parent,
node_type="geometry"):
# type: (str, str, str) -> hou.Node
@ -117,6 +143,11 @@ class HoudiniCreator(NewCreator):
instance_node.moveToGoodPosition()
return instance_node
@six.add_metaclass(ABCMeta)
class HoudiniCreator(NewCreator, HoudiniCreatorBase):
selected_nodes = []
def create(self, subset_name, instance_data, pre_create_data):
try:
if pre_create_data.get("use_selection"):
@ -127,7 +158,7 @@ class HoudiniCreator(NewCreator):
if node_type is None:
node_type = "geometry"
instance_node = self._create_instance_node(
instance_node = self.create_instance_node(
subset_name, "/out", node_type)
instance_data["instance_node"] = instance_node.path()
@ -163,20 +194,7 @@ class HoudiniCreator(NewCreator):
def collect_instances(self):
# cache instances if missing
if self.collection_shared_data.get("houdini_cached_instances") is None:
self.log.info("Caching instances ...")
self.collection_shared_data["houdini_cached_instances"] = {}
cached_instances = lsattr("id", "pyblish.avalon.instance")
for i in cached_instances:
creator_id = i.parm("creator_identifier").eval()
if creator_id not in self.collection_shared_data[
"houdini_cached_instances"]:
self.collection_shared_data["houdini_cached_instances"][
creator_id] = [i]
else:
self.collection_shared_data["houdini_cached_instances"][
creator_id].append(i)
self.cache_instances(self.collection_shared_data)
for instance in self.collection_shared_data["houdini_cached_instances"].get(self.identifier, []): # noqa
created_instance = CreatedInstance.from_existing(
read(instance), self

View file

@ -0,0 +1,76 @@
# -*- coding: utf-8 -*-
"""Creator plugin for creating workfiles."""
from openpype.hosts.houdini.api import plugin
from openpype.hosts.houdini.api.lib import read
from openpype.pipeline import CreatedInstance, AutoCreator
from openpype.pipeline.legacy_io import Session
from openpype.client import get_asset_by_name
class CreateWorkfile(plugin.HoudiniCreatorBase, AutoCreator):
"""Workfile auto-creator."""
identifier = "io.openpype.creators.houdini.workfile"
label = "Workfile"
family = "workfile"
icon = "gears"
default_variant = "Main"
def create(self):
variant = self.default_variant
current_instance = next(
(
instance for instance in self.create_context.instances
if instance.creator_identifier == self.identifier
), None)
project_name = self.project_name
asset_name = Session["AVALON_ASSET"]
task_name = Session["AVALON_TASK"]
host_name = Session["AVALON_APP"]
if current_instance is None:
asset_doc = get_asset_by_name(project_name, asset_name)
subset_name = self.get_subset_name(
variant, task_name, asset_doc, project_name, host_name
)
data = {
"asset": asset_name,
"task": task_name,
"variant": variant
}
data.update(
self.get_dynamic_data(
variant, task_name, asset_doc,
project_name, host_name, current_instance)
)
new_instance = CreatedInstance(
self.family, subset_name, data, self
)
self._add_instance_to_context(new_instance)
# Update instance context if is not the same
elif (
current_instance["asset"] != asset_name
or current_instance["task"] != task_name
):
asset_doc = get_asset_by_name(project_name, asset_name)
subset_name = self.get_subset_name(
variant, task_name, asset_doc, project_name, host_name
)
current_instance["asset"] = asset_name
current_instance["task"] = task_name
current_instance["subset"] = subset_name
def collect_instances(self):
self.cache_instances(self.collection_shared_data)
for instance in self.collection_shared_data["houdini_cached_instances"].get(self.identifier, []): # noqa
created_instance = CreatedInstance.from_existing(
read(instance), self
)
self._add_instance_to_context(created_instance)
def update_instances(self, update_list):
pass

View file

@ -5,19 +5,20 @@ from openpype.pipeline import legacy_io
import pyblish.api
class CollectHoudiniCurrentFile(pyblish.api.ContextPlugin):
class CollectHoudiniCurrentFile(pyblish.api.InstancePlugin):
"""Inject the current working file into context"""
order = pyblish.api.CollectorOrder - 0.01
label = "Houdini Current File"
hosts = ["houdini"]
family = ["workfile"]
def process(self, context):
def process(self, instance):
"""Inject the current working file"""
current_file = hou.hipFile.path()
if not os.path.exists(current_file):
# By default Houdini will even point a new scene to a path.
# By default, Houdini will even point a new scene to a path.
# However if the file is not saved at all and does not exist,
# we assume the user never set it.
filepath = ""
@ -34,43 +35,26 @@ class CollectHoudiniCurrentFile(pyblish.api.ContextPlugin):
"saved correctly."
)
context.data["currentFile"] = current_file
instance.context.data["currentFile"] = current_file
folder, file = os.path.split(current_file)
filename, ext = os.path.splitext(file)
task = legacy_io.Session["AVALON_TASK"]
data = {}
# create instance
instance = context.create_instance(name=filename)
subset = 'workfile' + task.capitalize()
data.update({
"subset": subset,
"asset": os.getenv("AVALON_ASSET", None),
"label": subset,
"publish": True,
"family": 'workfile',
"families": ['workfile'],
instance.data.update({
"setMembers": [current_file],
"frameStart": context.data['frameStart'],
"frameEnd": context.data['frameEnd'],
"handleStart": context.data['handleStart'],
"handleEnd": context.data['handleEnd']
"frameStart": instance.context.data['frameStart'],
"frameEnd": instance.context.data['frameEnd'],
"handleStart": instance.context.data['handleStart'],
"handleEnd": instance.context.data['handleEnd']
})
data['representations'] = [{
instance.data['representations'] = [{
'name': ext.lstrip("."),
'ext': ext.lstrip("."),
'files': file,
"stagingDir": folder,
}]
instance.data.update(data)
self.log.info('Collected instance: {}'.format(file))
self.log.info('Scene path: {}'.format(current_file))
self.log.info('staging Dir: {}'.format(folder))
self.log.info('subset: {}'.format(subset))