implemented new collection of render instances

This commit is contained in:
Jakub Trllo 2023-02-15 11:07:59 +01:00
parent ff7b3004ad
commit b405cac45c
2 changed files with 87 additions and 280 deletions

View file

@ -1,280 +0,0 @@
import json
import copy
import pyblish.api
from openpype.client import get_asset_by_name
from openpype.pipeline import legacy_io
from openpype.pipeline.create import get_subset_name
class CollectInstances(pyblish.api.ContextPlugin):
label = "Collect Instances"
order = pyblish.api.CollectorOrder - 0.4
hosts = ["tvpaint"]
def process(self, context):
workfile_instances = context.data["workfileInstances"]
self.log.debug("Collected ({}) instances:\n{}".format(
len(workfile_instances),
json.dumps(workfile_instances, indent=4)
))
filtered_instance_data = []
# Backwards compatibility for workfiles that already have review
# instance in metadata.
review_instance_exist = False
for instance_data in workfile_instances:
family = instance_data["family"]
if family == "review":
review_instance_exist = True
elif family not in ("renderPass", "renderLayer"):
self.log.info("Unknown family \"{}\". Skipping {}".format(
family, json.dumps(instance_data, indent=4)
))
continue
filtered_instance_data.append(instance_data)
# Fake review instance if review was not found in metadata families
if not review_instance_exist:
filtered_instance_data.append(
self._create_review_instance_data(context)
)
for instance_data in filtered_instance_data:
instance_data["fps"] = context.data["sceneFps"]
# Conversion from older instances
# - change 'render_layer' to 'renderlayer'
render_layer = instance_data.get("instance_data")
if not render_layer:
# Render Layer has only variant
if instance_data["family"] == "renderLayer":
render_layer = instance_data.get("variant")
# Backwards compatibility for renderPasses
elif "render_layer" in instance_data:
render_layer = instance_data["render_layer"]
if render_layer:
instance_data["renderlayer"] = render_layer
# Store workfile instance data to instance data
instance_data["originData"] = copy.deepcopy(instance_data)
# Global instance data modifications
# Fill families
family = instance_data["family"]
families = [family]
if family != "review":
families.append("review")
# Add `review` family for thumbnail integration
instance_data["families"] = families
# Instance name
subset_name = instance_data["subset"]
name = instance_data.get("name", subset_name)
instance_data["name"] = name
instance_data["label"] = "{} [{}-{}]".format(
name,
context.data["sceneMarkIn"] + 1,
context.data["sceneMarkOut"] + 1
)
active = instance_data.get("active", True)
instance_data["active"] = active
instance_data["publish"] = active
# Add representations key
instance_data["representations"] = []
# Different instance creation based on family
instance = None
if family == "review":
# Change subset name of review instance
# Project name from workfile context
project_name = context.data["workfile_context"]["project"]
# Collect asset doc to get asset id
# - not sure if it's good idea to require asset id in
# get_subset_name?
asset_name = context.data["workfile_context"]["asset"]
asset_doc = get_asset_by_name(project_name, asset_name)
# Host name from environment variable
host_name = context.data["hostName"]
# Use empty variant value
variant = ""
task_name = legacy_io.Session["AVALON_TASK"]
new_subset_name = get_subset_name(
family,
variant,
task_name,
asset_doc,
project_name,
host_name,
project_settings=context.data["project_settings"]
)
instance_data["subset"] = new_subset_name
instance = context.create_instance(**instance_data)
instance.data["layers"] = copy.deepcopy(
context.data["layersData"]
)
elif family == "renderLayer":
instance = self.create_render_layer_instance(
context, instance_data
)
elif family == "renderPass":
instance = self.create_render_pass_instance(
context, instance_data
)
if instance is None:
continue
any_visible = False
for layer in instance.data["layers"]:
if layer["visible"]:
any_visible = True
break
instance.data["publish"] = any_visible
self.log.debug("Created instance: {}\n{}".format(
instance, json.dumps(instance.data, indent=4)
))
def _create_review_instance_data(self, context):
"""Fake review instance data."""
return {
"family": "review",
"asset": context.data["asset"],
# Dummy subset name
"subset": "reviewMain"
}
def create_render_layer_instance(self, context, instance_data):
name = instance_data["name"]
# Change label
subset_name = instance_data["subset"]
# Backwards compatibility
# - subset names were not stored as final subset names during creation
if "variant" not in instance_data:
instance_data["label"] = "{}_Beauty".format(name)
# Change subset name
# Final family of an instance will be `render`
new_family = "render"
task_name = legacy_io.Session["AVALON_TASK"]
new_subset_name = "{}{}_{}_Beauty".format(
new_family, task_name.capitalize(), name
)
instance_data["subset"] = new_subset_name
self.log.debug("Changed subset name \"{}\"->\"{}\"".format(
subset_name, new_subset_name
))
# Get all layers for the layer
layers_data = context.data["layersData"]
group_id = instance_data["group_id"]
group_layers = []
for layer in layers_data:
if layer["group_id"] == group_id:
group_layers.append(layer)
if not group_layers:
# Should be handled here?
self.log.warning((
f"Group with id {group_id} does not contain any layers."
f" Instance \"{name}\" not created."
))
return None
instance_data["layers"] = group_layers
return context.create_instance(**instance_data)
def create_render_pass_instance(self, context, instance_data):
pass_name = instance_data["pass"]
self.log.info(
"Creating render pass instance. \"{}\"".format(pass_name)
)
# Change label
render_layer = instance_data["renderlayer"]
# Backwards compatibility
# - subset names were not stored as final subset names during creation
if "variant" not in instance_data:
instance_data["label"] = "{}_{}".format(render_layer, pass_name)
# Change subset name
# Final family of an instance will be `render`
new_family = "render"
old_subset_name = instance_data["subset"]
task_name = legacy_io.Session["AVALON_TASK"]
new_subset_name = "{}{}_{}_{}".format(
new_family, task_name.capitalize(), render_layer, pass_name
)
instance_data["subset"] = new_subset_name
self.log.debug("Changed subset name \"{}\"->\"{}\"".format(
old_subset_name, new_subset_name
))
layers_data = context.data["layersData"]
layers_by_name = {
layer["name"]: layer
for layer in layers_data
}
if "layer_names" in instance_data:
layer_names = instance_data["layer_names"]
else:
# Backwards compatibility
# - not 100% working as it was found out that layer ids can't be
# used as unified identifier across multiple workstations
layers_by_id = {
layer["layer_id"]: layer
for layer in layers_data
}
layer_ids = instance_data["layer_ids"]
layer_names = []
for layer_id in layer_ids:
layer = layers_by_id.get(layer_id)
if layer:
layer_names.append(layer["name"])
if not layer_names:
raise ValueError((
"Metadata contain old way of storing layers information."
" It is not possible to identify layers to publish with"
" these data. Please remove Render Pass instances with"
" Subset manager and use Creator tool to recreate them."
))
render_pass_layers = []
for layer_name in layer_names:
layer = layers_by_name.get(layer_name)
# NOTE This is kind of validation before validators?
if not layer:
self.log.warning(
f"Layer with name {layer_name} was not found."
)
continue
render_pass_layers.append(layer)
if not render_pass_layers:
name = instance_data["name"]
self.log.warning(
f"None of the layers from the RenderPass \"{name}\""
" exist anymore. Instance not created."
)
return None
instance_data["layers"] = render_pass_layers
return context.create_instance(**instance_data)

