透過 Maya Python API 2.0 取得 "nodes"

常見的 OpenMaya API 2.0 nodes 的取得方法.

MSelectionList

常見作法是把物件的字串名稱加入 MSelectionList, 再轉換成想要的 node type.

取得選取範圍的 MSelectionList

1
2
3
import maya.api.OpenMaya as om2

sel_list = om2.MGlobal.getActiveSelectionList()

將多個物件名稱加入 MSelectionList

1
2
3
4
5
6
import maya.api.OpenMaya as om2
node_names = ["persp", "side"]
sel_list = om2.MSelectionList()

for name in node_names:
    sel_list.add(name)

單一名稱

getSelectionListByName 基本上和 om2.MSelectionList.add 一樣, 差別在於前者效能略佳, 而且在取得單一物件的時候寫法看起來更簡潔易懂.

1
2
3
4
import maya.api.OpenMaya as om2

name = "persp"
sel_list = om2.MGlobal.getSelectionListByName(name)

MObject

MObject 是 Maya 內部最基礎的物件. 可以用來 instantiate 其他類型的 API nodes, 判定物件的 exact type (MFn::Type, apiType) 或是和特定的 function set 相容與否.

1
2
3
4
5
6
7
8
9
import maya.api.OpenMaya as om2

node_names = ["persp", "side"]
sel_list = om2.MSelectionList()

for name in node_names:
    sel_list.add(name)

mobjects = [sel_list.getDependNode(cnt) for cnt in range(sel_list.length())]

MFnDependencyNode

MFnDependencyNode 是 dependency graph nodes 的 function set. 包括取得 name string, namespace, 它的屬性和連結等等.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import maya.api.OpenMaya as om2

node_names = ["persp", "side"]
sel_list = om2.MSelectionList()

for name in node_names:
    sel_list.add(name)

dep_fns = [
    om2.MFnDependencyNode(
        sel_list.getDependNode(cnt)
        )
        for cnt in range(sel_list.length())
]

字串名稱

透過 getSelectionStrings 取得 MSelectionList 內含物件的字串名稱, 如果有名稱重複的會回傳 partial path names.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import maya.api.OpenMaya as om2
import maya.cmds as cmds

grps = [cmds.group("side")]
grps.append(cmds.duplicate(grps[0])[0])

full_path_names = cmds.listRelatives(grps, allDescendents=True, fullPath=True)
cmds.select(full_path_names)

sel_list = om2.MGlobal.getActiveSelectionList()
print(sel_list.getSelectionStrings())
# ('group1|side|sideShape', 'group1|side', 'group2|side|sideShape', 'group2|side')

MobjectHandle

MobjectHandle 把 Mobject 包裝起來, 透過 isValidisAlive 判斷Mobject 代表的結果在 Maya 場景裡的狀態.

  • isValid: 物件已失效, 被刪除而且無法靠 undo 恢復.
  • isAlive: 物件已經不存在場景, 但是在 undo queue 之中.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import maya.api.OpenMaya as om2

grp = cmds.group(empty=True)
sel_list = om2.MGlobal.getSelectionListByName(grp)
handle = om2.MObjectHandle(sel_list.getDependNode(0))

print("After creation")
print("{0} isValid: {1}".format(grp, handle.isValid()))
# null1 isValid: True
print("{0} isAlive: {1}".format(grp, handle.isAlive()))
# null1 isAlive: True

cmds.delete(grp)
print("\nAfter deletion")
print("{0} isValid: {1}".format(grp, handle.isValid()))
# null1 isValid: False
print("{0} isAlive: {1}".format(grp, handle.isAlive()))
# null1 isAlive: True

cmds.undo()
print("\nAfter undoing the delteion.")
print("{0} isValid: {1}".format(grp, handle.isValid()))
# null1 isValid: True
print("{0} isAlive: {1}".format(grp, handle.isAlive()))
# null1 isAlive: True

cmds.delete(grp)
cmds.flushUndo()
print("\nAfter deletion and flushing the undo queue.")
print("{0} isValid: {1}".format(grp, handle.isValid()))
# null1 isValid: False
print("{0} isAlive: {1}".format(grp, handle.isAlive()))
# null1 isAlive: False

MDagPath

原則上 DAG node 是在 Outliner 裡面有階層關係的那些 transform 和 shape 節點. MDagPath 則是用來取得這些階層關係資訊和操作從屬關係.

1
2
3
4
5
6
import maya.api.OpenMaya as om2

grp = cmds.group(empty=True)
sel_list = om2.MGlobal.getSelectionListByName(grp)

dag_path = sel_list.getDagPath(0)

如果你有現成的 MObject, 也可直接用 MDagPath.getAPathTo 產生.

1
2
3
4
5
6
7
import maya.api.OpenMaya as om2

grp = cmds.group(empty=True)
sel_list = om2.MGlobal.getSelectionListByName(grp)
mobj = sel_list.getDependNode(0)

dag_path = om2.MDagPath.getAPathTo(mobj)

Maya 有一些和 transformation/matrix 相關的 class/function 必須要使用 MDagPath 來作為 constructor. e.g.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import maya.api.OpenMaya as om2

grp = cmds.group(empty=True)
sel_list = om2.MGlobal.getSelectionListByName(grp)

dag_path = sel_list.getDagPath(0)
mobj = sel_list.getDependNode(0)

fn_mobj = om2.MFnTransform(mobj)
fn_dag_path = om2.MFnTransform(dag_path)

vector = om2.MVector(0,0,0)
space = om2.MSpace.kWorld

fn_dag_path.setTranslation(vector, space)
print("Success")
# Success

fn_mobj.setTranslation(vector, space)
# RuntimeError: (kInvalidParameter): Object is incompatible with this method