mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 12:54:40 +01:00
improved collectors
This commit is contained in:
parent
e0fa549f0b
commit
9a70383051
3 changed files with 233 additions and 25 deletions
|
|
@ -3,7 +3,7 @@ from maya import cmds
|
|||
import pyblish.api
|
||||
|
||||
|
||||
class CollectMindbenderInstances(pyblish.api.ContextPlugin):
|
||||
class CollectInstances(pyblish.api.ContextPlugin):
|
||||
"""Gather instances by objectSet and pre-defined attribute
|
||||
|
||||
This collector takes into account assets that are associated with
|
||||
|
|
@ -38,14 +38,24 @@ class CollectMindbenderInstances(pyblish.api.ContextPlugin):
|
|||
|
||||
"""
|
||||
|
||||
label = "Collect Mindbender Instances"
|
||||
label = "Collect Instances"
|
||||
order = pyblish.api.CollectorOrder
|
||||
hosts = ["maya"]
|
||||
isntance_order = ["colorbleed.model",
|
||||
"colorbleed.rig",
|
||||
"colorbleed.animation",
|
||||
"colorbleed.camera",
|
||||
"colorbleed.texture",
|
||||
"colorbleed.lookdev",
|
||||
"colorbleed.historyLookdev",
|
||||
"colorbleed.group"]
|
||||
|
||||
def process(self, context):
|
||||
|
||||
objectset = cmds.ls("*.id", long=True, type="objectSet",
|
||||
recursive=True, objectsOnly=True)
|
||||
for objset in objectset:
|
||||
self.log.info("Creating instance for {}".format(objset))
|
||||
|
||||
members = cmds.sets(objset, query=True)
|
||||
if members is None:
|
||||
|
|
@ -61,7 +71,8 @@ class CollectMindbenderInstances(pyblish.api.ContextPlugin):
|
|||
|
||||
# The developer is responsible for specifying
|
||||
# the family of each instance.
|
||||
has_family = cmds.attributeQuery("family", node=objset,
|
||||
has_family = cmds.attributeQuery("family",
|
||||
node=objset,
|
||||
exists=True)
|
||||
assert has_family, "\"%s\" was missing a family" % objset
|
||||
|
||||
|
|
@ -70,7 +81,7 @@ class CollectMindbenderInstances(pyblish.api.ContextPlugin):
|
|||
# Apply each user defined attribute as data
|
||||
for attr in cmds.listAttr(objset, userDefined=True) or list():
|
||||
try:
|
||||
value = cmds.getAttr("{}.{}".format(objset, attr))
|
||||
value = cmds.getAttr("%s.%s" % (objset, attr))
|
||||
except Exception:
|
||||
# Some attributes cannot be read directly,
|
||||
# such as mesh and color attributes. These
|
||||
|
|
@ -82,9 +93,10 @@ class CollectMindbenderInstances(pyblish.api.ContextPlugin):
|
|||
|
||||
# Collect members
|
||||
members = cmds.ls(members, long=True) or []
|
||||
|
||||
children = cmds.listRelatives(members,
|
||||
allDescendents=True,
|
||||
fullPath=True)
|
||||
fullPath=True) or []
|
||||
parents = self.get_all_parents(members)
|
||||
members_hierarchy = list(set(members + children + parents))
|
||||
|
||||
|
|
@ -99,6 +111,10 @@ class CollectMindbenderInstances(pyblish.api.ContextPlugin):
|
|||
# user interface interested in visualising it.
|
||||
self.log.info("Found: \"%s\" " % instance.data["name"])
|
||||
|
||||
context[:] = sorted(context)
|
||||
|
||||
return context
|
||||
|
||||
def get_all_parents(self, nodes):
|
||||
"""Get all parents by using string operations (optimization)
|
||||
|
||||
|
|
@ -108,6 +124,7 @@ class CollectMindbenderInstances(pyblish.api.ContextPlugin):
|
|||
Returns:
|
||||
list
|
||||
"""
|
||||
|
||||
parents = []
|
||||
for node in nodes:
|
||||
splitted = node.split("|")
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
from maya import cmds
|
||||
|
||||
from cb.utils.maya import context
|
||||
import cbra.utils.maya.node_uuid as id_utils
|
||||
import pyblish.api
|
||||
|
||||
from cb.utils.maya import context, shaders
|
||||
import cbra.utils.maya.node_uuid as id_utils
|
||||
|
||||
SHAPE_ATTRS = ["castsShadows",
|
||||
"receiveShadows",
|
||||
|
|
@ -37,8 +37,8 @@ def get_look_attrs(node):
|
|||
valid = [attr for attr in attrs if attr in SHAPE_ATTRS]
|
||||
result.extend(valid)
|
||||
|
||||
if "mbID" in result:
|
||||
result.remove("mbID")
|
||||
if "cbId" in result:
|
||||
result.remove("cbId")
|
||||
|
||||
return result
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ class CollectLook(pyblish.api.InstancePlugin):
|
|||
"""
|
||||
|
||||
order = pyblish.api.CollectorOrder + 0.4
|
||||
families = ["colorbleed.look"]
|
||||
families = ["colorbleed.lookdev"]
|
||||
label = "Collect Look"
|
||||
hosts = ["maya"]
|
||||
|
||||
|
|
@ -120,6 +120,9 @@ class CollectLook(pyblish.api.InstancePlugin):
|
|||
instance.data["lookData"] = {"attributes": attributes,
|
||||
"relationships": sets.values(),
|
||||
"sets": looksets}
|
||||
# Collect textures
|
||||
resources = [self.collect_resources(n) for n in cmds.ls(type="file")]
|
||||
instance.data["resources"] = resources
|
||||
|
||||
# Log a warning when no relevant sets were retrieved for the look.
|
||||
if not instance.data["lookData"]["sets"]:
|
||||
|
|
@ -157,7 +160,8 @@ class CollectLook(pyblish.api.InstancePlugin):
|
|||
for objset in related_sets:
|
||||
if objset in sets:
|
||||
continue
|
||||
unique_id = cmds.getAttr("%s.mbID" % objset)
|
||||
|
||||
unique_id = cmds.getAttr("%s.cbId" % objset)
|
||||
sets[objset] = {"name": objset,
|
||||
"uuid": unique_id,
|
||||
"members": list()}
|
||||
|
|
@ -253,11 +257,24 @@ class CollectLook(pyblish.api.InstancePlugin):
|
|||
if member in [m["name"] for m in objset_members]:
|
||||
return
|
||||
|
||||
# check node type, if mesh get parent! makes assigning shaders easier
|
||||
if cmds.nodeType(node) == "mesh":
|
||||
parent = cmds.listRelatives(node, parent=True, fullPath=True)
|
||||
# a mesh NEEDS to have a parent in Maya logic, no reason for
|
||||
# assertions or extra checking
|
||||
parent = parent[0]
|
||||
if cmds.attributeQuery("cbId", node=parent, exists=True):
|
||||
node = parent
|
||||
else:
|
||||
self.log.error("Transform group of mesh '{}' has no attribute "
|
||||
"'cbId', this is manditory")
|
||||
return
|
||||
|
||||
if verbose:
|
||||
self.log.debug("Such as %s.." % member)
|
||||
|
||||
member_data = {"name": node,
|
||||
"uuid": cmds.getAttr("{}.mbID".format(node, ))}
|
||||
"uuid": cmds.getAttr("{}.cbId".format(node))}
|
||||
|
||||
# Include components information when components are assigned
|
||||
if components:
|
||||
|
|
@ -304,3 +321,46 @@ class CollectLook(pyblish.api.InstancePlugin):
|
|||
attributes.append(data)
|
||||
|
||||
return attributes
|
||||
|
||||
def collect_resources(self, node, verbose=False):
|
||||
"""Collect the link to the file(s) used (resource)
|
||||
Args:
|
||||
node (str): name of the node
|
||||
verbose (bool): enable debug information
|
||||
|
||||
Returns:
|
||||
dict
|
||||
"""
|
||||
|
||||
attribute = "{}.fileTextureName".format(node)
|
||||
source = cmds.getAttr(attribute)
|
||||
|
||||
# Get the computed file path (e.g. the one with the <UDIM> pattern
|
||||
# in it) So we can reassign it this computed file path whenever
|
||||
# we need to.
|
||||
computed_attribute = "{}.computedFileTextureNamePattern".format(node)
|
||||
computed_source = cmds.getAttr(computed_attribute)
|
||||
if source != computed_source:
|
||||
if verbose:
|
||||
self.log.debug("File node computed pattern differs from "
|
||||
"original pattern: {0} "
|
||||
"({1} -> {2})".format(node,
|
||||
source,
|
||||
computed_source))
|
||||
|
||||
# We replace backslashes with forward slashes because V-Ray
|
||||
# can't handle the UDIM files with the backslashes in the
|
||||
# paths as the computed patterns
|
||||
source = computed_source.replace("\\", "/")
|
||||
|
||||
files = shaders.get_file_node_files(node)
|
||||
if not files:
|
||||
self.log.error("File node does not have a texture set: "
|
||||
"{0}".format(node))
|
||||
return
|
||||
|
||||
# Define the resource
|
||||
return {"node": node,
|
||||
"attribute": attribute,
|
||||
"source": source, # required for resources
|
||||
"files": files} # required for resources
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
from maya import cmds
|
||||
|
||||
import pyblish.api
|
||||
|
||||
import cb.utils.maya.shaders as shaders
|
||||
|
||||
TAGS = ["maya", "attribute", "look"]
|
||||
|
|
@ -72,23 +71,37 @@ class CollectLookTextures(pyblish.api.InstancePlugin):
|
|||
|
||||
"""
|
||||
|
||||
order = pyblish.api.CollectorOrder + 0.498
|
||||
label = 'Textures'
|
||||
order = pyblish.api.CollectorOrder + 0.35
|
||||
label = 'Collect Look Textures'
|
||||
families = ["colorbleed.texture"]
|
||||
actions = [SelectTextureNodesAction]
|
||||
|
||||
IGNORE = ["out_SET", "controls_SET", "_INST"]
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
verbose = instance.data.get("verbose", False)
|
||||
|
||||
# Get textures from sets
|
||||
sets = instance.data["lookData"]["sets"]
|
||||
if not sets:
|
||||
raise RuntimeError("No look sets found for the nodes in the "
|
||||
"instance. %s" % sets)
|
||||
# Get all texture nodes from the shader networks
|
||||
sets = self.gather_sets(instance)
|
||||
instance_members = {str(i) for i in cmds.ls(instance, long=True,
|
||||
absoluteName=True)}
|
||||
|
||||
self.log.info("Gathering set relations..")
|
||||
for objset in sets:
|
||||
self.log.debug("From %s.." % objset)
|
||||
content = cmds.sets(objset, query=True)
|
||||
objset_members = sets[objset]["members"]
|
||||
for member in cmds.ls(content, long=True, absoluteName=True):
|
||||
member_data = self.collect_member_data(member,
|
||||
objset_members,
|
||||
instance_members,
|
||||
verbose)
|
||||
if not member_data:
|
||||
continue
|
||||
|
||||
# Get the file nodes
|
||||
history = cmds.listHistory(sets) or []
|
||||
history = cmds.listHistory(sets.keys()) or []
|
||||
files = cmds.ls(history, type="file")
|
||||
files = list(set(files))
|
||||
|
||||
|
|
@ -99,9 +112,44 @@ class CollectLookTextures(pyblish.api.InstancePlugin):
|
|||
continue
|
||||
resources.append(resource)
|
||||
|
||||
# Store resources
|
||||
instance.data['resources'] = resources
|
||||
|
||||
def gather_sets(self, instance):
|
||||
"""Gather all objectSets which are of importance for publishing
|
||||
|
||||
It checks if all nodes in the instance are related to any objectSet
|
||||
which need to be
|
||||
|
||||
Args:
|
||||
instance (list): all nodes to be published
|
||||
|
||||
Returns:
|
||||
dict
|
||||
"""
|
||||
|
||||
# Get view sets (so we can ignore those sets later)
|
||||
sets = dict()
|
||||
view_sets = set()
|
||||
for panel in cmds.getPanel(type="modelPanel"):
|
||||
view_set = cmds.modelEditor(panel, query=True,
|
||||
viewObjects=True)
|
||||
if view_set:
|
||||
view_sets.add(view_set)
|
||||
|
||||
for node in instance:
|
||||
related_sets = self.get_related_sets(node, view_sets)
|
||||
if not related_sets:
|
||||
continue
|
||||
|
||||
for objset in related_sets:
|
||||
if objset in sets:
|
||||
continue
|
||||
unique_id = cmds.getAttr("%s.cbId" % objset)
|
||||
sets[objset] = {"name": objset,
|
||||
"uuid": unique_id,
|
||||
"members": list()}
|
||||
return sets
|
||||
|
||||
def collect_resources(self, node, verbose=False):
|
||||
"""Collect the link to the file(s) used (resource)
|
||||
Args:
|
||||
|
|
@ -112,6 +160,8 @@ class CollectLookTextures(pyblish.api.InstancePlugin):
|
|||
dict
|
||||
"""
|
||||
|
||||
# assure node includes full path
|
||||
node = cmds.ls(node, long=True)[0]
|
||||
attribute = "{}.fileTextureName".format(node)
|
||||
source = cmds.getAttr(attribute)
|
||||
|
||||
|
|
@ -146,8 +196,89 @@ class CollectLookTextures(pyblish.api.InstancePlugin):
|
|||
"node": node,
|
||||
"attribute": attribute,
|
||||
"source": source, # required for resources
|
||||
"files": files, # required for resources
|
||||
"subfolder": "textures", # optional for resources
|
||||
}
|
||||
"files": files} # required for resources
|
||||
|
||||
return resource
|
||||
|
||||
def collect_member_data(self, member, objset_members, instance_members,
|
||||
verbose=False):
|
||||
"""Get all information of the node
|
||||
Args:
|
||||
member (str): the name of the node to check
|
||||
objset_members (list): the objectSet members
|
||||
instance_members (set): the collected instance members
|
||||
verbose (bool): get debug information
|
||||
|
||||
Returns:
|
||||
dict
|
||||
|
||||
"""
|
||||
|
||||
node, components = (member.rsplit(".", 1) + [None])[:2]
|
||||
|
||||
# Only include valid members of the instance
|
||||
if node not in instance_members:
|
||||
if verbose:
|
||||
self.log.info("Skipping member %s" % member)
|
||||
return
|
||||
|
||||
if member in [m["name"] for m in objset_members]:
|
||||
return
|
||||
|
||||
if verbose:
|
||||
self.log.debug("Such as %s.." % member)
|
||||
|
||||
member_data = {"name": node,
|
||||
"uuid": cmds.getAttr("{}.cbId".format(node, ))}
|
||||
|
||||
# Include components information when components are assigned
|
||||
if components:
|
||||
member_data["components"] = components
|
||||
|
||||
return member_data
|
||||
|
||||
def get_related_sets(self, node, view_sets):
|
||||
"""Get the sets which do not belong to any specific group
|
||||
|
||||
Filters out based on:
|
||||
- id attribute is NOT `pyblish.avalon.container`
|
||||
- shapes and deformer shapes (alembic creates meshShapeDeformed)
|
||||
- set name ends with any from a predefined list
|
||||
- set in not in viewport set (isolate selected for example)
|
||||
|
||||
Args:
|
||||
node (str): name of the current not to check
|
||||
"""
|
||||
|
||||
ignored = ["pyblish.avalon.instance", "pyblish.avalon.container"]
|
||||
|
||||
related_sets = cmds.listSets(object=node, extendToShape=False)
|
||||
if not related_sets:
|
||||
return []
|
||||
|
||||
# Ignore containers
|
||||
sets = [s for s in related_sets if
|
||||
not cmds.attributeQuery("id", node=s, exists=True) or
|
||||
not cmds.getAttr("%s.id" % s) in ignored]
|
||||
|
||||
# Exclude deformer sets
|
||||
# Autodesk documentation on listSets command:
|
||||
# type(uint) : Returns all sets in the scene of the given
|
||||
# >>> type:
|
||||
# >>> 1 - all rendering sets
|
||||
# >>> 2 - all deformer sets
|
||||
deformer_sets = cmds.listSets(object=node, extendToShape=False,
|
||||
type=2) or []
|
||||
deformer_sets = set(deformer_sets) # optimize lookup
|
||||
sets = [s for s in sets if s not in deformer_sets]
|
||||
|
||||
# Ignore specifically named sets
|
||||
sets = [s for s in sets if not any(s.endswith(x) for x in self.IGNORE)]
|
||||
|
||||
# Ignore viewport filter view sets (from isolate select and
|
||||
# viewports)
|
||||
sets = [s for s in sets if s not in view_sets]
|
||||
|
||||
self.log.info("Found sets %s for %s" % (related_sets, node))
|
||||
|
||||
return sets
|
||||
Loading…
Add table
Add a link
Reference in a new issue