マニピュレータはノード上のプラグとやり取りを行い、その値を設定して、マニピュレータの値もプラグの値に対して適切に設定します。
マニピュレータとノードのやり取りは、単純な 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);
...
}