基本
 
 
 

以下は、MPxNode 親クラスからサブクラス化した、単純なユーザ定義ディペンデンシー グラフ ノードで、浮動小数点数を入力として取り、正弦を計算して結果を出力します。

#include <string.h>
#include <iostream.h>
#include <math.h>
#include <maya/MString.h> 
#include <maya/MFnPlugin.h>

なお、これはプラグインなので MFnPlugin.h が必要です。ただし、ノードを登録するには、コマンドではなく別のメソッドを使用します。

#include <maya/MPxNode.h> 
#include <maya/MTypeId.h> 
#include <maya/MPlug.h>
#include <maya/MDataBlock.h>
#include <maya/MDataHandle.h>

これらのヘッダ ファイルは、ほとんどのプラグイン ディペンデンシー グラフ ノードで使用されます。

#include <maya/MFnNumericAttribute.h>

さまざまなアトリビュート型が数多くあります(これらについては後で説明します)。必要なアトリビュート型は、作成するノードの種類によって決まります。このサンプルでは数値データのみを使用します。

class sine : public MPxNode
{

ユーザ定義ディペンデンシー グラフ ノードは、MPxNode クラスから派生します。

public:
 sine();

コンストラクタ

このノードのインスタンスが作成されるたびに、ノードのコンストラクタがコールされます。createNode コマンドをコールするときや、または MFnDependencyNode::create() メソッドを起動するときなどが、これにあたります。

 virtual ~sine();

デストラクタ

ノードを本当に削除する場合のみ、デストラクタがコールされます。Maya には元に戻す(undo)待ち行列があるので、ノードを削除しても実際にノードのデストラクタはコールされません。削除を元に戻した場合に、ノードを再作成せずに復元できるようにするためです。一般的に削除したノードのデストラクタは、元に戻す待ち行列がフラッシュされた場合にのみコールされます。

 virtual MStatus compute( const MPlug& plug,
 MDataBlock& data );

compute() メソッド

compute() メソッドはノードの頭脳です。ノードの入力を使用してノードの実際の作業を実行し、出力を生成します。

 static void* creator();

creator() メソッド

creator() メソッドは、コマンドの creator メソッドと同じ目的で動作します。つまり、Maya でこのノードのインスタンスをインスタンス化できるようにします。createNode コマンドまたは MFnDependencyNode::create() メソッドがノードの新しいインスタンスを要求するたびに、creator() メソッドがコールされます。

 static MStatus initialize();

initialize() メソッドは、ディペンデンシー ノードのための登録メカニズムでコールされます。このため、ユーザ定義ノードを含むプラグインがロードされた直後に一度コールされます。ノードの入出力(たとえばアトリビュート)を定義するために使用されます。

public:
 static MObject input;
 static MObject output;

この 2 つの MObject は sine ノードのアトリビュートです。ノードのアトリビュートには任意の名前を自由に使用できます。ここでは分かりやすくするため、入力(input)と出力(output)を使用します。

 static MTypeId id;

それぞれのノードには固有の識別子が必要です。MFnDependencyNode::create() は、この識別子を使用して作成するノードを識別します。Maya ファイル フォーマットでも、この識別子が使用されます。

ノードをローカルでテストする場合は、0x00000000 から 0x0007ffff までの識別子を任意に使用できますが、永続的な目的でノードを使用する場合は、世界で固有な識別子を Autodesk テクニカル サポートから取得してください。ユーザごとに独自で管理できる、固有の範囲が割り当てられます。

};
MTypeId sine::id( 0x80000 );

ここでは、ノードの識別子を一意のタグに初期化します。これらのタグは、すべてのノードで一意にする必要があります(タグはノードを再作成するためにファイル フォーマットで使用されます)。タグは Autodesk から API ユーザに割り当てます。

MObject sine::input; 
MObject sine::output; 

ノードのアトリビュートは NULL 値に初期化されます。

void* sine::creator() {
 return new sine;
}

前に説明したように、creator() メソッドは、このノードの新しいインスタンスを単に返します。複数のノードを相互にコネクトする必要がある、より複雑な状況では、コネクトされる複数のノード用に 1 つの creator を定義し、この creator を使って割り当てすべてのノードを相互にコネクトすることができます。

