Skip to content

Instantly share code, notes, and snippets.

@BigRoy
Last active October 5, 2023 18:29
Show Gist options
  • Save BigRoy/eddac6a93ad4ff233e2757c6bbccf3da to your computer and use it in GitHub Desktop.
Save BigRoy/eddac6a93ad4ff233e2757c6bbccf3da to your computer and use it in GitHub Desktop.
Autodesk Maya Python list or query all children including each instance
"""When using maya.cmds.listRelatives with allDescendents=True it will only return the first instanced child.
Below are some example functions that correctly return all instanced children where they are "somewhat" optimized to rapidly return a result as opposed to slow recursive queries.
"""
import maya.api.OpenMaya as om
from maya import cmds
import time
import re
def iter_parents(node):
"""Iter parents of node from its long name.
Note: The `node` *must* be the long node name.
Args:
node (str): Node long name.
Yields:
str: All parent node names (long names)
"""
while True:
split = node.rsplit("|", 1)
if len(split) == 1 or not split[0]:
return
node = split[0]
yield node
def get_highest_in_hierarchy(nodes):
"""Return highest nodes in the hierarchy that are in the `nodes` list.
The "highest in hierarchy" are the nodes closest to world: top-most level.
Args:
nodes (list): The nodes in which find the highest in hierarchies.
Returns:
list: The highest nodes from the input nodes.
"""
# Ensure we use long names
nodes = cmds.ls(nodes, long=True)
if len(nodes) < 2:
return nodes
lookup = set(nodes)
highest = []
for node in nodes:
# If no parents are within the nodes input list
# then this is a highest node
if not any(n in lookup for n in iter_parents(node)):
highest.append(node)
return highest
def list_all_children(nodes):
"""Fast, but slow when nesting is very deep."""
result = set()
children = set(cmds.listRelatives(nodes, fullPath=True) or [])
while children:
result.update(children)
children = set(cmds.listRelatives(children, fullPath=True) or []) - result
return list(result)
def list_all_children2(nodes):
"""Invalid because it will ignore a child if it's in 'nodes'
whilst it was a child of another node in the list."""
nodes = cmds.ls(nodes, long=True)
lookup = set(nodes) # parent lookup
hierarchy = cmds.ls(nodes, dag=True, long=True, allPaths=True)
children = []
for node in hierarchy:
if node in lookup:
# Ignore self
continue
if not any(node.startswith(x) for x in lookup):
# Only include if it has a parent in the original nodes
continue
children.append(node)
return children
def list_all_children4(nodes):
"""
Fastest with few input `nodes` (<1000)
"""
roots = get_highest_in_hierarchy(nodes)
# Escape the | in the node paths, this is faster than re.escape()
# And also join an extra "\|" to make sure it will only capture
# its children.
src = "|"
to = r"\|"
prefixes = ["".join([n.replace(src, to), to]) for n in roots]
rx = re.compile(''.join(['^(?:', '|'.join(prefixes), ')']))
hierarchy = cmds.ls(roots, dag=True, long=True, allPaths=True)
return [child for child in children if rx.match(child)]
def list_all_children5(nodes):
"""
Fastest with many input `nodes` (1000+)
"""
sel = om.MSelectionList()
traversed = set()
iterator = om.MItDag(om.MItDag.kDepthFirst)
for node in nodes:
if node in traversed:
# Ignore if already processed as a child
# before
continue
sel.clear()
sel.add(node)
dag = sel.getDagPath(0)
iterator.reset(dag)
iterator.next() # ignore self
while not iterator.isDone():
path = iterator.fullPathName()
if path in traversed:
iterator.prune()
iterator.next()
continue
traversed.add(path)
iterator.next()
return list(traversed)
def list_all_children6(nodes):
"""Quite slow but accurate - just use Select > Select Hierarchy as trick.."""
sel = cmds.ls(sl=1)
cmds.select(nodes, hierarchy=True, replace=True)
hierarchy = cmds.ls(selection=True, long=True)
cmds.select(sel, replace=True)
return hierarchy
members = cmds.ls(sl=1, long=True)
s = time.time()
print("list_all_children")
children = list_all_children(members)
e = time.time()
num = len(children)
print num
print e-s
s = time.time()
print("list_all_children4")
children = list_all_children4(members)
e = time.time()
num = len(children)
print num
print e-s
s = time.time()
print("list_all_children5")
children = list_all_children5(members)
e = time.time()
num = len(children)
print num
print e-s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment