API ガイド > ディペンデンシー グラフ プラグイン >

# 基本

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

create メソッドではアトリビュートの型も指定します。この場合は float (MFnNumbericData::kFloat)です。また既定値をゼロに設定します。アトリビュートの名前を一意にする必要があるのは同一ノード内のみです。別のノードでは同じ名前のアトリビュートを使用できます。

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

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

- readable (出力として使用できるか)
- writable (入力として使用できるか)
- connectable (別のアトリビュートから接続できるか)
- storable (ファイルに保存できるか)
- settable (値を設定できるか)

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

- multi (配列)
- keyable (キーフレーム化できるか)
- indeterminant (使用されるかどうかわからないアトリビュート -- 関連するレンダリング)
- hidden (アトリビュート エディタ(Attribute Editor)内で可視でない)

        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;
    }

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