マニピュレータ コンテナをプログラムで作成し、コンテナに 1 つまたは複数のベース マニピュレータを追加できます。このアプローチは、次の手順で実行します。
ユーザ定義のコンテナ マニピュレータの親クラスは MPxManipContainer です。MPxManipContainer には多くのメソッドがあり、これを使用すると、さまざまなベース マニピュレータをコンテナに追加できます。カスタム マニピュレータにも、いくつかのメソッドを実装する必要があります。
draw メソッドをオーバーライドし、コンテナ マニピュレータの描画方法をカスタマイズすることもできます。
creator メソッドは、マニピュレータの新しいインスタンスを返す必要があり、MFnPlugin::registerNode() メソッドへのコールとともに initializePlugin() 関数に登録されます。
initialize メソッドは、マニピュレータに必要な初期化と親クラス MPxManipContainer::initialize() のコールを実行します。creator メソッドと同じように、initialize メソッドは派生メソッドではなく、スタティックかつ登録されたメソッドです。
ベース マニピュレータは、MPxManipContainer::createChildren() メソッドを使用してマニピュレータ コンテナ クラスに追加されます。
たとえば moveManip::createChildren() メソッドは以下のようになります。
MStatus moveManip::createChildren() { ... fDistanceManip = addDistanceManip(manipName, distanceName); fFreePointManip = addFreePointTriadManip(pointManipName, pointName); ... }
このメソッドは、通常はカスタム マニピュレータ コンテナ クラスをセットアップした後に呼び出されます。MPxManipContainer クラスは、個別のベース マニピュレータを追加するための一連のメンバ関数を提供します。そのほとんどの名前は addXYZManip です。 XYZ は、マニピュレータの名前を表します。この関数は、作成されたベース マニピュレータを表す MDagPath オブジェクトを返します。カスタム マニピュレータ コンテナに距離マニピュレータを追加する footPrintManip プラグインの例を次に示します。
MStatus footPrintLocatorManip::createChildren() { MStatus stat =MStatus::kSuccess; MString manipName("distanceManip"); MString distanceName("distance"); MPoint startPoint (0.0, 0.0, 0.0); MVector direction (0.0, 1.0, 0.0); fDistanceManip =addDistanceManip(manipName,distanceName); MFnDistanceManip distanceManipFn(fDistanceManip); distanceManipFn.setStartPoint(startPoint); distanceManipFn.setDirection(direction); return(stat); }
connectToDependNode() メソッドは、やり取りを行うマニピュレータとプラグ間に関連付けが作成される場所です。マニピュレータとプラグの間の通信を設定するすべての操作(1 対 1 の関連付けや変換関数を含む)は、このメソッドに入れる必要があります。マニピュレータとプラグの間のマッピング関係を設定した後、2 つのメソッドを呼び出します。そのメソッドは MPxManipContainer::finishAddingManips() と MPxManipContainer::connectToDependNode() で、この順序で呼び出す必要があります。MPxManipContainer::finishAddingManips() は、プラグとのコネクションを確立した後で呼び出す必要があることに注意してください。さらに、finishAddingManips() は 1 回しか呼び出す必要がありません。
たとえば moveManip::connectToDependNode() メソッドでは以下のようになります。
MStatus moveManip::connectToDependNode(const MObject &node) { ... distanceManipFn.connectToDistancePlug(syPlug); ... freePointTriadManipFn.connectToPointPlug(tPlug); ... finishAddingManips(); ... MPxManipContainer::connectToDependNode(node); ... }
footPrintManip プラグインの例では、次の操作を示します。距離マニピュレータを作成し、MFnDistanceManip 関数セット クラスを作成した距離マニピュレータに適用し、プラグと距離マニピュレータ値の間に 1 対 1 の関連付けを設定し、plugToManip 変換を設定してマニピュレータの開始ポイント位置を設定します。
MStatus footPrintLocatorManip::connectToDependNode (const MObject &node) { MStatus stat; // Get the DAG path MFnDagNode dagNodeFn(node); dagNodeFn.getPath(fNodePath); // Connect the plugs MFnDistanceManip distanceManipFn(fDistanceManip); MFnDependencyNode nodeFn(node); MPlug sizePlug =nodeFn.findPlug("size", &stat); if ( stat != MStatus::kFailure ) { distanceManipFn.connectToDistancePlug (sizePlug); unsigned startPointIndex =distanceManipFn.startPointIndex(); addPlugToManipConversionCallback (startPointIndex, (plugToManipConversionCallback)&footPrintLocatorManip::startPointCallback); finishAddingManips(); MPxManipContainer::connectToDependNode(node); } return(stat); }
draw メソッドは、コンテナ マニピュレータの作成をカスタマイズするために使用する、オプションのメソッドです。draw メソッドを上書きする場合は、最初に MPxManipContainer::draw() をコールしてすべての子を描画する必要があります。
たとえば moveManip::draw() メソッドでは、ベース マニピュレータに加えてラベルが描画されます。
void moveManip::draw(M3dView &view, const MDagPath &path, M3dView::DisplayStyle style, M3dView::DispalyStatus status) { MPxManipContainer::draw(view, path, style, status); view.beginGL(); MPoint textPos(0, 0, 0); char str[100]; sprintf(str, "Stretch Me!"); MString distanceText(str); view.drawText(distanceText, textPos, M3dView::kLeft); view.endGL(); }
MPxManipContainer::draw() メソッドは補足図面をマニピュレータに追加するための M3dView パラメータを提供するだけなので、カスタム マニピュレータのシェイプと図面はベース マニピュレータに制限されます。カスタム マニピュレータのシェイプは、現在のマニピュレータ コンテナに追加されたベース マニピュレータ シェイプの組み合わせによってすでに記述されています。ただし、マニピュレータの異なるパースペクティブをより詳細にコントロールする必要がある場合があります。Maya 2009 で導入された MPxManipulatorNode クラスは、カスタム OpenGL 描画コードでカスタム マニピュレータを実装する新しい方法を提供します。カスタム マニピュレータのコンポーネントを選択する(別のハンドルをアクティブにする)ためのオプションが提供されます。このクラスは、単独で、または MPxManipContainer クラスと共に動作できます。
MPxManipulatorNode::draw() メソッドは、カスタム描画を実装するためにオーバーライドされます。OpenGL では、描画と選択は一緒に行われます。次のような重要なメソッドがいくつかあります。
void triadScaleManip::draw (M3dView &view, const MDagPath &path, M3dView::DisplayStyle style, M3dView::DisplayStatus status) { …… // Begin the drawing view.beginGL(); // Place before you draw the manipulator component that can // be pickable. MGLuint glPickableItem; glFirstHandle(glPickableItem); // Top topName =glPickableItem; colorAndName(view, glPickableItem, true, mainColor()); gGLFT->glBegin(GL_LINES); gGLFT->glVertex3fv(tl); gGLFT->glVertex3fv(tr); gGLFT->glEnd(); // Right glPickableItem++; rightName =glPickableItem; colorAndName(view, glPickableItem, true, mainColor()); gGLFT->glBegin(GL_LINES); gGLFT->glVertex3fv(tr); gGLFT->glVertex3fv(br); gGLFT->glEnd(); // ... // End the drawing view.endGL(); }
MPxManipulatorNode を使用して、次の方法でプラグ値を更新できます。
マニピュレータ値にプラグを直接接続するには、最初にマニピュレータでマニピュレータ値を作成する必要があります。異なる型のマニピュレータ値を追加するため、複数の add*Value() メソッドがあります。1 対 1 の関連付けは、MPxManipulatorNode::connectToDependNode() 内で connectPlugToValue() メソッドを呼び出すことにより実現できます。マニピュレータが対応するマウス イベントを受け取るとトリガされる do*() 関数の 1 つで、set*Value() を呼び出して対応するマニピュレータ値を設定し、結果としてプラグ値を設定します。
マニピュレータ コンテナはノードから派生しているので、ユーザ定義マニピュレータの登録と登録解除はほかのノードと同じようにできますが、MFnPlugin::registerNode() の MPxNode::Type 引数の設定先が、既定の MPxNode::kDependNode ではなく MPxNode::kManipContainer である点だけが異なります。
たとえば moveToolManip.cpp では以下のようになっています。
MStatus initializePlugin(MObject obj) { ... plugin.registerNode("moveManip", moveManip::id, &moveManip::creator, &moveManip::initialize, MPxNode::kManipContainer); ... } MStatus uninitializePlugin(MObject obj) { ... plugin.deregisterNode(moveManip::id); ... }