マニピュレータ コンテナをプログラムで作成し、コンテナに 1 つまたは複数のベース マニピュレータを追加できます。このアプローチは、次の手順で実行します。
MPxManipContainer から派生したマニピュレータ コンテナ クラスを作成します。ユーザ定義のコンテナ マニピュレータの親クラスは MPxManipContainer です。MPxManipContainer には多くのメソッドがあり、これを使用すると、さまざまなベース マニピュレータをコンテナに追加できます。カスタム マニピュレータにも、いくつかのメソッドを実装する必要があります。
必要なメソッドは以下のとおりです。
draw メソッドをオーバーライドし、コンテナ マニピュレータの描画方法をカスタマイズすることもできます。
creator メソッドは、マニピュレータの新しいインスタンスを返す必要があり、initializePlugin() メソッドへの呼び出しとともに MFnPlugin::registerNode() 関数に登録されます。
注: このメソッドはスタティックで登録されており、派生メソッドではありません。したがって、メソッド名が creator である必要はありませんが、慣習では creator という名前が一般的に使用されます。
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);
...
}
注: 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 メソッドをオーバーライドする場合は、最初に 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 では、描画と選択は一緒に行われます。次のような重要なメソッドがいくつかあります。
glFirstHandle(): OpenGL の選択可能なコンポーネントを描画するときは、OpenGL コンポーネントを一意に表す名前を設定する必要があります。このメソッドは、使用可能な最初の OpenGL ハンドルを表す符号なしの整数値を返します。1 つの OpenGL コンポーネントの描画が完了したら、整数値を 1 だけインクリメントして、次の OpenGL コンポーネントを表すことができます。colorAndName(): このメソッドは、次に描画される OpenGL コンポーネントのカラーを設定するために使用されます。また、選択がサポートされるようにコンポーネントの 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 を使用して、次の方法でプラグ値を更新できます。
マウス移動イベントに関係のあるメソッドを実装します: マウス移動イベントに関係のあるメソッドは、MPxManipulatorNode::doPress()、MPxManipulatorNode::doDrag()、MPxManipulatorNode::doRelease() の 3 つです。これらのメソッドは、マウス ダウン、マウス ドラッグ、マウス リリースなどの対応するマウス イベントをマニピュレータが受信すると呼び出されます。これらのメソッドが呼び出されたらプラグの値を更新するアルゴリズムを実装できます。 たとえば、doPress() が呼び出されたらマウス位置を元の位置として記録でき、doDrag() が呼び出されたらマウスの移動を記録できます(方向と距離)。
従属ノードに接続します: 次の手順で従属ノードに接続します。
マニピュレータ ノードの postConstructor() で add*Value() を呼び出します。
connectToDependNode() で conectPlugToValue() を呼び出します。
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);
...
}