チュートリアル / 読んで触ってよくわかる!Mayaを使いこなす為のAtoZ
第66回:MSelecctionListについて語る
- Maya
- ゲーム
- コラム
- チュートリアル
- 中級者
- 学生・初心者
- 教育
- 映画・TV
この前CEDECに参加していてふと気づいたのですが、このコラム、タイトルがA to Zにもかかわらず、ネタが大体A~Mあたりをうろついていて、Zレーティング(?)な内容が無いのです。CEDECでお客さんが紹介しているMayaの話のほうが随分深い内容だったりしますし。
そこで、少しZ寄りの内容を増やしてみたいと考えたわけです。それって本職であるコンサルティングのネタになってしまうところでもあるので、あまり取り上げると商売上がったりですが、個別のAPIを掘り下げるようなのも面白いかと思いましたので、ちょっとその辺りの話をしてみます。
Open Mayaは一般に出回る情報も少ないですし、ドキュメントは英語ですし、少しでも理解のお手伝いができればと思います。
昔はビルドしないと試せなかったようなことも、Pythonを使ってAPIサンプルを気軽に実行できるので、こういう試みも出来る時代ですね。
どのAPIを取り上げるかが悩みどころですが、無作為に取り上げるよりもよく使う機能から順を追ったほうがわかりやすく、役に立ててもらいやすいと思いますので、初回はMSelectionListについて語ります。
APIの話と言っても難しい話ばかりだと面白くありませんので、スクリプトを知っているレベルの方からわかるようにします!…と思って書き始めたところ、あまりに話が長くなるので、既に知っている人を対象にざっくばらんに解説するように進めていきます。
MSelectionListの役割
MSelection Class Reference
http://help.autodesk.com/view/MAYAUL/2017/JPN/?guid=__cpp_ref_class_m_selection_list_html
OpenMayaAPIでツールを作っている人にはとても馴染みのあるクラスですね。選択しているもののリストを得るためのクラスです。
ドキュメントのClass Descriptionには次のように書かれています。
“This class implements a list of MObjects.”
そう、確かにそのとおりです。簡単に言えばMObjectArrayとあまり変わらず、MObjectのリストを持っているものといえます。
でもMObjectArrayはMObjectの配列以上に意味のある仕事が出来ませんが、MSelectionListはその名の通り選択に関わることが出来るようになっています。
Mayaの中で選択できるものはたくさんあります。MayaをGUIで使用していると日常的にオブジェクト、ノードといった物を選択しています。
でも実はそれ以上にも選択出来るものがあります。たとえばアトリビュートのプラグも選択出来ます。
また、選択しているものはMObjectという一つの型で扱われます。実際に選択物を利用するには、それぞれの種類に応じた適切なMFnクラスへデータを渡す必要があります。MSelectionListはその窓口にもなっています。
MSelectionListで選択する
皆さんシーンのノードの選択をリストにするのによくMGlobal::getActiveSelectionList(MSelctionList)を使われると思います。でも他にも選択方法があります。
MSelectionList::add(const MString matchString…)を使うと、名前を元に簡単にリストを得られます。
シーン内に球を2つ作り、次のPythonを実行すると、pSphere*という名前の物をリストにします。
import maya.OpenMaya as OM sList = OM.MSelectionList() sList.add('pSphere*') if not sList.isEmpty(): for i in range(sList.length()): depNode = OM.MObject() sList.getDependNode(i, depNode) print i, OM.MFnDependencyNode(depNode).name() # 0 pSphere1 # 1 pSphere2 # 2 pSphereShape1 # 3 pSphereShape2
プラグも同様に選択できます。なんか、慣れないと気持ち悪い感じがしますが。
import maya.OpenMaya as OM sList = OM.MSelectionList() sList.add('pSphere1.tx') plug = OM.MPlug() sList.getPlug(0, plug) print plug.name() # pSphere1.translateX
Dependency NodeとDAGとコンポーネントの取得
Open Mayaを始めた頃よく陥った問題として、Dependency NodeとDAGノードの扱いがあります。
「どっち使えばいいの?わけわかんないんだけどMAYAさん!!」とイライラしたものです。
MFnDependencyNodeやらなにやらをトピックスとして取り上げるときに改めて説明しようと思っているのですが、MSelectionListにも関わってくるので簡単に説明をします。
MSelectionListから実際のオブジェクトを抜き出すのに、主に次の2つの関数を使用します。
MStatus getDependNode (unsigned int index, MObject &depNode) const
Get a handle for the dependency node of the given element of the selection list. More...(Dependency Nodeへのハンドルと取得)
MStatus getDagPath (unsigned int index, MDagPath &dagPath, MObject &component=MObject::kNullObj) const
Get the dag path and component (may be NULL) of the given element of the selection list. More...(Dag Pathとコンポーネント(NULLかもしんないけど)を取得)
MFnDependencyNodeを使う予定ならgetDependNode(…)を使います。得られるMObjectをMFnDependencyNodeに渡します。
Dependency Nodeとはなんぞや…。依存ノード?つまりMayaのノードのことです。Maya内のノードなら何でもこれです。
球の名前を出力していた上のサンプルコートで使われているものです。ノード名を得る、アトリビュートを扱うなど、座標や階層に関わらないノードの処理はこちら経由で行えます。
MDagPathを使う予定ならgetDagPath(…)を使います。
DagPathとはなんぞや…。DAGノードへのパスです。
DAGノードとはなんぞや…。親子関係を作れるノードです(座標があるオブジェクト)。
そういえば、ポリゴンをいじった履歴を親にすることは出来ませんが、メッシュは親子に出来ます。その、親子に出来るものをDAGノードと呼んでいます。
OutlinerでDisplay > DAG Objects Onlyをオンにしている時に、Outlinerに出てくるものが(大体)DAGノードです。
親がいるメッシュを選択すると、正式なオブジェクト名が「group|pCube1」などになります。このパスがDagPathです。
階層をいじったり、座標の情報を扱う(たとえばオブジェクトの位置を取る)ときは、getDagPath(…)で得られる情報を利用します。
もう一つgetDependNodeとgetDagPathの重要な違いとして、getDagPathを使うときは選択しているコンポーネントも得られるというところもあります。
コンポーネントを使うということは、座標があるということですので、自ずとgetDagPathでのみ取得可能です。
たとえば球を作って頂点を選択した後、次のPythonを実行すると、選択しているコンポーネントタイプと数がスクリプトエディタに出力されます。
import maya.OpenMaya as OM sList = OM.MSelectionList() OM.MGlobal.getActiveSelectionList(sList) obj = OM.MObject() sList.getDependNode(0,obj) component = OM.MObject() dagPath = OM.MDagPath() sList.getDagPath(0,dagPath, component) print dagPath.fullPathName() print component.apiTypeStr() # kMeshVertComponent print OM.MFnSingleIndexedComponent(component).elementCount() # 13
コンポーネントはMObjectで渡されます。Mayaでは何でもMObject経由ですね。ユーザーが適切なMFnクラスに渡してから利用します。 頂点は1,2,3,4といった一つの数字のIDなのでMFnSingleIndexedComponentに渡します。
上のコードではちゃんとエラーハンドリングしていませんが、コンポーネントを選択していなかったときはcomponentがNULLなので、MFnSingleIndexedComponentに渡す前に確認してください。
まとめ
絵が少ない、華がない。でも内容にZ感が出てき、意外とよい感じがしてきました☺
こういう話は日本語だけでなく、英語で探しても出てきませんので、TAやプログラマといった筋の人向けに役に立てそうな気がしてきました。
というわけで、たとえページのヒット数や「いいね!」数が少なくてもしばらくこのネタで突き進んでみたいと思います!