View file

@ -0,0 +1,87 @@
import copy
import pyblish.api
from openpype.lib import prepare_template_data
class CollectRenderInstances(pyblish.api.InstancePlugin):
label = "Collect Render Instances"
order = pyblish.api.CollectorOrder - 0.4
hosts = ["tvpaint"]
families = ["render", "review"]
def process(self, instance):
context = instance.context
creator_identifier = instance.data["creator_identifier"]
if creator_identifier == "render.layer":
self._collect_data_for_render_layer(instance)
elif creator_identifier == "render.pass":
self._collect_data_for_render_pass(instance)
else:
if creator_identifier == "scene.review":
self._collect_data_for_review(instance)
return
subset_name = instance.data["subset"]
instance.data["name"] = subset_name
instance.data["label"] = "{} [{}-{}]".format(
subset_name,
context.data["sceneMarkIn"] + 1,
context.data["sceneMarkOut"] + 1
)
def _collect_data_for_render_layer(self, instance):
instance.data["families"].append("renderLayer")
creator_attributes = instance.data["creator_attributes"]
group_id = creator_attributes["group_id"]
if creator_attributes["mark_for_review"]:
instance.data["families"].append("review")
layers_data = instance.context.data["layersData"]
instance.data["layers"] = [
copy.deepcopy(layer)
for layer in layers_data
if layer["group_id"] == group_id
]
def _collect_data_for_render_pass(self, instance):
instance.data["families"].append("renderPass")
layer_names = set(instance.data["layer_names"])
layers_data = instance.context.data["layersData"]
creator_attributes = instance.data["creator_attributes"]
if creator_attributes["mark_for_review"]:
instance.data["families"].append("review")
instance.data["layers"] = [
copy.deepcopy(layer)
for layer in layers_data
if layer["name"] in layer_names
]
render_layer_data = None
render_layer_id = creator_attributes["render_layer_instance_id"]
for in_data in instance.context.data["workfileInstances"]:
if (
in_data["creator_identifier"] == "render.layer"
and in_data["instance_id"] == render_layer_id
):
render_layer_data = in_data
break
instance.data["renderLayerData"] = copy.deepcopy(render_layer_data)
# Invalid state
if render_layer_data is None:
return
render_layer_name = render_layer_data["variant"]
subset_name = instance.data["subset"]
instance.data["subset"] = subset_name.format(
**prepare_template_data({"renderlayer": render_layer_name})
)
def _collect_data_for_review(self, instance):
instance.data["layers"] = copy.deepcopy(
instance.context.data["layersData"]
)