【Maya】 ls commandで検索する
2016/5/30
こんにちは、TD室長の石田です。
タイトルの通り今回はlsコマンドを使ってMaya内を検索する方法をpythonでまとめてみようと思います。
lsコマンドはmayaのscriptを勉強した人であれば誰もが真っ先に覚えるコマンドだと思います。
今更lsコマンド!!と思うかもしれませんが実は意外となんでも出来る優れたコマンド(出来ないこともあるけど…)なんですよ。
基本的な使い方から応用した使い方まで書いていこうと思います。
あとノードネットワークの検索の仕方も少し書きます。
今回の環境はMaya2014です。
もしかすると2014以降のバージョンで挙動が変わっている可能性もあります。と言うかありました。バグが直ってました。
■とりあえずノード作成
ノードが無いと何も始まらないので読みながら試したい方は下記のsctiptを実行してください。
from maya import cmds nodeA = cmds.createNode('transform',n='nodeA') nodeB = cmds.createNode('transform',n='nodeB') node_A = cmds.createNode('transform',n='node_A') node_B = cmds.createNode('transform',n='node_B') childA = cmds.createNode('transform',n='childA',p=nodeA) childB = cmds.createNode('transform',n='childA',p=nodeB) pcube = cmds.polyCube(ch=0) cmds.rename(pcube,'node_'+pcube[0]) namespace = cmds.createNode('transform',n='namespace') if not cmds.namespace( ex='XXX' ): cmds.namespace( add='XXX' ) namespaceX = cmds.createNode('transform',n='XXX:namespace') if not cmds.namespace( ex='YYY' ): cmds.namespace( add='YYY' ) namespaceY = cmds.createNode('transform',n='YYY:XXX:namespace') childSpA = cmds.createNode('transform',n='XXX:childA',p=namespaceX) childSpB = cmds.createNode('transform',n='XXX:childA',p=namespaceY) cmds.addAttr(nodeA,ln='testA') cmds.addAttr(nodeA,ln='testB') cmds.addAttr(nodeB,ln='testA') cmds.addAttr(node_A,ln='testA') cmds.addAttr(node_A,ln='testB') cmds.addAttr(node_B,ln='testC')
■lsコマンドの基本的な使い方
○名前で検索
○typeフラグでノード名で検索
○ワイルドカード(*,?)で検索
※「*」が任意の長さの文字、「?」が任意の1文字
※ノード名がわからない場合はAttributeEditorで見れます。
#-- nodeAという名前のノードを検索 --# cmds.ls('nodeA') # Result: [u'nodeA'] # # 複数検索 # cmds.ls('nodeA','nodeB') # Result: [u'nodeA', u'nodeB'] # #-- 複数検索(リストでもOK) --# cmds.ls(['nodeA','node_p*']) # Result: [u'nodeA', u'node_pCube1', u'node_pCubeShape1'] # #-- nodeという名前を含むノードを検索 --# # ワイルドカード仕様(*) cmds.ls('node*') # Result: [u'nodeA', u'nodeB', u'node_A', u'node_B', u'node_pCube1', u'node_pCubeShape1'] #-- node+任意1文字という名前を含むノードを検索 --# # ワイルドカード仕様(?) cmds.ls('node?') # Result: [u'nodeA', u'nodeB'] # #-- node*Aという名前を含むノードを検索 --# cmds.ls('node*A') # Result: [u'nodeA', u'node_A'] # #-- ノードタイプで検索 --# # typeも複数検索可能 cmds.ls(type='transform') # Result: [u'front', u'nodeA', u'nodeB', u'node_A', u'node_B', u'node_pCube1', ...] # #-- nodeという名前を含むノードでtransformノードを検索 --# cmds.ls('node*',type='transform') # Result: [u'nodeA', u'nodeB', u'node_A', u'node_B', u'node_pCube1'] #
■アトリビュート名で検索
実はアトリビュート名も検索出来ます。
ドキュメントの例文にも書いてないので意外と知らない人が多かったりします。
ただしlsコマンドではアトリビュート名にワイルドカードが使用できません!
#-- nodeAという名前があるノードでtestAというアトリビュートがあるノードを検索 = cmds.ls('nodeA.testA') # Result: [u'nodeA.testA'] # #-- pCubeのpnts[5]アトリビュートを検索 --# cmds.ls('*pCubeShape1.pnts[5]') # Result: [u'node_pCube1.vtx[5]'] # #-- pCubeのpnts配列アトリビュートを全て検索 --# cmds.ls('*pCubeShape1.pnts[*]') # Result: [u'node_pCube1.vtx[0:7]'] # cmds.ls('*pCubeShape1.pnts[*]',flatten=1) # Result: [u'node_pCube1.vtx[0]', u'node_pCube1.vtx[1]', u'node_pCube1.vtx[2]', ...] # #-- nodeという名前を含むノードでtestAというアトリビュートがあるノードを検索 --# cmds.ls('node*.testA') # Result: [u'node_A.testA', u'nodeB.testA', u'nodeA.testA'] # #-- nodeと名前を含むノードでtestという名前のアトリビュートを含むノードを検索 --# cmds.ls('node*.test*') # Result: [] # 検索できない! もちろん"?"も使えません。
■アトリビュート名をワイルドカードで検索
lsコマンドでアトリビュートの任意検索が出来ませんでしたが、
listAttrを使用すればアトリビュート名にワイルドカードが使用できます!
ここではpythonの内包表記を使っています。
#-- node_と名前を含むノードでtestという名前のアトリビュートを含むノードを検索(内包表記) --# # ls と listAttrを組み合わせる [nd+'.'+at for nd in cmds.ls('node_*') for at in cmds.listAttr(nd,string='test*') or []] # Result: [u'node_A.testA', u'node_A.testB', u'node_B.testC'] # # 普通に書くならこんな感じ ndat = [] for nd in cmds.ls('node_*'): for at in cmds.listAttr(nd,string='test*') or []: ndat.append(nd+'.'+at) # Result: [u'node_A.testA', u'node_A.testB', u'node_B.testC'] # #-- transformノードタイプでtestという名前のアトリビュートを含むノードで検索(内包表記) --# [nd+'.'+at for nd in cmds.ls(type='transform') for at in cmds.listAttr(nd,string='test*') or []] # Result: [u'nodeA.testA', u'nodeA.testB', u'nodeB.testA', u'node_A.testA', u'node_A.testB', u'node_B.testC'] # #-- testAという名前のアトリビュート名でtransformノードタイプを検索 --# cmds.ls('*.testA',type='transform') # Result: [] # 検索できない! # node.attrではtypeフラグは使用できません。 #-- testAという名前のアトリビュート名でtransformノードタイプを検索(lsを二回使用する) --# # このように書けばtypeフラグを利用しつつアトリビュート名検索が出来ます。 cmds.ls('*.testA',cmds.ls(type='transform')) # Result: [u'node_A.testA', u'nodeB.testA', u'nodeA.testA'] # #-- ノード名、アトリビュート名、共にワイルドカードを使用して尚且つノードタイプを検索(内包表記) --# [nd+'.'+at for nd in cmds.ls('node_*',type='transform') for at in cmds.listAttr(nd,string='test*') or []] # Result: [u'node_A.testA', u'node_A.testB', u'node_B.testC'] #
■namespaceの検索
意外とややこしいのがnamespaceがついたノード名です。
XXX:namespaceを検索するときcmds.ls(‘*namespace’)では引っかかりません。
ぶっちゃけ検索に引っかかってくれてもいい気もしますがrecursiveフラグで検索出来ます。
#-- namespaceのあるノードを検索 --# cmds.ls('*namespace') # Result: [] # 検索できない! #-- namespaceの検索 :をつける --# cmds.ls('*:namespace') # Result: [u'XXX:namespace'] # # でもYYY:XXX:namespaceは引っかからない #-- namespaceの検索 :をもう一つつける --# cmds.ls('*:*:namespace') # Result: [u'YYY:XXX:namespace'] # #-- namespaceがあるノードを取りたい場合 --# cmds.ls('namespace',recursive=1) # Result: [u'namespace', u'XXX:namespace', u'YYY:XXX:namespace'] # # namespace無しのノードも引っかかってしまいます。 # namespaceあるものだけ取りたい場合は下記のように書きます。 cmds.ls('*:namespace',recursive=1) # 全て取りたい場合 cmds.ls('*:*',recursive=1) # Result: [u'YYY:XXX:namespace|XXX:childA', u'XXX:namespace|XXX:childA', u'XXX:namespace', u'YYY:XXX:namespace'] #
■同じ名前のノードを検索するときの注意点
Mayaシーン内に同じ名前が複数存在していた場合、lsコマンドで検索するとフルパス名でその数だけ返って来ます。
ただしnamespaceがあると何故かエラーを返してきます。がMaya2016では直ってました!!バグでしたね!?
#-- 同じ名前の検索 --# cmds.ls('childA') # Result: [u'nodeB|group1|childA', u'nodeA|group1|childA'] # #-- 同じ名前の検索(namespace付き) --# cmds.ls('XXX:childA') # RuntimeError: No object matches name: XXX:childA # エラー!? # Maya2016では直ってました!! #-- 同じ名前の検索(namespace付き)、recursiveをつけると返ってくる。Maya2014で使いたい場合 --# cmds.ls('*:childA',recursive=1) # Result: [u'YYY:XXX:namespace|XXX:childA', u'XXX:namespace|XXX:childA'] #
■ちょっとしたTips
# マテリアルを検索、他にもlights,texturesなどいろいろあります。 cmds.ls(materials=1) # トップノードだけを検索、意外と使う。 cmds.ls(assemblies=1) # 指定したノード以下全てを検索 cmds.ls('node_pCube1',dag=1) # 指定したノード以下全てを検索,shapesフラグとtypeフラグの合わせ技はよく使います。 cmds.ls(cmds.ls('node_pCube1',dag=1,shapes=1),type='mesh')
■特殊なnodeTypeの検索の仕方
pointConstraintを例として上げます。
ドキュメントを見ると下記の表が書かれていると思います。
pointConstraint
Node name | Parents | Classification | MFn type | Compatible function sets |
---|---|---|---|---|
pointConstraint | constraint | animation | kPointConstraint | kBase kNamedObject kDependencyNode kDagNode kTransform kConstraint kPointConstraint |
Parentsにconstraintと書かれています。
APIの話しになってきますがこれはpointConstraintNodeを作成する為にconstraintを親として使用していることになります。
たぶんMPxConstraintを使用しているはずです。
他にもノードのドキュメントを見るとParentsの記述があると思います。
実はこのParents名でノードタイプの検索が出来るんです。
デフォーマーノードもいろいろとあるかと思いますが親の種類が一緒なものがあります。
こういったものはノード専用に作ったscriptでも親が一緒であれば使い回しが出来る事があるため地味に重宝します。
ただし親の部分が一緒であればの話しですが、試しに同じ親のノードを調べてみると新しい発見があるかもしれませんよ。
cmds.createNode('pointConstraint') cmds.createNode('orientConstraint') cmds.createNode('parentConstraint') cmds.ls(type='pointConstraint') # Result: [u'pointConstraint1'] # cmds.ls(type='constraint') # Result: [u'orientConstraint1', u'parentConstraint1', u'pointConstraint1'] #
■ノードネットワーク内を検索する方法
ここではlistHistoryを使用したノードネットワークの検索の仕方を書きます。
コネクション先や元などを探す時listConnectionsコマンドを使用するかと思いますがノードネットワーク内をこれで検索するのは少々面倒くさいです。
listHistoryコマンドを使えば一気に取れるので楽にノードネットワーク内にあるノードを検索出来ます。
■ノードネットワーク準備script
# 適当にfileNodeをコネクトする関数 def cnctFile(mat): for attr in cmds.listAttr(mat,w=1,c=1): if not cmds.ls(mat+'.'+attr): continue if cmds.getAttr(mat+'.'+attr,type=1) == 'float3': fileNode = cmds.shadingNode('file',asTexture=1) cmds.connectAttr(fileNode+'.outColor',mat+'.'+attr,f=1) lambert1 = cmds.shadingNode('lambert',asShader=1) lambert2 = cmds.shadingNode('lambert',asShader=1) lambert3 = cmds.shadingNode('lambert',asShader=1) cnctFile(lambert1) cnctFile(lambert2) cnctFile(lambert3) cmds.connectAttr(lambert2+'.outColor',lambert1+'.color',f=1) cmds.connectAttr(lambert3+'.outColor',lambert2+'.color',f=1)
■lsコマンドとlistHistoryコマンドの合わせ技
#指定したノードより後ろのノードを取得する file_list = cmds.ls(cmds.listHistory(lambert1),type='file') cmds.select(file_list) # Result: [u'file19', u'file20', u'file21', u'file22', u'file23', u'file25', u'file26', u'file10', u'file12', u'file13', u'file14', u'file16', u'file17', u'file1', u'file3', u'file4', u'file5', u'file6', u'file7', u'file8', u'file9'] # #指定したノードから前のノードを取得する lambert_list = cmds.ls(cmds.listHistory(file_list[0],future=1),type='lambert') cmds.select(lambert_list) # Result: [u'lambert7', u'lambert6', u'lambert5'] #
どうでしたでしょうか。
一番知られているコマンドだけど意外と知らないこともあったかと思います。
検索方法が簡単になればコード内もすっきりするので是非いろいろ試してみてください。
本記事内で公開している全ての手法・コードの有用性、安全性について、当方は一切の保証を与えるものではありません。
これらのコードを使用したことによって引き起こる直接的、間接的な損害に対し、当方は一切責任を負うものではありません。
自己責任でご使用ください。
コメント
コメントフォーム