Maya Python

スクリプトで学ぶ maya のノード体系①【 DAGノード 】

今回はノードやアトリビュートとは一体どういったものなのか、ということについて解説していきます。

ノード

ノードとはアトリビュートを持つもので、アトリビュートのひとかたまりです。

アウトライナ・ハイパーシェード・アトリビュートエディタの上でタブ化されているものなどがノードと呼ばれるものです。

ノードは ノードタイプ によっていくつかの種類に分類されます
ノードタイプはアトリビュートエディタのノード名の左に表示されています。

他にも Hypergraph Hierarchy や Hypergraph Connections といったウィンドウでノードを確認することができます。

シーン内にあるすべてのノードを取得する | ls

ノードを取得するのは ls コマンドを使用します。フラグを一切設定せずに ls コマンドを使用するとシーン内のすべてのノードを取得することができます。

# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import maya.cmds as cmds

node_list = cmds.ls() # シーン内にあるノードを全て取得
print('----------------------------\n\n\n')
print('シーン内にある全てのノードのリスト : ')
print(node_list)
print('\nノードの個数 : ' + str(len(node_list)) + ' 個')

上記のコードを実行すると、大量のノードが出力されるはずです。開いたばかりのシーンデータでも 90個近くのノードがリストで出力されると思います。

9行目のコードががわかりにくいと思うので解説しておきます。

リストの個数を取得する | len 関数

まず、len(リスト) でリストの個数を取得できます。

# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals

test_list = [1, 2, 3, 4, 5]
print( len( test_list ) )

# >>> 5 が出力される

数字を文字列型へ変換 | str 関数

型は同じ型同士でしか計算や連結ができません。数字と文字列を連結したい場合、数字を文字列へ変換します。このとき使用するのが str 関数です。

# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals

int_val = 15
print('文字列へ変換 : ' + str(int_val))

# 下記の文だとエラーが起きる
# print('文字列へ変換 : ' + int_val)

str 関数は下記の記事でも紹介しました。

ここでは文字コードの違いを統一させるために使っていますが、他の型を文字列に変換したい場合にも使用できます。

また、数字以外にもリスト型などの型も文字列へ変換できます。

# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals

list_val = [1, 2, 3, 4, 5]
print('文字列へ変換 : ' + str(list_val ))

9行目のコードの解説

先ほどのコードの 9行目は次のようになっています。

リスト型の個数を取得し、その数を str型 に変換することで他の文字列と接続させています。

ノードのタイプを取得する | nodeType

# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import maya.cmds as cmds

selectNode_list = cmds.ls(sl=True)
print('\n----------------------------\n\n\n')
for selectNode in selectNode_list:

	print('ノード名   : ' + selectNode)
	
	# ノードタイプを取得
	node_type = cmds.nodeType(selectNode)

	print('ノードタイプ : ' + node_type)
	print()

アトリビュート

アトリビュートは値を持つものです。注意したいのは、ノードが値をもっているのではなく、アトリビュートが値を持っています。

アトリビュートエディタはその名の通り、アトリビュートを編集できるウィンドウです。

他にもアトリビュートスプレットシートやコンポーネントエディタなどでアトリビュートを確認できます。

アトリビュートの一覧を取得する | listAttr

ノードが持っているアトリビュートを取得するには listAttr コマンドを使用します。次のコードでは選択したノードが持っているアトリビュートを全て出力します。

# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import maya.cmds as cmds

selectNode_list = cmds.ls(sl=True)
print('\n----------------------------\n\n\n')
for selectNode in selectNode_list:
	
	print('ノード名 : ' + selectNode)
	
	# 全てのアトリビュートをリストで取得
	attr_list = cmds.listAttr(selectNode)

	print('アトリビュート一覧 : ' + str(attr_list))
	print('アトリビュートの数 : ' + str(len(attr_list)) + ' 個')
	print()

どのノードを選んでも大量のアトリビュートが返ってくると思います。アトリビュートエディタで確認できるアトリビュートは一部でしかありません。

listAttr コマンドはフラグを使用することで条件を追加できます。
例えば下記のコードであれば ロックされているアトリビュートを取得できます。

# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import maya.cmds as cmds

