ディペンデンシー グラフについて

このページでは、ディペンデンシー グラフの仕組みを簡単に説明します。

ディペンデンシー グラフ(DG)は、接続された構成要素の集合です。DAG とは異なり、この接続はサイクル可能で、親子リレーションシップを持ちません。その代わりにグラフの接続によって、グラフのある構成要素から別の構成要素にデータを移動できます。グラフ内で入力の受け入れ、計算の実行、新しいデータの出力を行う構成要素は、ディペンデンシー グラフ ノードと呼ばれます。ディペンデンシー グラフ ノードは、モデル作成、デフォメーション、アニメーション、シミュレーション、オーディオ処理など、Maya のほとんどすべてで使用されます。

ノードは、ディペンデンシー グラフを駆動するエンジンです。データがノード内に入り、データに対して操作を実行し、新しいデータを再度使用可能にします。データは入力プラグを通して入り(ノード アトリビュートのインスタンス化)、出力プラグを通して出て行きます。プラグを通して使用できるデータ以外に、ノードが外部データをさらに要求することはありません。

Maya のほとんどのオブジェクトは、ディペンデンシー グラフ ノードか、ノードのネットワーク(複数のノードが接続されたもの)です。たとえば DAG ノードはディペンデンシー グラフ ノードで、シェーダはノードのネットワークです。

ディペンデンシー グラフ ノード同士が接続されると、DAG ノードが影響され、レンダーされるものも影響を受けます。

この図では、DAG 階層とディペンデンシー グラフを結合しています。Transform1、Transform2、Transform3、球(Sphere)がすべて DAG ノードである一方(ディペンデンシー グラフ ノードでもあります)、時間(Time)は単なるディペンデンシー グラフ ノードです。

Transform3 のスケール X (Scale X)、スケール Y (Scale Y)、スケール Z (Scale Z)パラメータは時間の影響を受けています。あるいは、時間の出力が、Transform3 のスケール X、スケール Y、スケール Z の接続に接続されていると考えることもできます。アニメーションの再生時には、球の 2 つのインスタンスのサイズが大きくなります。

グラフ内を流れるデータは、数値のように単純な場合もあれば、サーフェスのように複雑な場合もあります。完全なユーザ定義オブジェクトである場合もあります。

ディペンデンシー グラフは非常に複雑なアーキテクチャで構成されており、その動作を完全に説明すると、もう 1 冊マニュアルが書けてしまいます。ここでは、簡潔に説明します。

前に説明したように、ディペンデンシー グラフは有向グラフで、グラフのエッジは別のノードのプラグを接続します。データはこのエッジに沿って送信されます。データには、数値、ベクトル、行列などの基本の型、カーブ、サーフェス、ユーザ定義型などの複雑な型が含まれます。

Maya ノードの定義の一部として、どの入力アトリビュートがどの出力アトリビュートに影響するかを指定する必要があります(API では、MPxNode::attributeAffects メソッドで実行します)。

ノードのアトリビュートが変更されると、ディペンデンシー グラフは、そのアトリビュートが出力に影響するかどうかチェックします。影響する場合は、それぞれの出力がダーティ(dirty)とマークされます。これは、キャッシュされている値が古く、再計算の必要があるということを表します。出力アトリビュートごとに、ディペンデンシー グラフは、それが接続のソースになっているかどうか確認します。ソースになっている場合は接続がたどられ、たどられたアトリビュートもダーティとマークされます。この処理が繰り返され、最終的には、グラフ内の計算し直す必要があるノードのすべてのアトリビュートがダーティとマークされます。この時点では、どのアトリビュートも再計算されないことに注意してください。その代わりに状態が更新され、どのデータが無効であるかを認識できるようになります。無効なアトリビュートの評価と再計算は、別々の手順で実行されます。