MStatus sine::initialize() {

initialize メソッドは、ノードを初めて Maya に登録する際、一度だけコールされます。このメソッドでは、ノードのアトリビュート、つまりその他のノードからのコネクトの対象となる、ノードの入出力データを定義します。

 MFnNumericAttribute nAttr;

このサンプルでは数値データしか使用しないので、すべてのアトリビュートは数値であり MFnNumericAttribute のみが必要になります。

 output = nAttr.create( “output”, “out”,
 MFnNumericData::kFloat, 0.0 );
 nAttr.setWritable(false);
 nAttr.setStorable(false);

この 3 行の最初の行は、sine ノードの出力アトリビュートを定義します。アトリビュートを定義する場合は、アトリビュートのロング ネーム(4 文字以上)とショート ネーム(3 文字以下)を指定する必要があります。この名前は、MEL スクリプトと UI エディタで特定アトリビュートを識別するために使用されます。必須ではありませんが、一般的にはロング ネームをアトリビュートの C++ 識別子と同じにします。このサンプルでは、両方とも出力(output)です。

create メソッドではアトリビュートの型も指定します。この場合は float(MFnNumbericData::kFloat)です。またデフォルト値をゼロに設定します。アトリビュートの名前は、ノード内でのみ一意にする必要があります。別のノードには、同じ名前のアトリビュートを含められます。

次の 2 行は、このアトリビュートの特定の特性を設定します。これは正弦(sine)ノードの出力であるため、その他のノードからは書き込めません。つまり、別のノードの出力アトリビュートは、このアトリビュートにコネクトできません。またこれは出力であるため、ファイルの書き込み時に出力を保存する必要はありません。出力は入力から生成できるからです(出力を保存しても問題にはなりませんが、スペースの浪費になります)。

新しいノードをインスタンス化すると、Maya によって以下の特性が true に設定されます。

以下の特性は false に設定されます。

 input = nAttr.create( “input”, “in”,
 MFnNumericData::kFloat, 0.0 );
 nAttr.setStorable(true);

入力アトリビュートの初期化は出力アトリビュートと同じですが、入力の値はノードで計算できないので、ノードを保存する際に保存する必要があります。

 addAttribute( input );
 attributeAffects( input, output );

入力アトリビュートが正弦ノードのアトリビュートとして追加されます。attributeAffects() メソッドは、入力アトリビュートが出力アトリビュートに影響するタイミングを示すために使用されます。これを認識すると、Maya は、複数の入出力がある、より複雑なノードのグラフでディペンデンシーを最適化できるようになりますが、すべての入力がすべての出力に影響するとは限りません。

 addAttribute( output );

出力アトリビュートが正弦ノードに追加されます。出力アトリビュートが生成されても入力アトリビュートは影響されないので、attributeAffects() メソッドは必要ありません。

 return MS::kSuccess;

成功を返し、ノードが問題なく初期化されたことを Maya に通知します。エラーが返されると初期化は停止します。initialize メソッドは一度しかコールされないので、ノードはこのセッションで使用できなくなります。ノードが必要とするリソースを使用できない場合は、常にエラーが返されます。

}
sine::sine() {}
sine::~sine() {}

非常に単純なノードなので、コンストラクタとデストラクタは何も実行しません。

MStatus sine::compute( const MPlug& plug, MDataBlock& data ) {

compute() メソッドはディペンデンシー グラフ ノードの頭脳で、ノードの実際の作業をすべて実行します。このメソッドは 2 つの引数を取ります。最初の引数は、計算を要求するプラグへの参照で、次の引数はノードのデータ ブロックです。プラグとデータ ブロックについては、後のセクションで詳しく説明します。

 MStatus returnStatus;
 
 if( plug == output )
 {

プラグ

プラグは、再計算されたアトリビュートと考えることができます。このテストでは、再計算が要求されている出力アトリビュートがチェックされます。

この単純なサンプルでは出力アトリビュートしか該当しませんが、より複雑なノードでは、任意の出力になることがあります。プラグが認識されているアトリビュートを表しているかどうか、常にテストしてください。たとえば、誰かがコネクションのあるノードにダイナミック アトリビュートをアタッチしたとします。これにより、入力が変更されていないのに compute メソッドがコールされることがあります。

 MDataHandle inputData = data.inputValue( input,
 &returnStatus );

データ ブロック

データ ブロックには、ノードのこのインスタンスのデータがすべて含まれています。効率上の理由から、このデータは 1 つのブロックとして保存されます。ブロックの一部を参照するには、データ ハンドルを使用します。このケースでは、入力アトリビュートを参照するためにデータ ハンドルが設定されています。

 if( returnStatus != MS::kSuccess )
 cerr << “ERROR getting data” << endl;
 else
 {
 float result = sin( inputData.asFloat() );

MFnDataHandleのas*() メソッドによって、データ ハンドルからデータが取り出されます。as*() メソッドは必ず、宣言されたアトリビュートの型と一致させる必要があります。入力アトリビュートを MFnNumericAttribute::kFloat として宣言したので、データは asFloat() で取り出す必要があります。型と取り出しメソッドが混在すると、重大なエラーの原因となります。たとえばアトリビュートを MFnNumericAttribute::kDouble として宣言し、asFloat() で取り出すと重大なエラーとなります。

 MDataHandle outputHandle = data.outputValue(
 output );

出力アトリビュートのデータ ブロックの一部を参照するために、新しいデータ ハンドルを割り当てます。

 outputHandle.set( result );

出力アトリビュートに計算結果が割り当てられます。

 data.setClean(plug);

再計算を引き起こしたデータ ブロックのプラグが clean にマークされ、新しく計算し直されたことが示されます。

 }
 }
 return MS::kSuccess;
}

成功ステータスが返ると、計算が適切に終了したことが分かります。

MStatus initializePlugin( MObject obj ) { 
 MStatus status;
 MFnPlugin plugin( obj, “My plug-in”, “1.0”, “Any”);
 status = plugin.registerNode( “sine”, sine::id, sine::creator, sine::initialize );

プラグインでは、コマンド プラグインと同じように initializePlugin() と uninitializePlugin() が必要ですが、registerCommand() の代わりに registerNode() を使用し、Maya のノードのデータベースにノードを追加します。ノードの initialize メソッドは、registerNode をコールした結果としてコールされます。initialize メソッドがエラー コードを返すと、registerNode もエラーになり、ノードはロードされません。

 return status;
}
MStatus uninitializePlugin( MObject obj) {
 MStatus status;
 MFnPlugin plugin( obj );
 status = plugin.deregisterNode( sine::id );
 return status;
}

単純なディペンデンシー グラフ ノードが完成しました。