look validation improvements

This commit is contained in:
aardschok 2017-08-09 16:34:29 +02:00
parent d19223e26a
commit fea1560978
8 changed files with 66 additions and 99 deletions

View file

@ -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"]

View file

@ -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

View file

@ -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]

View file

@ -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

View file

@ -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

View file

@ -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))

View file

@ -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)

View file

@ -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