画面のリフレッシュやアニメーションの再生など、特定のイベントによって、ディペンデンシー グラフの再評価が引き起こされることがあります。たとえばリフレッシュ中は、システムが DAG を走査し、DAG ノードごとに再評価の必要があるかどうかを確認します(プラグがダーティであるかどうかチェックします)。再評価の必要がある場合は、プラグに影響するノードの compute メソッドがコールされます。この compute メソッドは、ダーティなプラグに依存している可能性があるので、影響するノードの compute メソッドもコールされます。このようにして、DG の関連する部分で、再評価が必要な部分のみが再評価されます。

最適化のために、DG は必要にならないとグラフを再評価しません。たとえば、3 つのノードがある回転サーフェスを考えます。あるカーブ DAG ノードが、カーブを回転してサーフェスを作成する第 2 ノードの入力として使用され、それが第 3 ノード、すなわちサーフェスを DAG に配置する DAG ノードの出力となっている関係です。入力カーブを修正しても、サーフェスはすぐには再作成されません。再作成は画面が次にリフレッシュされるまで行われません。最終的にサーフェスが確実に再作成されるようにするため、カーブを修正すると、カーブの出力プラグに接続されているすべてのプラグがダーティとマークされ、回転ノードの入力もダーティとマークされます(カーブの出力プラグ自体は、再計算されたばかりなのでダーティとマークされません)。アトリビュートを宣言する場合には、相互に影響するアトリビュートを指定する必要があります。回転ノードでは、出力アトリビュートは入力アトリビュートに依存します。このため入力アトリビュートをダーティとマークすると、出力アトリビュートもダーティとマークされます。回転ノードの出力はサーフェス ノードに接続されているので、回転ノードの出力がダーティとマークされると、サーフェスもダーティとマークされます。このため、画面のリフレッシュ中に DAG が走査されると、サーフェスがダーティとマークされているので、ダーティとマークされているものに依存するすべてが再評価される必要があります。

再評価は、ダーティとマークされた入力を含まない最初のノードで停止します。たとえばカーブの回転角度を変更したが、カーブ自体は変更しなかった場合、回転サーフェスの再作成により、回転ノードは再計算されますが、カーブは影響されません。

これは高レベルでの説明です。実際はいろいろ複雑な判断が行われ、必要ない評価は実行されません。

グラフ内を流れるデータは、パイプ内を流れる水にたとえられます。パイプ自体は接続にあたり、流れるデータがなければパイプは何も行いません。

このたとえを拡張すると、ノードは、栓、シャワー、噴水などにあたります。それぞれ独自の方法で水を使用して何らかを行いますが、水がないと動作しません。

DG を使用する場合の興味深い副作用は、オブジェクトに直接影響を与えるのが難しくなることです。

たとえば、前の図の球を考えてください。Transform3 のスケールに DG ノードが接続されていなければ、UI か API で設定した値が新しいスケールになります。しかし図のように 時間が球のスケールに影響する場合、Transform3 のスケールを UI か API でさらに修正しても、結果は異なったものになります。スケールを設定すると、ディペンデンシー グラフが次に再評価されるまで、時間によって設定された値をオーバーライドしますが、再評価と同時に UI または API で設定した値は、時間により再度オーバーライドされます。

回転サーフェスはより複雑な例です。作成されたサーフェス上の CV を移動したら、何が起きるでしょうか。CV は、DG が再評価されるまで新しい位置に移動しますが、再評価された時点で、回転ノードが指示する位置に戻ります。

