https://www.patreon.com/posts/python-spoonfed-31572219
2019年11月15日
利用上一课的选择函数,我们现在可以拼凑出一些脚本(有一些事情我们还没有解释,但应该很容易理解)。以下代码将允许您选择当前所选对象的父对象、顶级对象、同级对象、表兄弟对象或子对象。这些功能的一部分过去已包含在 Cineversity 中,但在这里您可以获取它们,包括源代码。
我们先从Parent的选择开始。PS_SelectObject_Parent.py
import c4d
def SetActiveObjects(objlist):
cleared = False
for obj in objlist:
if not cleared:
doc.SetActiveObject(obj, c4d.SELECTION_NEW)
cleared = True
else:
doc.SetActiveObject(obj, c4d.SELECTION_ADD)
def main():
if doc == None: return
activeObjectList = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
if not activeObjectList: return
newSelection = []
for obj in activeObjectList:
if obj.GetUp() != None:
newSelection += [obj.GetUp()]
else:
newSelection += [obj]
SetActiveObjects(newSelection)
c4d.EventAdd()
if __name__=='__main__':
main()
在这里,我们将函数 SetActiveObjects() 添加到 API 中的选择设置函数数量中。由于给定的函数 只能选择一个BaseObject 一次 ,因此我们在这里封装SetActiveObject() 并允许传递整个列表。
唯一的技巧是,我们必须使用标志 SELECTION_NEW 设置第一个对象以清除 以前的 设置其他每个对象 选择,但必须使用SELECTION_ADD 。为此,我们使用一个布尔变量 清除 开始 ,它从False 设置为 True ,并在第一次有机会时 保持True )。 (此后一直
在函数 main() 循环中迭代当前选择 中,我们在for ,获取每个对象的直接父对象并将其添加到新选择中。如果没有父对象,则将添加对象本身(本质上保持选中状态)。
newSelection 是一个列表对象。 文字初始化为空列表 它由[ ] 。要添加对象,我们首先通过再次将对象括在方括号中来创建一个列表,其中包含该对象中的一项。 将此迷你列表附加到现有列表 可以使用扩展赋值+= 。
第二个脚本基本相同,但它不是寻找直接父代,而是寻找最顶层的祖先。这是在 while 循环中完成的: PS_SelectObject_Top.py
import c4d
def SetActiveObjects(objlist):
cleared = False
for obj in objlist:
if not cleared:
doc.SetActiveObject(obj, c4d.SELECTION_NEW)
cleared = True
else:
doc.SetActiveObject(obj, c4d.SELECTION_ADD)
def main():
if doc == None: return
activeObjectList = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
if not activeObjectList: return
newSelection = []
for obj in activeObjectList:
while obj.GetUp() != None:
obj = obj.GetUp()
newSelection += [obj]
SetActiveObjects(newSelection)
c4d.EventAdd()
if __name__=='__main__':
main()
我们不需要额外的情况来包含 obj 请注意,如果没有祖先, 循环 本身。在这种情况下,while 结束 本身在obj 处 。
如果我们在最初的选择中有两个兄弟姐妹会怎样?难道我们不会为两者获得相同的父级或祖先,并且有一个包含重复元素的列表可供选择吗? -- 确实如此,但没关系:将对象设置为活动 两次 不会产生不良影响,因此我们不需要经历整理重复项的麻烦。PS_SelectObject_Siblings.py
import c4d
def SetActiveObjects(objlist):
cleared = False
for obj in objlist:
if not cleared:
doc.SetActiveObject(obj, c4d.SELECTION_NEW)
cleared = True
else:
doc.SetActiveObject(obj, c4d.SELECTION_ADD)
def SelectSiblings(startobj):
global newSelection
if startobj == None: return
newSelection += [startobj]
obj = startobj
while obj.GetPred() != None:
newSelection += [obj.GetPred()]
obj = obj.GetPred()
obj = startobj
while obj.GetNext() != None:
newSelection += [obj.GetNext()]
obj = obj.GetNext()
def main():
global newSelection
if doc == None: return
activeObjectList = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
if not activeObjectList: return
newSelection = []
for obj in activeObjectList:
SelectSiblings(obj)
SetActiveObjects(newSelection)
c4d.EventAdd()
if __name__=='__main__':
main()
在第三个脚本(选择最初选定对象的所有同级)中,我们引入了一个新函数 SelectSiblings() 。这将获取一个 BaseObject ,并将该对象本身及其所有同级添加到共享全局列表 newSelection 中 。 它通过从参数对象走到列表的前面,然后再次从参数对象走到列表的后面来实现这一点。
我们只调用 SelectSiblings 一次,因此我们可能直接保留该代码而不是函数调用(这种做法也称为 内联代码 )。 函数 但是,分离出SetActiveObjects 和 SelectSiblings 使代码更清晰、更易于阅读 - 而且,我们可以为最后两个脚本重用相同的结构。PS_SelectObject_Cousins.py
import c4d
def SetActiveObjects(objlist):
cleared = False
for obj in objlist:
if not cleared:
doc.SetActiveObject(obj, c4d.SELECTION_NEW)
cleared = True
else:
doc.SetActiveObject(obj, c4d.SELECTION_ADD)
def SelectSiblings(startobj):
global newSelection
if startobj == None: return
newSelection += [startobj]
obj = startobj
while obj.GetPred() != None:
newSelection += [obj.GetPred()]
obj = obj.GetPred()
obj = startobj
while obj.GetNext() != None:
newSelection += [obj.GetNext()]
obj = obj.GetNext()
def main():
global newSelection
if doc == None: return
activeObjectList = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
if not activeObjectList: return
newSelection = []
for obj in activeObjectList:
if obj.GetUp() == None:
SelectSiblings(obj)
else:
parent = obj.GetUp()
while parent.GetPred() != None:
parent = parent.GetPred()
while parent != None:
SelectSiblings(parent.GetDown())
parent = parent.GetNext()
SetActiveObjects(newSelection)
c4d.EventAdd()
if __name__=='__main__':
main()
第四个脚本不仅选择兄弟姐妹,还选择最初选择的对象的“表兄弟”。在这种情况下,“表兄弟”是父母的兄弟姐妹的子对象。为了找到这些,代码首先上一层,然后从头到尾遍历这一层,将所有节点的所有子节点添加到选择中。如果没有父母,代码只会添加兄弟姐妹。
第五个也是最后一个选择器脚本选择最初选定对象的子对象:PS_SelectObject_Children
import c4d
def SetActiveObjects(objlist):
cleared = False
for obj in objlist:
if not cleared:
doc.SetActiveObject(obj, c4d.SELECTION_NEW)
cleared = True
else:
doc.SetActiveObject(obj, c4d.SELECTION_ADD)
def main():
if doc == None: return
activeObjectList = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
if not activeObjectList: return
newSelection = []
for obj in activeObjectList:
if obj.GetUp() != None:
newSelection += [obj.GetUp()]
else:
newSelection += [obj]
SetActiveObjects(newSelection)
c4d.EventAdd()
if __name__=='__main__':
main()
这与 Cinema 4D 的内置功能“选择子项”不同,因为该功能会选择所有依赖子树直至最低级别。相反,脚本仅限于 直接 子对象(如果没有子对象,甚至是原始对象)。
我没有包含像 C4D 的“选择子项”(无论如何应该命名为“选择子树”)这样的功能,因为该功能已经可用。
一点作业:如果所需的目标对象(父对象、顶级对象、兄弟姐妹、子对象、表兄弟)不可用,则所有五个脚本都会保留最初选择的对象。您可能想要更改该行为,以便不再选择最初选择的对象。在什么情况下这才有意义?这容易实现吗?