マニピュレータ コンテナ

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

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

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

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

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

creator メソッド

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

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

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 を使用して、次の方法でプラグ値を更新できます。

  1. マニピュレータ ノードの postConstructor()add*Value() を呼び出します。
  2. connectToDependNode()conectPlugToValue() を呼び出します。
  3. do*() 関数のいずれかで set*Value() を呼び出します。

マニピュレータ値にプラグを直接接続するには、最初にマニピュレータでマニピュレータ値を作成する必要があります。異なる型のマニピュレータ値を追加するため、複数の 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);
    ...
}