selectNode_list = cmds.ls(sl=True)
print('\n----------------------------\n\n\n')
for selectNode in selectNode_list:

	print('ノード名 : ' + selectNode)
	
	# ロックされているアトリビュートをリストで取得
	attr_list = cmds.listAttr(selectNode, locked=True)

	print('ロックされているアトリビュート一覧 : ' + str(attr_list))
	print('アトリビュートの数 : ' + str(len(attr_list)) + ' 個')
	print()

ロックしているアトリビュートが1つもない場合はエラーで止まりますので、適当にアトリビュートにロックをかけてから実行してください。

アトリビュートに値を設定する | setAttr

上記の記事で設定方法を解説しています。
設定しようとしているアトリビュートが見つからない場合はエラーで処理が止まるので注意してください。

アトリビュートが持っている値を取得する | getAttr

# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import maya.cmds as cmds

# アトリビュート名
attribute_name = 'translateX'

selectNode_list = cmds.ls(sl=True)

print('\n----------------------------\n\n\n')
for selectNode in selectNode_list:

	print('ノード名 : ' + selectNode)
	
	# アトリビュートが持っている値を調べる
	status = cmds.getAttr(selectNode + '.' + attribute_name)

	print('値を調べたアトリビュート名 : ' + attribute_name)
	print('取得した値 : ' + str(status))
	print()

アトリビュートが存在するかを確認する | attributeQuery

# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import maya.cmds as cmds

# 検索するアトリビュート名
attribute_name = 'translateX'

selectNode_list = cmds.ls(sl=True)

print('\n----------------------------\n\n\n')
for selectNode in selectNode_list:

	print('ノード名 : ' + selectNode)
	
	# アトリビュートを検索
	status = cmds.attributeQuery(attribute_name , node=selectNode , exists=True)

	print('検索したアトリビュート : ' + attribute_name)
	print('存在するかどうか : ' + str(status))
	print()

DAGノード

親子関係を構築できるノードを DAG ノード と呼びます。

具体的にはトランスフォームノード、シェイプノード、デフォーマー、ボーン、コンストレインなど、初期設定のアウトライナで表示されるノード + シェイプノードのことです。
逆にファイルノードやマテリアルなどは親子関係がつけられないため、 DAG ノードではありません。

コマンドリファレンスで DAG ノードと一括りで記載されている箇所が多々あるので、この単語と意味を把握しておく必要があります。

トランスフォームノードとシェイプノード

アウトライナは初期設定でシェイプノードを非表示になっています。
Display > Shapes の項目でシェイプノードの表示を切り替えられます。

「シェイプノード」というノードは実際にはありません。シェイプノードは カテゴリの名称 です。

「 mesh 」、「 spotLight 」、「 camera 」など、そのオブジェクトの性質を扱うノードを総称してシェイプノードと呼びます。
これに対し、トランスフォームノードは位置・回転・スケール・表示状況などに関係するアトリビュートを持ちます。

そして、トランスフォームノードとシェイプノードは 親子関係を持ちます。
シェイプノードは単体で存在することはなく、必ずトランスフォームノードを親に持ちます。

シーン内にある全てのトランスフォームノードを取得する

# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import maya.cmds as cmds

# シーン内にあるトランスフォームノードを全て取得
transformNode_list = cmds.ls(transforms=True)
print('----------------------------\n\n\n')
print('シーン内にある全てのトランスフォームノードのリスト : ')
print(transformNode_list)
print('\nノードの個数 : ' + str(len(transformNode_list)) + ' 個')

ls コマンドの transforms フラグでシーン内のトランスフォームノードを取得できます。

シーン内にある全てのシェイプノードを取得する

# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import maya.cmds as cmds

# シーン内にあるシェイプノードを全て取得
shapeNode_list = cmds.ls(shapes=True)
print('----------------------------\n\n\n')
print('シーン内にある全てのシェイプノードのリスト : ')
print(shapeNode_list)
print('\nノードの個数 : ' + str(len(shapeNode_list)) + ' 個')

ls コマンドの shapes フラグでシーン内のシェイプノードを取得できます。

選択したトランスフォームノードから
シェイプノードを取得する

# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import maya.cmds as cmds

# 検索するアトリビュート名
attribute_name = 'translateX'

selectNode_list = cmds.ls(sl=True)

