mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 16:34:53 +01:00
Merge pull request #287 from BigRoy/enhancement/maya_yeti_user_variables
Maya: Yeti - Implement writing and loading user variables with a yeti cache
This commit is contained in:
commit
c52963ae20
3 changed files with 161 additions and 1 deletions
101
client/ayon_core/hosts/maya/api/yeti.py
Normal file
101
client/ayon_core/hosts/maya/api/yeti.py
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from maya import cmds
|
||||||
|
|
||||||
|
|
||||||
|
def get_yeti_user_variables(yeti_shape_node: str) -> List[str]:
|
||||||
|
"""Get user defined yeti user variables for a `pgYetiMaya` shape node.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
yeti_shape_node (str): The `pgYetiMaya` shape node.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: Attribute names (for a vector attribute it only lists the top
|
||||||
|
parent attribute, not the attribute per axis)
|
||||||
|
"""
|
||||||
|
|
||||||
|
attrs = cmds.listAttr(yeti_shape_node,
|
||||||
|
userDefined=True,
|
||||||
|
string=("yetiVariableV_*",
|
||||||
|
"yetiVariableF_*")) or []
|
||||||
|
valid_attrs = []
|
||||||
|
for attr in attrs:
|
||||||
|
attr_type = cmds.attributeQuery(attr, node=yeti_shape_node,
|
||||||
|
attributeType=True)
|
||||||
|
if attr.startswith("yetiVariableV_") and attr_type == "double3":
|
||||||
|
# vector
|
||||||
|
valid_attrs.append(attr)
|
||||||
|
elif attr.startswith("yetiVariableF_") and attr_type == "double":
|
||||||
|
valid_attrs.append(attr)
|
||||||
|
|
||||||
|
return valid_attrs
|
||||||
|
|
||||||
|
|
||||||
|
def create_yeti_variable(yeti_shape_node: str,
|
||||||
|
attr_name: str,
|
||||||
|
value=None,
|
||||||
|
force_value: bool = False) -> bool:
|
||||||
|
"""Get user defined yeti user variables for a `pgYetiMaya` shape node.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
yeti_shape_node (str): The `pgYetiMaya` shape node.
|
||||||
|
attr_name (str): The fully qualified yeti variable name, e.g.
|
||||||
|
"yetiVariableF_myfloat" or "yetiVariableV_myvector"
|
||||||
|
value (object): The value to set (must match the type of the attribute)
|
||||||
|
When value is None it will ignored and not be set.
|
||||||
|
force_value (bool): Whether to set the value if the attribute already
|
||||||
|
exists or not.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: Whether the attribute value was set or not.
|
||||||
|
|
||||||
|
"""
|
||||||
|
exists = cmds.attributeQuery(attr_name, node=yeti_shape_node, exists=True)
|
||||||
|
if not exists:
|
||||||
|
if attr_name.startswith("yetiVariableV_"):
|
||||||
|
_create_vector_yeti_user_variable(yeti_shape_node, attr_name)
|
||||||
|
if attr_name.startswith("yetiVariableF_"):
|
||||||
|
_create_float_yeti_user_variable(yeti_shape_node, attr_name)
|
||||||
|
|
||||||
|
if value is not None and (not exists or force_value):
|
||||||
|
plug = "{}.{}".format(yeti_shape_node, attr_name)
|
||||||
|
if (
|
||||||
|
isinstance(value, (list, tuple))
|
||||||
|
and attr_name.startswith("yetiVariableV_")
|
||||||
|
):
|
||||||
|
cmds.setAttr(plug, *value, type="double3")
|
||||||
|
else:
|
||||||
|
cmds.setAttr(plug, value)
|
||||||
|
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _create_vector_yeti_user_variable(yeti_shape_node: str, attr_name: str):
|
||||||
|
if not attr_name.startswith("yetiVariableV_"):
|
||||||
|
raise ValueError("Must start with yetiVariableV_")
|
||||||
|
cmds.addAttr(yeti_shape_node,
|
||||||
|
longName=attr_name,
|
||||||
|
attributeType="double3",
|
||||||
|
cachedInternally=True,
|
||||||
|
keyable=True)
|
||||||
|
for axis in "XYZ":
|
||||||
|
cmds.addAttr(yeti_shape_node,
|
||||||
|
longName="{}{}".format(attr_name, axis),
|
||||||
|
attributeType="double",
|
||||||
|
parent=attr_name,
|
||||||
|
cachedInternally=True,
|
||||||
|
keyable=True)
|
||||||
|
|
||||||
|
|
||||||
|
def _create_float_yeti_user_variable(yeti_node: str, attr_name: str):
|
||||||
|
if not attr_name.startswith("yetiVariableF_"):
|
||||||
|
raise ValueError("Must start with yetiVariableF_")
|
||||||
|
|
||||||
|
cmds.addAttr(yeti_node,
|
||||||
|
longName=attr_name,
|
||||||
|
attributeType="double",
|
||||||
|
cachedInternally=True,
|
||||||
|
softMinValue=0,
|
||||||
|
softMaxValue=100,
|
||||||
|
keyable=True)
|
||||||
|
|
@ -12,6 +12,7 @@ from ayon_core.pipeline import (
|
||||||
get_representation_path
|
get_representation_path
|
||||||
)
|
)
|
||||||
from ayon_core.hosts.maya.api import lib
|
from ayon_core.hosts.maya.api import lib
|
||||||
|
from ayon_core.hosts.maya.api.yeti import create_yeti_variable
|
||||||
from ayon_core.hosts.maya.api.pipeline import containerise
|
from ayon_core.hosts.maya.api.pipeline import containerise
|
||||||
from ayon_core.hosts.maya.api.plugin import get_load_color_for_product_type
|
from ayon_core.hosts.maya.api.plugin import get_load_color_for_product_type
|
||||||
|
|
||||||
|
|
@ -23,8 +24,19 @@ SKIP_UPDATE_ATTRS = {
|
||||||
"viewportDensity",
|
"viewportDensity",
|
||||||
"viewportWidth",
|
"viewportWidth",
|
||||||
"viewportLength",
|
"viewportLength",
|
||||||
|
"renderDensity",
|
||||||
|
"renderWidth",
|
||||||
|
"renderLength",
|
||||||
|
"increaseRenderBounds"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SKIP_ATTR_MESSAGE = (
|
||||||
|
"Skipping updating %s.%s to %s because it "
|
||||||
|
"is considered a local overridable attribute. "
|
||||||
|
"Either set manually or the load the cache "
|
||||||
|
"anew."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def set_attribute(node, attr, value):
|
def set_attribute(node, attr, value):
|
||||||
"""Wrapper of set attribute which ignores None values"""
|
"""Wrapper of set attribute which ignores None values"""
|
||||||
|
|
@ -209,9 +221,31 @@ class YetiCacheLoader(load.LoaderPlugin):
|
||||||
|
|
||||||
for attr, value in node_settings["attrs"].items():
|
for attr, value in node_settings["attrs"].items():
|
||||||
if attr in SKIP_UPDATE_ATTRS:
|
if attr in SKIP_UPDATE_ATTRS:
|
||||||
|
self.log.info(
|
||||||
|
SKIP_ATTR_MESSAGE, yeti_node, attr, value
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
set_attribute(attr, value, yeti_node)
|
set_attribute(attr, value, yeti_node)
|
||||||
|
|
||||||
|
# Set up user defined attributes
|
||||||
|
user_variables = node_settings.get("user_variables", {})
|
||||||
|
for attr, value in user_variables.items():
|
||||||
|
was_value_set = create_yeti_variable(
|
||||||
|
yeti_shape_node=yeti_node,
|
||||||
|
attr_name=attr,
|
||||||
|
value=value,
|
||||||
|
# We do not want to update the
|
||||||
|
# value if it already exists so
|
||||||
|
# that any local overrides that
|
||||||
|
# may have been applied still
|
||||||
|
# persist
|
||||||
|
force_value=False
|
||||||
|
)
|
||||||
|
if not was_value_set:
|
||||||
|
self.log.info(
|
||||||
|
SKIP_ATTR_MESSAGE, yeti_node, attr, value
|
||||||
|
)
|
||||||
|
|
||||||
cmds.setAttr("{}.representation".format(container_node),
|
cmds.setAttr("{}.representation".format(container_node),
|
||||||
repre_entity["id"],
|
repre_entity["id"],
|
||||||
typ="string")
|
typ="string")
|
||||||
|
|
@ -332,6 +366,13 @@ class YetiCacheLoader(load.LoaderPlugin):
|
||||||
for attr, value in attributes.items():
|
for attr, value in attributes.items():
|
||||||
set_attribute(attr, value, yeti_node)
|
set_attribute(attr, value, yeti_node)
|
||||||
|
|
||||||
|
# Set up user defined attributes
|
||||||
|
user_variables = node_settings.get("user_variables", {})
|
||||||
|
for attr, value in user_variables.items():
|
||||||
|
create_yeti_variable(yeti_shape_node=yeti_node,
|
||||||
|
attr_name=attr,
|
||||||
|
value=value)
|
||||||
|
|
||||||
# Connect to the time node
|
# Connect to the time node
|
||||||
cmds.connectAttr("time1.outTime", "%s.currentTime" % yeti_node)
|
cmds.connectAttr("time1.outTime", "%s.currentTime" % yeti_node)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ from maya import cmds
|
||||||
import pyblish.api
|
import pyblish.api
|
||||||
|
|
||||||
from ayon_core.hosts.maya.api import lib
|
from ayon_core.hosts.maya.api import lib
|
||||||
|
from ayon_core.hosts.maya.api.yeti import get_yeti_user_variables
|
||||||
|
|
||||||
|
|
||||||
SETTINGS = {
|
SETTINGS = {
|
||||||
|
|
@ -34,7 +35,7 @@ class CollectYetiCache(pyblish.api.InstancePlugin):
|
||||||
- "increaseRenderBounds"
|
- "increaseRenderBounds"
|
||||||
- "imageSearchPath"
|
- "imageSearchPath"
|
||||||
|
|
||||||
Other information is the name of the transform and it's Colorbleed ID
|
Other information is the name of the transform and its `cbId`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
order = pyblish.api.CollectorOrder + 0.45
|
order = pyblish.api.CollectorOrder + 0.45
|
||||||
|
|
@ -54,6 +55,16 @@ class CollectYetiCache(pyblish.api.InstancePlugin):
|
||||||
# Get specific node attributes
|
# Get specific node attributes
|
||||||
attr_data = {}
|
attr_data = {}
|
||||||
for attr in SETTINGS:
|
for attr in SETTINGS:
|
||||||
|
# Ignore non-existing attributes with a warning, e.g. cbId
|
||||||
|
# if they have not been generated yet
|
||||||
|
if not cmds.attributeQuery(attr, node=shape, exists=True):
|
||||||
|
self.log.warning(
|
||||||
|
"Attribute '{}' not found on Yeti node: {}".format(
|
||||||
|
attr, shape
|
||||||
|
)
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
current = cmds.getAttr("%s.%s" % (shape, attr))
|
current = cmds.getAttr("%s.%s" % (shape, attr))
|
||||||
# change None to empty string as Maya doesn't support
|
# change None to empty string as Maya doesn't support
|
||||||
# NoneType in attributes
|
# NoneType in attributes
|
||||||
|
|
@ -61,6 +72,12 @@ class CollectYetiCache(pyblish.api.InstancePlugin):
|
||||||
current = ""
|
current = ""
|
||||||
attr_data[attr] = current
|
attr_data[attr] = current
|
||||||
|
|
||||||
|
# Get user variable attributes
|
||||||
|
user_variable_attrs = {
|
||||||
|
attr: lib.get_attribute("{}.{}".format(shape, attr))
|
||||||
|
for attr in get_yeti_user_variables(shape)
|
||||||
|
}
|
||||||
|
|
||||||
# Get transform data
|
# Get transform data
|
||||||
parent = cmds.listRelatives(shape, parent=True)[0]
|
parent = cmds.listRelatives(shape, parent=True)[0]
|
||||||
transform_data = {"name": parent, "cbId": lib.get_id(parent)}
|
transform_data = {"name": parent, "cbId": lib.get_id(parent)}
|
||||||
|
|
@ -70,6 +87,7 @@ class CollectYetiCache(pyblish.api.InstancePlugin):
|
||||||
"name": shape,
|
"name": shape,
|
||||||
"cbId": lib.get_id(shape),
|
"cbId": lib.get_id(shape),
|
||||||
"attrs": attr_data,
|
"attrs": attr_data,
|
||||||
|
"user_variables": user_variable_attrs
|
||||||
}
|
}
|
||||||
|
|
||||||
settings["nodes"].append(shape_data)
|
settings["nodes"].append(shape_data)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue