マニピュレータはノード上のプラグとやり取りを行い、その値を設定して、マニピュレータの値もプラグの値に対して適切に設定します。
マニピュレータとノードのやり取りは、単純な 1 対 1 の関係、またはより複雑な変換関数を使用して行われます。以下は、ノードとマニピュレータのやり取りを説明する図です。
図中のコンバータは、ノード上のプラグとマニピュレータ値のやり取りを管理するメカニズムです。矢印は情報の流れる方向を表します。それぞれのコンテナ マニピュレータには 1 つのコンバータがあり、コンテナの子マニピュレータとその影響を受けるプラグの間のインタフェースになります。
コンバータとベース マニピュレータには、スクエアのボックスで表されている多くのデータ項目があります。子マニピュレータ値に関連する、コンバータの項目は、converterManipValue 項目と呼ばれ、ノード プラグ値に関連するコンバータの項目は converterPlugValue 項目と呼ばれます。
ベース マニピュレータの項目は manipValue 項目と呼ばれます。一部の manipValue 項目は、マニピュレータの可動性に直接関係します。たとえば MFnDiscManip::angleIndex は、DiscManip の回転可動性に直接関係します。
その他の manipValue 項目はマニピュレータの可動性に関係しませんが、MFnDiscManip::centerIndex、MFnDiscManip::axisIndex など、マニピュレータの位置や向きに関する重要な情報を提供します。
それぞれの converterManipValue 項目と converterPlugValue 項目には整数インデックスがあり、その項目が一意に識別されるようになっています。ベース マニピュレータのそれぞれの manipValue 項目にも整数インデックスがあり、その項目が一意に識別されるようになっています。
図から分かるように、converterManipValue 項目と converterPlugValue 項目の 1 対 1 の関係は直接的です。
converterManipValue 項目と converterPlugValue 項目の複雑な変換は、変換関数を通して実行されます。この関数では、任意の数の converterPlugValue 項目か converterManipValue 項目を使用し、対応する converterManipValue 項目か converterPlugValue 項目の値を計算します。
converterManipValue 項目と converterPlugValue 項目の間の 1 対 1 の関係は、MFnManip3D から派生したマニピュレータ クラスのメソッドを使用して確立されます。コネクトするプラグに対応するメソッドとデータ型は以下のとおりです。
このメソッドは、上で説明した connectToDependNode メソッドからコールする必要があります。たとえば footPrintManip では以下のようになっています。
MStatus footPrintLocatorManip::connectToDependNode (const MObject &node) { ... MFnDistanceManip distanceManipFn(fDistanceManip); MFnDependencyNode nodeFn(node); MPlug sizePlug = nodeFn.findPlug("size", &stat); if (MStatus::kFailure != stat) { distanceManipFn.connectToDistancePlug(sizePlug); ... finishAddingManips(); MPxManipContainer::connectToDependNode(node); } return stat; }
変換関数は、マニピュレータ値とプラグ値との変換に使用します。これらはコールバック メソッドとして実装されています。変換関数を使用するマニピュレータの簡単な例としては、プラグにコネクトされた DiscManip(タイプ MFnUnitAttribute::kAngle のアトリビュートに関連します)を持つコンテナ マニピュレータがありますが、これは disc マニピュレータの回転を取り、その回転を 10 倍にします。変換関数は、MFnDiscManip::angleIndex で MPxManipContainer:: getConverterManipValue を使用して、その角度を 10 倍にします。
変換関数は、マニピュレータの位置がオブジェクトの位置に影響される場合、またはマニピュレータのグループを特定の方法で一緒に移動する場合に非常に便利です。変換関数を使用しないと、マニピュレータを 1 単位として一緒に移動できず、マニピュレータの特定コンポーネントは空間の原点か固定位置に残ります。
変換コールバック メソッドには、manipToPlug と plugToManip の 2 種類があります。
plugToManip 変換コールバックは、さまざまな converterPlugValue 項目から converterManipValue 項目の値を取得するために使用します。このコールバックは、すべての converterPlugValue 項目にアクセスし、converterManipValue 項目の値を返します。
manipToPlug 変換コールバックは、さまざまな converterManipValue 項目から converterPlugValue 項目の値を取得するために使用します。このコールバックは、すべての converterManipValue 項目にアクセスし、converterPlugValue 項目の値を返します。
一般的に、manipToPlug 変換はあまり使用しません。converterPlugValue と converterManipValue の使用に加えて、DAG パスなどのクラスデータを使用すると便利なことがあります。fNodePath を使用してノード変換を計算する方法の例については、footPrintManip を参照してください。コンポーネント上で操作するマニピュレータについては、最初のコンポーネントの位置を保存しておくのも便利かもしれません(この方法の例については、componentScaleManip を参照)。
変換コールバック メソッドは、MManipData というデータ型を返します。MManipData では、マニピュレータ変換関数から返されたマニピュレータ データがカプセル化されます。これは、単純なデータか複雑なデータを表します。MManipData 上の単純なデータ メソッドは、bool、short、long、unsigned、float、double を表すために使用します。
MManipData は、行列、カーブ、データの配列など、MFnData またはその派生クラスによって作成された複雑なデータ型を表すためにも使用します。
サンプル プラグインの footPrintManip には、startPointCallback という plugToManip 変換コールバックの例が含まれています。startPointCallback は MManipData を返し、これは MFnNumericData が作成する MObject に設定されています。
class footPrintLocatorManip : public MPxManipContainer { public: ... MManipData startPointCallback(unsigned index) const; MVector nodeTranslation() const; MDagPath fDistanceManip; ... }; MManipData footPrintLocatorManip::startPointCallback (unsigned index) const { // The index is the startPointIndex that is // specified in addPlugToManipConversionCallback, // but it is not necessary to use this in the callback. MFnNumericData numData; MObject numDataObj = numData.create(MFnNumericData::k3Double); MVector vec = nodeTranslation(); numData.setData(vec.x, vec.y, vec.z); return MManipData(numDataObj); } MStatus footPrintLocatorManip::connectToDependNode (const MObject &node) { ... unsigned startPointIndex = distanceManipFn.startPointIndex(); addPlugToManipConversionCallback( startPointIndex, (plugToManipConversionCallback) startPointCallback); ... }