Python:Spoonfed - (2-09) Cinema 4D 选择 (搬砖)
Python:Spoonfed - (2-09) Cinema 4D 选择
https://www.patreon.com/posts/python-spoonfed-31510833
2019年11月13日
这是 Python 理论的很多内容,还有更多细节。在我们开始之前,让我们暂时回到 Cinema 4D 方面,并举一些激励人心的例子。
我们已经知道预定义变量 op 正在引用选定的对象(如果恰好有一个)。我们之前的例子就适用于此。但我们也知道C4D允许多重选择,那么那些呢?
现在我们至少听说过 Python 列表,我们可以看一下 BaseDocument 的 GetActive XXX 函数。对于几种不同的 C4D 类型,它们返回单个选择或整个选择列表:
- GetActiveBaseDraw() 返回当前视口;事实上我们已经听说过这一点。
- GetActiveRenderData() 将为您提供项目选定的渲染设置
- GetActiveObject() 返回从对象管理器中选择的对象(如果正好有一个)。这是 操作 。
- GetActiveTag() 返回从对象管理器中选择的标签(如果正好有)。
- GetActiveMaterial() 返回从材质管理器中选择的材质(如果恰好有一个)。
- GetActiveObjects() 返回从对象管理器中选择的对象的列表。可能是空的。
- GetActiveTags() 返回对象管理器中选定标签的列表。可能是空的。
- GetActiveMaterials() 返回从材质管理器中选择的材质列表。可能是空的。
函数 GetActiveObjects() 需要一个参数。您可以在此处传递影响函数行为的标志:
- c4d.GETACTIVEOBJECTFLAGS_NONE 导致 GetActiveObjects() 仅返回最上面的选定对象。如果选定的对象具有也被选定的子对象,则不会返回这些子对象。 - 当您无论如何都想影响功能中任何选定对象的整个子树时,请使用此标志,因此包含已被算法触及的选定子对象是没有意义的。
- c4d.GETACTIVEOBJECTFLAGS_CHILDREN 也允许 GetActiveObjects() 选择子对象,即使它们的任何父对象已被选择。
- c4d.GETACTIVEOBJECTFLAGS_SELECTIONORDER 强制 GetActiveObjects() 按照用户实际单击对象的顺序对结果列表进行排序。
您可以通过用竖线分隔标志来组合它们。
(注:竖线实际上是 二进制 或 运算符。我们还没有涵盖二进制数和运算符,还没有完全理解二进制标志,所以暂时就天真地使用它。 -- 另外,标志 GETACTIVEOBJECTFLAGS_NONE 实际上是一个 零 值,所以它只是意味着“没有设置标志”。将其与任何其他标志组合意味着 GETACTIVEOBJECTFLAGS_NONE 将不会有任何效果,一旦我们到达二进制数。)
循环遍历结果列表 您可以使用for 。
还有两个函数可能偶尔会用到:
- GetSelection() 标签的列表 选定对象和 返回对象管理器中 。您需要在代码中再次将它们分开。
- GetActiveObjectsFilter() 的 类似 工作方式与GetActiveObjects() ,但具有按类型或实例进行过滤的额外可能性。这 不是 使用我们已经提到的 Python 类从属关系,而是使用 C4D“类型”,因此需要等待解释。
既然我们从 C4D 中获得了选定的对象,那么我们将如何继续设置自己的选择呢?对象特定函数的调用与 Get 函数对称:
- SetActiveObject(基本列表,模式)
- SetActiveTag(基本列表,模式)
- SetActiveMaterial(基本列表,模式)
这三个函数都只接受一个对象作为第一个参数,并且这些函数没有“复数版本”来设置完整的列表!因此,我们需要多次调用此函数,为每个要选择的对象调用一次。在这里,传递正确的标志作为第二个参数非常重要:
- c4d.SELECTION_NEW 将删除先前的选择并开始新的选择。
- c4d.SELECTION_ADD 将另外选择传递的对象、标签或材质。
- c4d.SELECTION_SUB 将从当前选择中删除传递的对象、标签或材质。
这些标志使更改选择成为可能,而无需查看所有先前选择的元素(例如,如果您的脚本只是将项目添加到选择中)。请注意,组合这些标志是没有意义的;它们是 相互排斥的 。
作为第二个参数来调用这些函数 使用None 作为第一个参数和 c4d.SELECTION_NEW 将 取消选择 此对象类型。 警告 :对于 SetActiveObject() , c4d.SELECTION_NEW 将 也 的选择 清除标记 (但 反之亦然 ),无论第一个参数如何。
GetSelection() 还有一个对称的 Set 函数 - SetSelection() 。在这里您可以传递对象或标签。根据文档,它也适用于材质 - 这是正确的,但遗憾的是,当我使用标志 c4d.SELECTION_NEW 设置材质时,该函数不遵守该标志,而只是另外选择材质。考虑到这两个函数的问题,我建议使用特定于对象的 getter 和 setter 来代替......
以下脚本的第一部分显示了所有这些选择:
import c4d
def main():
if doc == None: return
print
print "Selected: ----------"
bd = doc.GetActiveBaseDraw()
if bd != None: print "BaseDraw:", bd.GetName()
rd = doc.GetActiveRenderData()
if rd != None: print "RenderData:", rd.GetName()
if op != None:
print "Op: ", op.GetName()
else:
print "No single object selection"
activeObject = doc.GetActiveObject()
if activeObject!=None: print "Active object:", activeObject.GetName()
activeTag = doc.GetActiveTag()
if activeTag!=None: print "Active tag:", activeTag.GetName()
activeMaterial = doc.GetActiveMaterial()
if activeMaterial!=None: print "Active material:", activeMaterial.GetName()
activeObjectList = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
# use these flags:
# c4d.GETACTIVEOBJECTFLAGS_NONE - only uppermost selected objects without children
# c4d.GETACTIVEOBJECTFLAGS_CHILDREN - select children even if parent is already selected
# c4d.GETACTIVEOBJECTFLAGS_SELECTIONORDER - sort list by user's selection sequence
print "Active object list:"
for obj in activeObjectList:
print ("-"*3) + obj.GetName()
activeTagList = doc.GetActiveTags()
print "Active tag list:"
for tag in activeTagList:
print ("-"*3) + tag.GetName()
activeMaterialList = doc.GetActiveMaterials()
print "Active material list:"
for mat in activeMaterialList:
print ("-"*3) + mat.GetName()
everythingSelected = doc.GetSelection()
print "Objects and tags selected:"
for obj in everythingSelected:
print ("-"*3) + obj.GetName()
print everythingSelected
# also available:
# BaseDocument.GetActiveObjectsFilter(children, type, instanceof)
# BaseDocument.SetActiveObject(bl, mode=c4d.SELECTION_NEW)
# BaseDocument.SetActiveTag(bl, mode=c4d.SELECTION_NEW)
# BaseDocument.SetActiveMaterial(bl, mode=c4d.SELECTION_NEW)
# BaseDocument.SetSelection(bl, mode=c4d.SELECTION_NEW)
# use these flags for mode:
# c4d.SELECTION_NEW
# c4d.SELECTION_ADD
# c4d.SELECTION_SUB
print
print "Everything: ----------"
firstObj = doc.GetFirstObject()
if firstObj!=None: print "First object:", firstObj.GetName()
firstMat = doc.GetFirstMaterial()
if firstMat!=None: print "First material:", firstMat.GetName()
topObjs = doc.GetObjects() # top-level only
print "Top-level objects:"
for obj in topObjs:
print ("-"*3) + obj.GetName()
allMats = doc.GetMaterials()
print "All materials:"
for mat in allMats:
print ("-"*3) + mat.GetName()
print
print "Explicit search: ----------"
objName = "Cube"
matName = "Mat"
foundObj = doc.SearchObject(objName) # returns c4d.BaseObject
if foundObj != None:
print objName + " found!"
foundMat = doc.SearchMaterial(matName) # returns c4d.BaseMaterial
if foundMat != None:
print matName + " found!"
if __name__=='__main__':
main()
在第二部分(部分作为提醒)中,我们看到文档函数返回 无关的对象或材质: 与选择
- GetFirstObject() 返回对象管理器中的第一个对象, 则返回None 。 如果没有任何对象,
- GetFirstMaterial() 返回材质管理器中的第一个材质, 则返回None 。 如果没有任何材质,
- GetObjects() 所有对象的列表 顶层 返回对象管理器 。孩子们被 忽视了 。
- GetMaterials() 返回材质管理器中所有材质的列表。
请注意,这些函数始终引用整个对象树和整个材质列表,无论可见性如何,也与 当前根无关! 您在对象管理器中设置的
相应的函数 GetFirstTag() 和 GetTags() 对于文档不可用,但对于 BaseObject 确实存在。他们将 只 处理该对象的标签。请注意,另一方面,标签的选择函数是在 文档 上调用的,并且 GetActiveTags() 将返回可能属于 不同 对象的标签。
脚本的第三部分也是最后一部分显示了两个按名称查找对象和材料的函数:
- SearchObject() 获取一个名称作为参数并返回 具有该名称的第一个 对象。可能还有其他同名的对象;这些都找不到。如果您需要识别具有特定名称的所有对象并选择它们或返回它们,您可以重用我们已经讨论过的树 遍历 方法,并使用它们按名称查找对象。
- SearchMaterial() 获取名称作为参数并返回 具有该名称的第一个 材质。与 SearchObject() 相同的限制。
请注意,您需要将所需的名称作为参数传递;这些函数不会调用用户对话框作为其功能的一部分。这取决于你作为程序员。