mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 12:54:40 +01:00
look validation improvements
This commit is contained in:
parent
d19223e26a
commit
fea1560978
8 changed files with 66 additions and 99 deletions
|
|
@ -97,11 +97,8 @@ def on_save(_):
|
|||
|
||||
avalon.logger.info("Running callback on save..")
|
||||
|
||||
types = ["objectSet", "file", "mesh", "nurbsCurve", "nurbsSurface"]
|
||||
type_nodes = set(cmds.ls(type=types, long=True))
|
||||
nodes = lib.filter_out_nodes(type_nodes,
|
||||
defaults=True,
|
||||
referenced_nodes=True)
|
||||
nodes = lib.get_id_required_nodes(defaults=True,
|
||||
referenced_nodes=True)
|
||||
|
||||
# Lead with asset ID from the database
|
||||
asset = os.environ["AVALON_ASSET"]
|
||||
|
|
|
|||
|
|
@ -613,7 +613,7 @@ def remap_resource_nodes(resources, folder=None):
|
|||
cmds.file(save=True, type="mayaAscii")
|
||||
|
||||
|
||||
def filter_out_nodes(nodes, defaults=False, referenced_nodes=False):
|
||||
def get_id_required_nodes(defaults=True, referenced_nodes=True):
|
||||
"""Filter out any node which are locked (reference) or readOnly
|
||||
|
||||
Args:
|
||||
|
|
@ -621,11 +621,13 @@ def filter_out_nodes(nodes, defaults=False, referenced_nodes=False):
|
|||
defaults (bool): set True to filter out default nodes
|
||||
referenced_nodes (bool): set True to filter out reference nodes
|
||||
Returns:
|
||||
nodes (list): list of filtered nodes
|
||||
nodes (set): list of filtered nodes
|
||||
"""
|
||||
# establish set of nodes to ignore
|
||||
|
||||
|
||||
# `readOnly` flag is obsolete as of Maya 2016 therefor we explicitly remove
|
||||
# default nodes and reference nodes
|
||||
camera_shapes = ["frontShape", "sideShape", "topShape", "perspShape"]
|
||||
|
||||
ignore = set()
|
||||
if referenced_nodes:
|
||||
|
|
@ -633,16 +635,26 @@ def filter_out_nodes(nodes, defaults=False, referenced_nodes=False):
|
|||
|
||||
if defaults:
|
||||
ignore |= set(cmds.ls(long=True, defaultNodes=defaults))
|
||||
ignore |= set(cmds.ls(camera_shapes, long=True))
|
||||
|
||||
# establish set of nodes to ignore
|
||||
types = ["objectSet", "file", "mesh", "nurbsCurve", "nurbsSurface"]
|
||||
|
||||
# We *always* ignore intermediate shapes, so we filter them out
|
||||
# directly
|
||||
nodes = cmds.ls(type=types, long=True, noIntermediate=True)
|
||||
|
||||
# The items which need to pass the id to their parent
|
||||
# Add the collected transform to the nodes
|
||||
dag = cmds.ls(list(nodes),
|
||||
dag = cmds.ls(nodes,
|
||||
type="dagNode",
|
||||
long=True) # query only dag nodes
|
||||
|
||||
transforms = cmds.listRelatives(dag,
|
||||
parent=True,
|
||||
fullPath=True) or []
|
||||
|
||||
nodes = set(nodes)
|
||||
nodes |= set(transforms)
|
||||
nodes -= ignore # Remove the ignored nodes
|
||||
|
||||
|
|
|
|||
|
|
@ -123,9 +123,11 @@ class CollectLook(pyblish.api.InstancePlugin):
|
|||
"relationships": sets.values(),
|
||||
"sets": looksets}
|
||||
|
||||
# Collect file nodes used by shading engines
|
||||
history = cmds.listHistory(looksets)
|
||||
files = cmds.ls(history, type="file", long=True)
|
||||
# Collect file nodes used by shading engines (if we have any)
|
||||
files = list()
|
||||
if looksets:
|
||||
history = cmds.listHistory(looksets)
|
||||
files = cmds.ls(history, type="file", long=True)
|
||||
|
||||
# Collect textures
|
||||
resources = [self.collect_resource(n) for n in files]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import maya.cmds as cmds
|
||||
|
||||
import pyblish.api
|
||||
import colorbleed.api
|
||||
|
||||
|
|
@ -15,34 +13,27 @@ class ValidateLookContents(pyblish.api.InstancePlugin):
|
|||
order = colorbleed.api.ValidateContentsOrder
|
||||
families = ['colorbleed.lookdev']
|
||||
hosts = ['maya']
|
||||
label = 'Look Contents'
|
||||
label = 'Look Data Contents'
|
||||
actions = [colorbleed.api.SelectInvalidAction]
|
||||
|
||||
invalid = []
|
||||
errors = []
|
||||
|
||||
def process(self, instance):
|
||||
"""Process all the nodes in the instance"""
|
||||
|
||||
if not instance[:]:
|
||||
raise RuntimeError("Instance is empty")
|
||||
|
||||
self.get_invalid(instance)
|
||||
|
||||
if self.errors:
|
||||
error_string = "\n".join(self.errors)
|
||||
raise RuntimeError("Invalid look content. "
|
||||
"Errors : {}".format(error_string))
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
raise RuntimeError("Invalid look content")
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, instance):
|
||||
"""Get all invalid nodes"""
|
||||
|
||||
attributes = list(cls.validate_lookdata_attributes(instance))
|
||||
relationships = list(cls.validate_relationships(instance))
|
||||
non_defaults = cls.validate_non_defaults(instance)
|
||||
relationships = list(cls.validate_relationship_ids(instance))
|
||||
|
||||
invalid = attributes + relationships + non_defaults
|
||||
invalid = attributes + relationships
|
||||
|
||||
return invalid
|
||||
|
||||
|
|
@ -61,14 +52,18 @@ class ValidateLookContents(pyblish.api.InstancePlugin):
|
|||
lookdata = instance.data["lookData"]
|
||||
for attr in attributes:
|
||||
if attr not in lookdata:
|
||||
cls.errors.append("Look Data has no attribute "
|
||||
"'{}'".format(attr))
|
||||
cls.log.error("Look Data has no attribute "
|
||||
"'{}'".format(attr))
|
||||
invalid.add(instance.name)
|
||||
|
||||
if not lookdata["relationships"] or not lookdata["sets"]:
|
||||
cls.log.error("Look has no `relationship` or `sets`")
|
||||
invalid.add(instance.name)
|
||||
|
||||
return invalid
|
||||
|
||||
@classmethod
|
||||
def validate_relationships(cls, instance):
|
||||
def validate_relationship_ids(cls, instance):
|
||||
"""Validate and update lookData relationships"""
|
||||
|
||||
invalid = set()
|
||||
|
|
@ -76,41 +71,9 @@ class ValidateLookContents(pyblish.api.InstancePlugin):
|
|||
relationships = instance.data["lookData"]["relationships"]
|
||||
for relationship in relationships:
|
||||
look_name = relationship["name"]
|
||||
for key, value in relationship.items():
|
||||
if value is None:
|
||||
cls.errors.append("{} has invalid attribute "
|
||||
"'{}'".format(look_name, key))
|
||||
|
||||
invalid.add(look_name)
|
||||
|
||||
return invalid
|
||||
|
||||
@classmethod
|
||||
def validate_non_defaults(cls, instance):
|
||||
"""Check if instance content items are part of the default nodes"""
|
||||
|
||||
invalid = []
|
||||
cams = ["perspShape", "topShape", "frontShape", "sideShape"]
|
||||
cameras = cmds.ls(cams, long=True)
|
||||
references = cmds.ls(referencedNodes=True)
|
||||
default_nodes = cmds.ls(defaultNodes=True, long=True)
|
||||
|
||||
defaults = list(set(cameras + references + default_nodes))
|
||||
|
||||
for node in cmds.ls(instance[:], long=True):
|
||||
# might be a transform of a default item listed
|
||||
if cmds.nodeType(node) == "transform":
|
||||
children = cmds.listRelatives(node,
|
||||
children=True,
|
||||
fullPath=True)
|
||||
if children:
|
||||
node = children
|
||||
else:
|
||||
continue
|
||||
|
||||
if node in defaults:
|
||||
invalid.append(node)
|
||||
cls.errors.append("'{}' is part of Maya default "
|
||||
"nodes".format(node))
|
||||
uuid = relationship["uuid"]
|
||||
if not uuid:
|
||||
cls.errors.append("{} has invalid ID ")
|
||||
invalid.add(look_name)
|
||||
|
||||
return invalid
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
import maya.cmds as cmds
|
||||
|
||||
import pyblish.api
|
||||
import colorbleed.api
|
||||
import colorbleed.maya.lib as lib
|
||||
|
||||
|
||||
class ValidateLookMembersHaveId(pyblish.api.InstancePlugin):
|
||||
class ValidateLookMembers(pyblish.api.InstancePlugin):
|
||||
"""Validate look members have colorbleed id attributes
|
||||
|
||||
Looks up the contents of the look to see if all its members have
|
||||
|
|
@ -18,28 +20,28 @@ class ValidateLookMembersHaveId(pyblish.api.InstancePlugin):
|
|||
order = colorbleed.api.ValidatePipelineOrder
|
||||
families = ['colorbleed.lookdev']
|
||||
hosts = ['maya']
|
||||
label = 'Look Members Have ID Attribute'
|
||||
label = 'Look Members'
|
||||
actions = [colorbleed.api.SelectInvalidAction,
|
||||
colorbleed.api.GenerateUUIDsOnInvalidAction]
|
||||
|
||||
def process(self, instance):
|
||||
"""Process all meshes"""
|
||||
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
invalid_ids = self.get_invalid(instance)
|
||||
if invalid_ids:
|
||||
raise RuntimeError("Members found without "
|
||||
"asset IDs: {0}".format(invalid))
|
||||
"asset IDs: {0}".format(invalid_ids))
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, instance):
|
||||
|
||||
# Get all members from the sets
|
||||
members = set()
|
||||
relations = instance.data["lookData"]["relationships"]
|
||||
for relation in relations:
|
||||
relationships = instance.data["lookData"]["relationships"]
|
||||
for relation in relationships:
|
||||
members.update([member['name'] for member in relation['members']])
|
||||
|
||||
# Ensure all nodes have a cbId
|
||||
invalid = [m for m in members if not lib.get_id(m)]
|
||||
if invalid:
|
||||
raise RuntimeError("Found invalid nodes.\nNo ID : "
|
||||
"{}".format(invalid))
|
||||
|
||||
return invalid
|
||||
|
|
|
|||
|
|
@ -37,16 +37,15 @@ class ValidateLookNoDefaultShaders(pyblish.api.InstancePlugin):
|
|||
"initialParticleSE",
|
||||
"particleCloud1"]
|
||||
|
||||
setmembers = instance.data["setMembers"]
|
||||
members = cmds.listRelatives(setmembers,
|
||||
members = cmds.listRelatives(instance,
|
||||
allDescendents=True,
|
||||
type="shape")
|
||||
|
||||
shapes=True,
|
||||
noIntermediate=True) or []
|
||||
for member in members:
|
||||
|
||||
# get connection
|
||||
# listConnections returns a list or None
|
||||
shading_engine = cmds.listConnections(member, type="shadingEngine")
|
||||
shading_engine = cmds.listConnections(member, type="objectSet")
|
||||
if not shading_engine:
|
||||
cls.log.error("Detected shape without shading engine : "
|
||||
"'{}'".format(member))
|
||||
|
|
@ -58,6 +57,7 @@ class ValidateLookNoDefaultShaders(pyblish.api.InstancePlugin):
|
|||
if shading_engine in disallowed:
|
||||
cls.log.error("Member connected to a disallows objectSet: "
|
||||
"'{}'".format(member))
|
||||
invalid.append(member)
|
||||
else:
|
||||
continue
|
||||
|
||||
|
|
@ -66,7 +66,6 @@ class ValidateLookNoDefaultShaders(pyblish.api.InstancePlugin):
|
|||
def process(self, instance):
|
||||
"""Process all the nodes in the instance"""
|
||||
|
||||
# sets = self.get_invalid_sets(instance)
|
||||
sets = self.get_invalid(instance)
|
||||
if sets:
|
||||
raise RuntimeError("Invalid shaders found: {0}".format(sets))
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
raise RuntimeError("Invalid shaders found: {0}".format(invalid))
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ class ValidateSingleShader(pyblish.api.InstancePlugin):
|
|||
for shape in shapes:
|
||||
shading_engines = cmds.listConnections(shape,
|
||||
destination=True,
|
||||
type="shadingEngine")
|
||||
type="shadingEngine") or []
|
||||
if len(shading_engines) > 1:
|
||||
invalid.append(shape)
|
||||
|
||||
|
|
|
|||
|
|
@ -36,18 +36,10 @@ class ValidateNodeIDs(pyblish.api.InstancePlugin):
|
|||
|
||||
# We do want to check the referenced nodes as it might be
|
||||
# part of the end product
|
||||
nodes = lib.filter_out_nodes(set(instance[:]), defaults=True)
|
||||
invalid = [n for n in nodes if not lib.get_id(n)
|
||||
and not cls.validate_children(n)]
|
||||
id_nodes = lib.get_id_required_nodes(defaults=True,
|
||||
referenced_nodes=False)
|
||||
|
||||
nodes = instance[:]
|
||||
invalid = [n for n in nodes if n in id_nodes and not lib.get_id(n)]
|
||||
|
||||
return invalid
|
||||
|
||||
@staticmethod
|
||||
def validate_children(node):
|
||||
"""Validate the children of the node if the ID is not present"""
|
||||
|
||||
children = cmds.listRelatives(node, children=True)
|
||||
for child in children:
|
||||
if lib.get_id(child):
|
||||
return True
|
||||
return False
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue