【问题标题】:Testing if an object is dependent to another object测试一个对象是否依赖于另一个对象
【发布时间】:2015-10-29 03:52:12
【问题描述】:

有没有办法检查一个对象是否通过父级、约束或与另一个对象的连接来依赖?我想在父对象之前做这个检查,看看它是否会导致依赖循环。

我记得 3DsMax 有一个命令可以准确地执行此操作。我检查了OpenMaya,但找不到任何东西。有cmds.cycleCheck,但这仅在当前有循环时才有效,这对我来说太迟了。

棘手的是,这两个对象可能位于场景层次结构中的任何位置,因此它们可能有也可能没有直接的父级关系。


编辑

检查层次结构是否会导致任何问题相对容易:

children = cmds.listRelatives(obj1, ad = True, f = True)
if obj2 in children:
    print "Can't parent to its own children!"

但检查约束或连接是另一回事。

【问题讨论】:

  • 你检查过 cmds.listConnections() 吗?
  • 是的,但如果它没有直接连接,这将失败。

标签: python maya maya-api


【解决方案1】:

根据您要查找的内容,cmds.listHistorycmds.listConnections 会告诉您给定节点的内容。 listHistory 仅限于驱动形状节点更改的可能连接的子集,因此如果您对约束感兴趣,则需要遍历节点的 listConnections 并查看上游的内容。该列表可以任意大,因为它可能包含许多隐藏节点,例如单元翻译、组部分等,您可能不想关心。

以下是控制节点传入连接并获取传入连接树的简单方法:

def input_tree(root_node):
    visited = set()  # so we don't get into loops

    # recursively extract input connections
    def upstream(node,  depth = 0):    
        if node not in visited:
            visited.add(node)
            children = cmds.listConnections(node, s=True, d=False)
            if children:
                grandparents  = ()
                for history_node in children:
                    grandparents += (tuple(d for d in  upstream(history_node, depth + 1)))
                yield node,  tuple((g for g in grandparents if len(g)))

    # unfold the recursive generation of the tree
    tree_iter = tuple((i for i  in upstream(root_node)))
    # return the grandparent array of the first node
    return tree_iter[0][-1]

应该生成一个嵌套的输入连接列表,例如

 ((u'pCube1_parentConstraint1',
   ((u'pSphere1',
     ((u'pSphere1_orientConstraint1', ()),
     (u'pSphere1_scaleConstraint1', ()))),)),
   (u'pCube1_scaleConstraint1', ()))

其中每个级别都包含一个输入列表。然后,您可以浏览它以查看您提议的更改是否包括该项目。

不会告诉您连接是否会导致真正的循环,但是:这取决于不同节点内的数据流。一旦你确定了可能的循环,你就可以回去看看循环是真实的(例如,两个项目会影响彼此的翻译)还是无害的(我影响你的轮换,你影响我的翻译)。

【讨论】:

  • 我昨天尝试使用递归函数执行相同的想法,但使用具有复杂连接的绑定它无法捕获所有内容(测试手臂的扭转关节对其肘杆矢量控制失败)。不过感谢您的回答!
  • 是的,这不是 Maya 让事情变得简单的事情。 cycleCheck 容易出现误报(例如上面的 my-translate,your-rotate 案例),这在逻辑上没有问题,但仍然会向您发送错误消息。
  • 是的,解决起来似乎不太简单。你给了一个非常可靠的答案,所以我仍然给你一个赞成票:)
【解决方案2】:

这不是最优雅的方法,但它是一种快速而肮脏的方法,到目前为止似乎工作正常。这个想法是,如果发生循环,则只需撤消操作并停止脚本的其余部分。使用钻机进行测试,无论连接多么复杂,它都会抓住它。

# Class to use to undo operations
class UndoStack():
    def __init__(self, inputName = ''):
        self.name = inputName

    def __enter__(self):
        cmds.undoInfo(openChunk = True, chunkName = self.name, length = 300)

    def __exit__(self, type, value, traceback):
        cmds.undoInfo(closeChunk = True)

# Create a sphere and a box
mySphere = cmds.polySphere()[0]
myBox = cmds.polyCube()[0]

# Parent box to the sphere
myBox = cmds.parent(myBox, mySphere)[0]

# Set constraint from sphere to box (will cause cycle)
with UndoStack("Parent box"):
    cmds.parentConstraint(myBox, mySphere)

# If there's a cycle, undo it
hasCycle = cmds.cycleCheck([mySphere, myBox])
if hasCycle:
    cmds.undo()
    cmds.warning("Can't do this operation, a dependency cycle has occurred!")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-17
    相关资源
    最近更新 更多