しかしモデルの微調整は、複雑なモデルやシーンの作成に必要な操作です。そこで Maya では、この調整を処理するメカニズムを設計しました。メッシュ シェイプはアトリビュート pnts を持ちます。ここには、メッシュの頂点に加えたローカルな変更が保存されます。メッシュの頂点の新しいセットを生成するメッシュ シェイプ ノードの上流接続は、pnts アトリビュートに影響しません。pnts アトリビュートの値は、メッシュの座標に追加されます。NURBS サーフェスと、コントロール ポイントに基づくその他のノードでは、controlPoints アトリビュートに調整情報が保存されます。Maya では、コントロール ポイントに基づくノードの調整情報を保存する tweak ノードも実装されています。tweak ノードは、コントロール ポイントに基づくノードとコントロール ポイント上で動作する上流トランスフォーム ノードの間に配置されます。tweak ノードは、調整情報と変形コントロール ポイントを統合し、最終的なコントロール ポイントを生成してシェイプに渡します。調整情報を処理するアトリビュートの詳細については、「tweak ノード」、「mesh シェイプ ノード」、「nurbsSurface シェイプ ノード」のマニュアル ページを参照してください。

ノード状態

各ディペンデンシー グラフ ノードには、評価方法を示す状態値があります。Maya ユーザは、MEL や Python コマンドおよび API を使用して、Maya UI でこの値を取得して設定できます。状態は、MPxNode::state アトリビュートに整数として格納されます。

状態値 状態 説明

0

通常(Normal)

これは通常、デフォルトのノードの状態です。この状態のノードは普通に評価されます。

1

エフェクトなし

エフェクトなし状態または通過状態は、入力データが未変更のノードを通過できるように、ノードが許可する必要があることを示します。これは、ノードが入力値の計算を実行し、同じタイプの出力を生成する場合に使用します。これにより、周囲のグラフからノードを切断せずに、ノード内の計算を簡単に無効にすることができます。

たとえば、ほぼすべてのデフォーマが、入力ジオメトリを変形せずに、出力アトリビュートに直接送信することで、この状態をサポートします。ただし、デフォーマが通常受け入れる入力とは異なるタイプの出力を生成するノードは、この状態をサポートしません。

カスタム ディペンデンシー ノード クラスを作成する場合、この状態をサポートすることができます。詳細については、「ディペンデンシー グラフ ノードに compute()メソッドを実装する」を参照してください。

2

ブロッキング

ブロッキング状態は、ディペンデンシー ノード ベース クラスで実装され、すべてのノードに適用されます。ブロッキングは、評価フェーズ中の接続に適用されます。ブロックされた接続に対する評価要求が失敗すると、目的プラグが現在の値を保持します。ブロックされた接続はクリーンな状態になることはないため、この状態はダーティな伝播に影響します。

ノードをブロッキングに設定すると、すべての送信接続が解除されたのと同じ動作になる可能性があります。ブロックされたノードの評価を直接要求しない限り、再評価されることはありません。ブロックされたノードは getAttr() 要求に引き続き応答しますが、下流ノードの getAttr() は、ブロックされたノードを再評価しないことに注意してください。

ブロッキング(Blocking)に対して階層のルート変換を設定しても、自動的にはこの階層の子変換に影響しません。その代わり、各子ノードを Blocking 状態に明示的に設定する必要があります。たとえば、次のようなスクリプトを使用します。

import maya.cmds as cmds
def blockTree(root):
    nodesToBlock = []
    for node in {child:1 for child in cmds.listRelatives( root, path=True, allDescendents=True )}.keys():
        nodesToBlock += cmds.listConnections(node, source=True, destination=True )
    for node in {source:1 for source in nodesToBlock}.keys():
        cmds.setAttr( '%s.nodeState' % node, 2 )

このスクリプトを適用してオブジェクトの描画を継続できますが、子ノードはアニメートできません。

カスタム ディペンデンシー ノード クラスを作成する場合、MPxNode ベース クラスをによって自動的に処理されるため、この場合を確認する必要がありません。

内部使用専用として次の 3 つの状態があります。待機 - 通常、待機 - エフェクトなし、および 待機 - ブロッキングです。これらのノードは、ユーザの操作(グラフの操作)中にグラフのパーツを一時的に遮断します。操作が完了したら、Maya はノードの状態を適切にリセットします。これらの状態を心配する必要はありません。