マニピュレータ コンテナ

マニピュレータ コンテナをプログラムで作成し、コンテナに 1 つまたは複数のベース マニピュレータを追加できます。このアプローチは、次の手順で実行します。

  1. MPxManipContainer から派生したマニピュレータ コンテナ クラスを作成します。
  2. マニピュレータ コンテナ クラスにベース マニピュレータを追加します。
  3. マニピュレータとノードのアトリビュート間の関連付けを定義します。

ユーザ定義のコンテナ マニピュレータの親クラスは MPxManipContainer です。MPxManipContainer には多くのメソッドがあり、これを使用すると、さまざまなベース マニピュレータをコンテナに追加できます。カスタム マニピュレータにも、いくつかのメソッドを実装する必要があります。

必要なメソッドは以下のとおりです。

draw メソッドをオーバーライドし、コンテナ マニピュレータの描画方法をカスタマイズすることもできます。

creator メソッド

creator メソッドは、マニピュレータの新しいインスタンスを返す必要があり、MFnPlugin::registerNode() メソッドへのコールとともに initializePlugin() 関数に登録されます。

注: このメソッドはスタティックで登録されており、派生メソッドではありません。したがって、メソッド名が creator である必要はありませんが、慣習では creator という名前が一般的に使用されます。

initialize メソッド

initialize メソッドは、マニピュレータに必要な初期化と親クラス MPxManipContainer::initialize() のコールを実行します。creator メソッドと同じように、initialize メソッドは派生メソッドではなく、スタティックかつ登録されたメソッドです。

createChildren メソッド

ベース マニピュレータは、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 メソッド

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);
    ...
}
注: connectToDependNode() は仮想のメソッドですが、カスタム コンテキスト内でマニピュレータを使用している場合は、通常は自分でこのメソッドを呼び出す責任があります。詳細については、「マニピュレータをマニピュレータの表示ツール(Show Manipulator Tool)に接続する」を参照してください。

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 メソッドは、コンテナ マニピュレータの作成をカスタマイズするために使用する、オプションのメソッドです。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 を使用して、次の方法でプラグ値を更新できます。

登録/登録解除

マニピュレータ コンテナはノードから派生しているので、ユーザ定義マニピュレータの登録と登録解除はほかのノードと同じようにできますが、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);
    ...
}