print('\n----------------------------\n\n\n')
for selectNode in selectNode_list:

	print('ノード名 : ' + selectNode)
	
	# シェイプノードのリストを取得
	shapeNode_list = cmds.listRelatives(selectNode , shapes=True)

	print('シェイプノードのリスト : ' + str(shapeNode_list))
	print()

トランスフォームノードを選択した状態でコードを実行してください。

listRelatives コマンドの shapes フラグを利用する事でシェイプノードを取得できます。listRelatives コマンドは階層化されているノードの親や子ノードを取得するためのコマンドです。利用頻度がかなり高いコマンドです。

注目したいのは、シェイプノードがリストで取得されている ことです。

シェイプノードは複数存在する場合がある

シェイプノード → トランスフォームノードの順に選択し、下記のコードを実行してみてください。
※今回あえてやってますが、ライトとメッシュを同じトランスフォームの子にするとバグるので新規のシーンでやってください。

# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import maya.cmds as cmds

cmds.parent(relative=True, shape=True)

このように、一つのトランスフォームノードに対して複数のシェイプノードをペアレントすることができます。

普通に作業をする分にはこのような状況にはなることはありません。

通常は1つのトランスフォームノードに対して1つしかシェイプノードを持てません。
コンバインをしたとしてもシェイプノードはひとつにまとめられますし、メッシュとライトが同じトランスフォームノードの下に来ることはあり得ません。

ですがコンバインやセパレートを繰り返すと、極まれに メッシュのシェイプノードを複数持つトランスフォームノードが出来上がってる ことがあります。

POINT
  • シェイプノードはリスト型で取得される

これを忘れると思わぬところでエラーが発生します。
基本的にシェイプノードはひとつですが、複数存在する場合がまれにあるので注意してください。

また、便利だからといってこの方法でメッシュをまとめることはおすすめしません。多くのツールでエラーが発生します。

選択したシェイプノードから
トランスフォームノードを取得する

# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import maya.cmds as cmds

# 検索するアトリビュート名
attribute_name = 'translateX'

selectNode_list = cmds.ls(sl=True)

print('\n----------------------------\n\n\n')
for selectNode in selectNode_list:

	print('ノード名 : ' + selectNode)
	
	# 親ノードをリスト型で取得
	parentNode_list = cmds.listRelatives(selectNode , parent=True)

	print('親ノードのリスト : ' + str(parentNode_list))
	print()

シェイプノードの直上にあるノードがトランスフォームノードです。そのため、直上にあるノードを取得することでトランスフォームノードが取得できます。

取得するには listRelatives コマンドの parent フラグを使用します。

このコードは直上の親ノードを取得しているため、シェイプが複数あっても関係ありません。

選択したトランスフォームノードから
シェイプノードのアトリビュートのリストを取得する

# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import maya.cmds as cmds

# 検索するアトリビュート名
attribute_name = 'translateX'

selectNode_list = cmds.ls(sl=True)

print('\n----------------------------\n\n\n')
for selectNode in selectNode_list:

	print('ノード名 : ' + selectNode)
	
	# シェイプノードのリストを取得
	shapeNode_list = cmds.listRelatives(selectNode , shapes=True)
	
	print('シェイプノード名 : ' + str(shapeNode_list[0]))
	
	# アトリビュートをリストで取得
	attribute_list = cmds.listAttr(shapeNode_list[0])
	
	print('シェイプノードのアトリビュート一覧 : ' + str(attribute_list))
	print('シェイプノードのアトリビュートの個数 : ' + str(len(attribute_list)) + ' 個')
	

18行目と21行目のシェイプノードのリストに「 [0] 」を付けています。シェイプノードはリスト型で取得されるため、一番最初にあるシェイプノードのアトリビュートを取得しています。

全てのシェイプノードのアトリビュートを取得するには for 文でループさせる必要があります。

まとめ

ノード・アトリビュート・DAGノード・シェイプノードの特徴について話しました。

POINT
  • nodeType コマンドでノードのタイプを取得できる
  • 親子関係を構築できるノードを DAG ノードと呼ぶ
  • listRelatices コマンドで親子関連のノードを取得可能
  • シェイプノードは複数存在する場合がある

これと併せて、

POINT
  • リストの数を取得する len 関数
  • 値を文字列に変換する str 関数

これらの関数は使用頻度が高いので覚えておきましょう。

-Maya Python
-