ディペンデンシー グラフ ノードに compute()メソッドを実装する

このトピックでは、カスタム ディペンデンシー ノード クラスに対して MPxNode::compute() メソッドを実装する場合に注意すべきいくつかの原理について紹介します。

Maya は、ノードの出力アトリビュートまたはプラグの 1 つが古く、再計算が必要であると判断した場合、使用するノードの MPxNode::compute()メソッドを呼び出します。再計算する必要のあるプラグ、および使用するノードの現在のインスタンスに対する入出力アトリビュートの現在の値を含むデータ ブロックが引数として渡されます。compute()メソッドは、ノードの入力アトリビュートの現在の値に基づいて、要求したプラグの値を再計算し、計算した出力値をデータ ブロックに戻して保存することが求められます。

パフォーマンスの問題

ノードを頻繁に再評価すると仮定します。できるだけ効率的に計算するように努力します。

たとえば、ノードのレンダリング中、ピクセルごとに複数回評価する必要があるとします。計算をできるだけ高速に処理しないと、ディペンデンシー グラフが簡単にボトルネックとなる可能性があります。

入力アトリビュートのみに依存

すべてのノードの compute()メソッドは、パラメータ内に存在する値、すなわちそのアトリビュートの現在の値のみを使用して動作する必要があります。

計算でその他のデータを使用する必要がある場合は、そのデータをアトリビュート内に作成します。一時的に情報をキャッシュ化して、計算を高速化するだけだとしても、ファイルの読み出し後の最初のリフレッシュを高速化する非表示アトリビュートとして役に立ちます。

出力アトリビュートのみを変更する

ノードは、その出力アトリビュートとは関係のない値またはオブジェクトに影響を与えてはいけません。たとえば、ノードが、DAG またはその他のディペンデンシー グラフ ノードを直接変更してはいけません。変更すると、無限ループが発生する可能性があります。ディペンデンシー グラフの新しい評価がプロンプト表示されるため、ノードの再計算を迫られます。これにより、DAG またはディペンデンシー グラフを再度変更し、ディペンデンシー グラフ評価を新しくしなければならなくなります。何らかの理由でノードがまわりの状態に変更する必要がある場合は、アトリビュートとしてその知識をカプセル化し、計算されたデータを使用できる別のコンポーネントにアトリビュートを接続する必要があります。外部データに影響を与えると、ほとんどの場合以下のうちいずれかに反することになります。

要求したプラグを常に確認する

Maya がどのプラグの再計算を要求しているかを常に確認し、MS::kUnknownParameterを返して認識されていないプラグをすべて処理します。

例:

{
    ...

    if ( (plug == myOutputPlug) || (plug == myOtherOutputPlug) )
    {
         ... // compute and set the requested output values here.
    }
    else
         return MS::kUnknownParameter;

    return MS::kSuccess;
}

ノードによる出力アトリビュートの不必要な再計算を回避することができます。

さらに、MS::kUnknownParameter を返すと、Maya は、使用するクラスの派生元となるベース クラスの compute()メソッドを呼び出します。再計算する必要のあるアトリビュートが、ベース クラスで初期化され、compute()メソッドによって計算される場合、値はベース クラスによって自動的に更新されます。したがって、派生クラスに継承されたアトリビュートを処理する必要はありません。ただし、値を更新したり、派生クラスに固有のアトリビュートと同じように MS::kSuccess を返すことで、ベース クラスが、実装内のアトリビュートのいずれかを処理する方法を上書きできる場合があります。

計算プラグを常にクリーンに設定する

ノードが、要求したプラグの新しい値を計算し、compute()メソッドに渡されるデータ ブロック内にその値を保存する場合、

data.setClean(plug);

MS::kSuccess を呼び出してから返し、プラグに「クリーン」のマークを付けることで、プラグの値が新しく計算されたことを Maya に常に通知します。

プラグにクリーンのマークを付けないと、ノードがディペンデンシー グラフをリフレッシュするたびに、Maya はノードの再評価を複数回要求する場合があります。

データへの参照を保存しない

ノードでは、プラグの compute()メソッドに渡されるいずれかのデータへの参照を保存しないでください。たとえばサーフェス ジオメトリがプラグで入ってきても、このジオメトリへのポインタを保存しないでください。プラグで入ってくるデータは一時的なもので、気付かないうちに消えることがあります。このデータは、ノードの compute()メソッドの実行中に限って存在することが保証されています。

必要に応じて、エフェクトなしノード状態に返信

ノードが特定の種類の入力アトリビュートを受け入れ、出力と同じ種類のデータを生成する場合、「エフェクトなし」または通過ノード状態をサポートしたいことがあります。通常、ノードをこの状態に設定すると、何も変更しなくても、入力アトリビュート値が出力アトリビュートに直接割り当てられます。これにより、Maya ユーザは、このディペンデンシー グラフ内の接続を切断することなく、ノードの計算を回避することができます。

たとえば、次の splitUVCmd/splitUVNode.cpp サンプルのコードは、状態アトリビュートの値を取得し、この値が、「エフェクトなし」状態を示す 1 かどうかが確認されます。その場合は、入力アトリビュートが返されるだけです。

MStatus splitUVNode::compute( const MPlug& plug, MDataBlock& data )
{
    MStatus status = MS::kSuccess;
     
    MDataHandle stateData = data.outputValue( state, &status );
    MCheckStatus( status, "ERROR getting state" );

    if( stateData.asShort() == 1 )
    {
        MDataHandle inputData = data.inputValue( inMesh, &status );
        MCheckStatus(status,"ERROR getting inMesh");
        MDataHandle outputData = data.outputValue( outMesh, &status );
        MCheckStatus(status,"ERROR getting outMesh");
        // Simply redirect the inMesh to the outMesh for the PassThrough effect
        //
        outputData.set(inputData.asMesh());
    }
    ...
}

ノード状態とその値の詳細については、「ディペンデンシー グラフについて」を参照してください。