diff --git a/client/ayon_core/plugins/publish/extract_usd_layer_contributions.py b/client/ayon_core/plugins/publish/extract_usd_layer_contributions.py index 01162fc481..ed3c16b5c2 100644 --- a/client/ayon_core/plugins/publish/extract_usd_layer_contributions.py +++ b/client/ayon_core/plugins/publish/extract_usd_layer_contributions.py @@ -2,6 +2,7 @@ from operator import attrgetter import dataclasses import os import platform +from collections import defaultdict from typing import Any, Dict, List import pyblish.api @@ -13,10 +14,11 @@ except ImportError: from ayon_core.lib import ( TextDef, BoolDef, + NumberDef, UISeparatorDef, UILabelDef, EnumDef, - filter_profiles, NumberDef + filter_profiles, ) try: from ayon_core.pipeline.usdlib import ( @@ -278,19 +280,23 @@ class CollectUSDLayerContributions(pyblish.api.InstancePlugin, # level, you can add it directly from the publisher at that particular # order. Future publishes will then see the existing contribution and will # persist adding it to future bootstraps at that order - contribution_layers: Dict[str, int] = { + contribution_layers: Dict[str, Dict[str, int]] = { # asset layers - "model": 100, - "assembly": 150, - "groom": 175, - "look": 200, - "rig": 300, + "asset": { + "model": 100, + "assembly": 150, + "groom": 175, + "look": 200, + "rig": 300, + }, # shot layers - "layout": 200, - "animation": 300, - "simulation": 400, - "fx": 500, - "lighting": 600, + "shot": { + "layout": 200, + "animation": 300, + "simulation": 400, + "fx": 500, + "lighting": 600, + } } # Default profiles to set certain instance attribute defaults based on # profiles in settings @@ -305,12 +311,18 @@ class CollectUSDLayerContributions(pyblish.api.InstancePlugin, cls.enabled = plugin_settings.get("enabled", cls.enabled) - # Define contribution layers via settings - contribution_layers = {} + # Define contribution layers via settings by their scope + contribution_layers = defaultdict(dict) for entry in plugin_settings.get("contribution_layers", []): - contribution_layers[entry["name"]] = int(entry["order"]) + for scope in entry.get("scope", []): + contribution_layers[scope][entry["name"]] = int(entry["order"]) if contribution_layers: - cls.contribution_layers = contribution_layers + cls.contribution_layers = dict(contribution_layers) + else: + cls.log.warning( + "No scoped contribution layers found in settings, falling back" + " to CollectUSDLayerContributions plug-in defaults..." + ) cls.profiles = plugin_settings.get("profiles", []) @@ -355,10 +367,11 @@ class CollectUSDLayerContributions(pyblish.api.InstancePlugin, asset_product = contribution.target_product layer_product = "{}_{}".format(asset_product, contribution.layer_id) - layer_order: int = self.contribution_layers.get( - attr_values["contribution_layer"], 0 - ) + scope: str = attr_values["contribution_target_product_init"] + layer_order: int = ( + self.contribution_layers[scope][attr_values["contribution_layer"]] + ) # Layer contribution instance layer_instance = self.get_or_create_instance( product_name=layer_product, @@ -489,14 +502,14 @@ class CollectUSDLayerContributions(pyblish.api.InstancePlugin, profile = {} # Define defaults - default_enabled = profile.get("contribution_enabled", True) + default_enabled: bool = profile.get("contribution_enabled", True) default_contribution_layer = profile.get( "contribution_layer", None) - default_apply_as_variant = profile.get( + default_apply_as_variant: bool = profile.get( "contribution_apply_as_variant", False) - default_target_product = profile.get( + default_target_product: str = profile.get( "contribution_target_product", "usdAsset") - default_init_as = ( + default_init_as: str = ( "asset" if profile.get("contribution_target_product") == "usdAsset" else "shot") @@ -509,6 +522,12 @@ class CollectUSDLayerContributions(pyblish.api.InstancePlugin, visible = publish_attributes.get("contribution_enabled", True) variant_visible = visible and publish_attributes.get( "contribution_apply_as_variant", True) + init_as: str = publish_attributes.get( + "contribution_target_product_init", default_init_as) + + contribution_layers = cls.contribution_layers.get( + init_as, {} + ) return [ UISeparatorDef("usd_container_settings1"), @@ -558,7 +577,7 @@ class CollectUSDLayerContributions(pyblish.api.InstancePlugin, "predefined ordering.\nA higher order (further down " "the list) will contribute as a stronger opinion." ), - items=list(cls.contribution_layers.keys()), + items=list(contribution_layers.keys()), default=default_contribution_layer, visible=visible), # TODO: We may want to make the visibility of this optional @@ -619,7 +638,11 @@ class CollectUSDLayerContributions(pyblish.api.InstancePlugin, # Update attributes if any of the following plug-in attributes # change: - keys = ["contribution_enabled", "contribution_apply_as_variant"] + keys = { + "contribution_enabled", + "contribution_apply_as_variant", + "contribution_target_product_init", + } for instance_change in event["changes"]: instance = instance_change["instance"] diff --git a/server/settings/publish_plugins.py b/server/settings/publish_plugins.py index da22e4206f..eb41c75699 100644 --- a/server/settings/publish_plugins.py +++ b/server/settings/publish_plugins.py @@ -74,13 +74,35 @@ class CollectFramesFixDefModel(BaseSettingsModel): ) +def usd_contribution_layer_types(): + return [ + {"value": "asset", "label": "Asset"}, + {"value": "shot", "label": "Shot"}, + ] + + class ContributionLayersModel(BaseSettingsModel): _layout = "compact" - name: str = SettingsField(title="Name") - order: str = SettingsField( + name: str = SettingsField( + default="", + regex="[A-Za-z0-9_-]+", + title="Name") + scope: list[str] = SettingsField( + # This should actually be returned from a callable to `default_factory` + # because lists are mutable. However, the frontend can't interpret + # the callable. It will fail to apply it as the default. Specifying + # this default directly did not show any ill side effects. + default=["asset", "shot"], + title="Scope", + min_items=1, + enum_resolver=usd_contribution_layer_types) + order: int = SettingsField( + default=0, title="Order", - description="Higher order means a higher strength and stacks the " - "layer on top.") + description=( + "Higher order means a higher strength and stacks the layer on top." + ) + ) class CollectUSDLayerContributionsProfileModel(BaseSettingsModel): @@ -1382,17 +1404,17 @@ DEFAULT_PUBLISH_VALUES = { "enabled": True, "contribution_layers": [ # Asset layers - {"name": "model", "order": 100}, - {"name": "assembly", "order": 150}, - {"name": "groom", "order": 175}, - {"name": "look", "order": 200}, - {"name": "rig", "order": 300}, + {"name": "model", "order": 100, "scope": ["asset"]}, + {"name": "assembly", "order": 150, "scope": ["asset"]}, + {"name": "groom", "order": 175, "scope": ["asset"]}, + {"name": "look", "order": 200, "scope": ["asset"]}, + {"name": "rig", "order": 300, "scope": ["asset"]}, # Shot layers - {"name": "layout", "order": 200}, - {"name": "animation", "order": 300}, - {"name": "simulation", "order": 400}, - {"name": "fx", "order": 500}, - {"name": "lighting", "order": 600}, + {"name": "layout", "order": 200, "scope": ["shot"]}, + {"name": "animation", "order": 300, "scope": ["shot"]}, + {"name": "simulation", "order": 400, "scope": ["shot"]}, + {"name": "fx", "order": 500, "scope": ["shot"]}, + {"name": "lighting", "order": 600, "scope": ["shot"]}, ], "profiles": [ {