ここでは、Maya API 開発キットで使用できる rockingTransform のサンプルについて説明します。rockingTransform のサンプルは、X 軸の周りのロッキング モーションを含むアトリビュートを導入します。このロッキング モーションまたは回転は、通常の 回転(Rotate)アトリビュートとは別に格納されますが、変換行列に組み込まれます。また、新しい rockXValue クラス変数にアクセスできるように、get/set メソッドがクラスに追加されています。
rockingTransformMatrix クラスは MPxTransformationMatrix を継承して、asMatrix() などの仮想メソッドを定義します。
class rockingTransformMatrix : public MPxTransformationMatrix { // A really simple implementation of MPxTransformationMatrix. // The methods include: // - Two accessor methods for getting and setting the // rock // - The virtual asMatrix() method which passes the matrix // back to Maya when the command "xform -q -ws -m" is invoked public: rockingTransformMatrix(); static void *creator(); virtual MMatrix asMatrix() const; virtual MMatrix asMatrix(double percent) const; virtual MMatrix asRotateMatrix() const; // Degrees double getRockInX() const; void setRockInX( double rock ); static MTypeId id; protected: typedef MPxTransformationMatrix ParentClass; // Degrees double rockXValue; };
rockingTransformNode を実装する際には、MPxTransform から派生させて、createTransformationMatrix() や validateAndSet() などの必要な仮想メソッドをサポートします。また、このクラスには新しい aRockInX アトリビュートが追加されています。
class rockingTransformNode : public MPxTransform { // A really simple custom transform. public: rockingTransformNode(); rockingTransformNode(MPxTransformationMatrix *); virtual ~rockingTransformNode(); virtual MPxTransformationMatrix *createTransformationMatrix(); virtual void postConstructor(); virtual MStatus validateAndSetValue( const MPlug& plug, const MDataHandle& handle, const MDGContext& context); virtual void resetTransformation (MPxTransformationMatrix *); virtual void resetTransformation (const MMatrix &); // Utility for getting the related rock matrix pointer rockingTransformMatrix *getRockingTransformMatrix(); const char* className(); static void * creator(); static MStatus initialize(); static MTypeId id; protected: // Degrees static MObject aRockInX; double rockXValue; typedef MPxTransform ParentClass; };
プラグインを初期化する場合、MFnPlugin を使用して新しいトランスフォーム ノードと関連する変換行列を登録する必要があります。トランスフォームを登録する場合、MTypeIds に格納する一意の識別子が必要です。
MStatus initializePlugin( MObject obj ) { MStatus status; MFnPlugin plugin(obj, "Autodesk", "6.5", "Any"); status = plugin.registerTransform( "rockingTransform", rockingTransformNode::id, &rockingTransformNode::creator, &rockingTransformNode::initialize, &rockingTransformMatrix::creator, rockingTransformMatrix::id); if (!status) { status.perror("registerNode"); return status; } return status; }
カスタム ノードの削除は、MFnPlugin の deregisterNode() メソッドをコールして uninitializePlugin() で実行されます。
MStatus uninitializePlugin( MObject obj) { MStatus status; MFnPlugin plugin(obj); status = plugin.deregisterNode( rockingTransformNode::id ); if (!status) { status.perror("deregisterNode"); return status; } return status; }
次のサンプルは、constructor、creator、get/set メソッドの単純な実施例です。
// // Matrix constructor. Initialize any // class variables. // rockingTransformMatrix::rockingTransformMatrix() { rockXValue = 0.0; } // // Creator for matrix // void *rockingTransformMatrix::creator() { return new rockingTransformMatrix(); } // // Utility method for getting the rock // motion in the X axis // double rockingTransformMatrix::getRockInX() const { return rockXValue; } // // Utility method for setting the rcok // motion in the X axis // void rockingTransformMatrix::setRockInX( double rock ) { rockXValue = rock; }
asMatrix() メソッドは、カスタム変換行列を使用する上で非常に重要です。このメソッドは、カスタム トランスフォームから変換行列を要求する際にコールされます。次のサンプルの asMatrix() は、ParentClass::asMatrix() をコールして Maya の標準的な変換行列を計算します。その後、ロッキング モーションを使用して、計算された変換行列にクォータニオン回転が追加されます。この方法を使うと、カスタム トランスフォームは新しいアトリビュートを変換行列の出力に統合できます。
// // This method will be used to return information to // Maya. Use the attributes which are outside of // the regular transform attributes to build a new // matrix. This new matrix will be passed back to // Maya. // MMatrix rockingTransformMatrix::asMatrix() const { // Get the current transform matrix MMatrix m = ParentClass::asMatrix(); // Initialize the new matrix we will calculate MTransformationMatrix tm( m ); // Find the current rotation as a quaternion MQuaternion quat = rotation(); // Convert the rocking value in degrees to radians DegreeRadianConverter conv; double newTheta = conv.degreesToRadians( getRockInX() ); quat.setToXAxis( newTheta ); // Apply the rocking rotation to the existing rotation tm.addRotationQuaternion( quat.x, quat.y, quat.z, quat.w, MSpace::kTransform ); // Let Maya know what the matrix should be return tm.asMatrix(); }
複数の asMatrix() メソッドが存在することに注意してください。カスタム トランスフォームが行列に与える影響によっては、すべての asMatrix() メソッドを実装する必要があります。
API を使用する他のプロキシ ノードの場合と同様に、新しいアトリビュートの追加および設定を行うには initialize() メソッドを使用します。次のサンプルでは、aRockInX アトリビュートがノードに追加され、キー設定可で ワールド空間に作用(affects world space)に設定されます。また、アトリビュートが変更されたときに Maya が正しく更新されるように、mustCallValidateAndSet() がコールされます。
// // Node initialize method. We configure node // attributes here. Static method so // the *this pointer is not available. // MStatus rockingTransformNode::initialize() { MFnNumericAttribute numFn; aRockInX = numFn.create("RockInX", "rockx", MFnNumericData::kDouble, 0.0); numFn.setKeyable(true); numFn.setAffectsWorldSpace(true); addAttribute(aRockInX); // This is required so that the validateAndSet method // is called mustCallValidateAndSet(aRockInX); return MS::kSuccess; }
// // Constructor of the transform node // rockingTransformNode::rockingTransformNode() : ParentClass() { rockXValue = 0.0; } // // Constructor of the transform node // rockingTransformNode::rockingTransformNode(MPxTransformationMatrix *tm) : ParentClass(tm) { rockXValue = 0.0; } // // Post constructor method. Has access to *this. Node setup // operations that do not go into the initialize() method should go // here. // void rockingTransformNode::postConstructor() { // Make sure the parent takes care of anything it needs. // ParentClass::postConstructor(); // The baseTransformationMatrix pointer should be setup properly // at this point, but just in case, set the value if it is missing. // if (NULL == baseTransformationMatrix) { MGlobal::displayWarning("NULL baseTransformationMatrix found!"); baseTransformationMatrix = new MPxTransformationMatrix(); } } // // Destructor of the rocking transform // rockingTransformNode::~rockingTransformNode() { } // // Method that returns the new transformation matrix // MPxTransformationMatrix *rockingTransformNode::createTransformationMatrix() { return new rockingTransformMatrix(); } // // Method that returns a new transform node // void *rockingTransformNode::creator() { return new rockingTransformNode(); }
validateAndSetValue() 仮想メソッドを使用すると、アトリビュートの入力が正しいことを確認できます。たとえば、アトリビュートがロックまたはクランプされているかどうかを確認する必要があります。この場合、このメソッドを使用するとロックおよびクランプを無視できます。次の実施例では、この手順が実行されています。
MStatus rockingTransformNode::validateAndSetValue( const MPlug& plug, const MDataHandle& handle, const MDGContext& context) { MStatus status = MS::kSuccess; // Make sure that there is something interesting to process. // if (plug.isNull()) return MS::kFailure; MDataBlock block = forceCache(*(MDGContext *)&context); MDataHandle blockHandle = block.outputValue(plug, &status); ReturnOnError(status); if ( plug == aRockInX ) { // Update our new rock in x value double rockInX = handle.asDouble(); blockHandle.set(rockInX); rockXValue = rockInX; // Update the custom transformation matrix to the // right rock value. rockingTransformMatrix *ltm = getRockingTransformMatrix(); if (ltm) ltm->setRockInX(rockXValue); else MGlobal::displayError("Failed to get rock transform matrix"); blockHandle.setClean(); // Mark the matrix as dirty so that DG information // will update. dirtyMatrix(); } // Allow processing for other attributes return ParentClass::validateAndSetValue(plug, handle, context); }
MPxTransform ノードでは、ロックとクランプの確認にいくつかの仮想メソッドを利用できます。たとえば、回転を使用してロックとクランプを適切に処理するには、checkAndSetRotation()、applyRotationLimits()、applyRotationLocks() を使用します。他のアトリビュートにも、同じメソッドのセットが存在します。Maya API 開発キットの rockingTransformCheck のサンプルには、回転に関するこれらの原理が例示されています。