MPxShadingNodeOverride (とそのサブクラス MPxSurfaceShadingNodeOverride)は、ビューポート 2.0 のプラグイン ソフトウェア シェーディング ノードをレンダリングするために使用されるハードウェア シェーディング フラグメントをオーバーライドする API エントリ ポイントです。MPxShaderOverride とは異なり、MPxShadingNodeOverride の実装は完全な描画を実行しません。実際、こうした実装は描画をまったく行いません。
MPxShadingNodeOverride の実装は、シェーディング ノードの特定のタイプと関連付ける必要があります。ほとんどの場合、プラグインがシェーディング ノードを定義し、個別の MPxShadingNodeOverride が書き出されてビューポート 2.0 のサポートが提供されます。MPxShadingNodeOverride の実装は、分類文字列を使用して MDrawRegistry に登録する必要があります。オーバーライドの分類を満たす分類文字列を使用するシェーディング ノードは、オーバーライドを使用してビューポート 2.0 用に変換されます。分類文字列は、システムが認識できるように「drawdb/shader」で始まる必要があります。
シェーディング ノード オーバーライドは、ソフトウェア シェーディング ノードに関連付けられるハードウェア シェーディング フラグメントを定義します。理想的な状態では、フラグメントに、ノードの入力アトリビュートに正確に対応する入力パラメータと、ノードの出力アトリビュートに正確に対応する出力パラメータがあります。これは常に可能ではありません。通常、ハードウェア フラグメントは、ソフトウェア シェーディング ノードの機能のサブセットをサポートします。可能な場合は常に、シェーディング ノード オーバーライドは、対象のシェーディング ノードからの情報だけを使用して単独で動作する必要があります。シェーディング ネットワークの他のノードについての情報を得る必要はありません。
Maya では、ビューポート 2.0 で表示するシェーディング ネットワークを変換するときに、(シェーディング エンジンに接続されているサーフェス シェーダから開始し、深度を最初にトラバースする方法で)ディペンデンシー グラフを上流にトラバースします。各ノードを参照するごとに、ノード タイプに関連付けられているシェーディング ノード オーバーライドのインスタンスを作成します。作成されたオーバーライドは内部オーバーライドであるか、プラグインによって定義されている場合があります(システムはこの 2 つの違いを認識しません)。ノードのオーバーライドを作成した後、オーバーライドからノードで使用されるフラグメントの名前またはフラグメント グラフが要求されます。次に、Maya シェーディング ネットワークのノードの DG 接続を概算するグラフでフラグメントを接続します。ネットワーク内のすべてのノードのフラグメントが作成されて相互に接続されると、ライティングおよびジオメトリ情報のグローバル フラグメントがいくつか接続され、最終的なフラグメント グラフがシェーディング エフェクトにコンパイルされます。このシェーディング エフェクトは、オリジナルのサーフェス シェーダが割り当てられているシーン オブジェクトを描画するときに適用されます。ネットワークのノード変換に問題がある場合は(たとえば、オーバーライドなし、不正なフラグメント、接続不可)、そのノードで変換が削減されます。その結果、そこでルーティングされたサブネットワークが最終的なシェーディング エフェクトに影響を及ぼさなくなります。
既存のシェーディング ネットワークが変更されると、オーバーライド システムが再度呼び出されます。この変更が Maya シェーディング ネットワークのトポロジを変更した場合、またはネットワーク内のノードのオーバーライドで変更が等しく大きくなるように指定されている場合は、既存のオーバーライドがすべて削除され、変換が最初からやり直されます。変更が単にアトリビュート値の変更である場合は、オーバーライドが呼び出され、元のフラグメントのパラメータに対応した最終的なシェーディング エフェクトのパラメータの値が更新されます。Maya によって多くの値の更新が自動的に処理されますが、必要に応じて、特定の実装でオーバーライドすることができます。
Maya では、内部オーバーライドとプラグイン シェーディング ノード オーバーライドの違いが識別されないので、すべてのビューポート 2.0 システムで使用できるビューポート 2.0 リプリゼンテーションを提供するには、プラグイン ソフトウェア シェーディング ノードに対して MPxShadingNodeOverride を実装することが最適な方法です。ライト、シャドウ、スクリーンスペース エフェクト、透明度、アクセラレーション ストラクチャ、および無関係のプラグインとの統合はすべて自動的に機能します。
図 43: 重要な Maya シェーディング ネットワークと、最終シェーディング エフェクトの作成に使用されるハードウェア フラグメント グラフにそれが変換される過程を示しています。各シェーディング ノードには、関連するシェーディング ノード オーバーライドがあります。オーバーライドは、ノードに対して作成されるハードウェア フラグメントまたはフラグメント グラフを指定します。これらのフラグメントは、いくつかのグローバル ライティング フラグメントおよびジオメトリ フラグメントとともに結合され、最終的なフラグメント グラフが作成されます。グラフの入力パラメータは、含まれているフラグメントの入力パラメータを制御します。
シェーダ フラグメントおよびフラグメント グラフは MFragmentManager によって管理されます。新しいフラグメントやグラフは、XML を使用して定義され、MFragmentManager を介して Maya に登録されます。これらのフラグメントおよびグラフは、MPxShadingNodeOverride の実装によって参照される場合があります。MPxShadingNodeOverride の目的に応じて、フラグメントとフラグメント グラフを交互に使用することができます。フラグメント グラフは、入力/出力パラメータを持つ特殊なケースのフラグメントですが、シェーディング コードを直接定義する代わりに、他のフラグメントで構成されています。このガイドでは、フラグメントに対するすべてのリファレンスがフラグメント グラフも参照すると仮定しています。
フラグメントとフラグメント グラフの XML 形式は XML スキーマ ドキュメント(XSD)によって完全に定義されています(「XML スキーマ」を参照)。ただし、高いレベルでは、この形式を使用して、フラグメントの入力および出力パラメータを定義したり、Cg または HLSL メソッドのコードを定義して、OpenGL や DirectX 11 の要求に応じてシェーディングを実装したりすることができます。フラグメント グラフの場合、この形式を使用して、複数の既存のフラグメントに名前を付けたり、これらのフラグメントを接続する方法を定義したり、これらのフラグメントのアトリビュートをフラグメント グラフの外部入力/出力インタフェースにマップする方法を定義したりすることができます。
サポートされているすべての内部 Maya シェーディング ノードは、フラグメントおよびフラグメント グラフを使用して実装されています。実際、MFragmentManager を使用すると、Maya の多くの内部フラグメントの XML を照会することができます。また、最終的なエフェクトの定義とともに中間フラグメント グラフをディスクにダイナミックにダンプするように指示します。これにより、フラグメントの作者は、Maya が個々のフラグメントを受け取って結合し、最後に最終的なシェーディング エフェクトを作成するプロセスを確認することができます。慎重に検討することで、定義済みの Maya フラグメントと適切に統合するフラグメントを生成することができます。また、可能であれば、プラグインは、独自のフラグメントを定義するのではなく、Maya の内部フラグメントを再利用します。
XML でフラグメントを定義する方法について学習する最も簡単な方法は、Developer Kit の既存の定義を調べるか、Maya の内部フラグメントをいくつかダンプして既存の定義を調べることです。brickShader デベロッパー キット サンプルから抜粋したサンプル フラグメントを次に示します。XML では、最初にフラグメントの名前と設定が定義され、次に、入力パラメータ(プロパティと呼ばれます)、いくつかの入力の既定値、および出力パラメータが定義されます。最後に、フラグメントの 2 つの実装が定義されます。1 つは OpenGL (Cg で記述)用で、もう 1 つは DirectX 11 (HLSL で記述)用です。ここでは、2 つの実装は同じですが(Cg と HLSL には共通点が多数あり)、常に同一ではありません。具体的には、テクスチャのアクセスとマトリックスの順序に関して、GL と DX の違いを処理する必要があります。
<fragment uiName="pluginBrickTexture" name="pluginBrickTexture" type="plumbing" class="ShadeFragment" version="1.0"> <description><![CDATA[Brick procedural texture fragment]]></description> <properties> <float3 name="brickColor" /> <float3 name="jointColor" /> <float name="blurFactor" /> <float2 name="uvCoord" semantic="mayaUvCoordSemantic" flags="varyingInputParam" /> <float2 name="uvFilterSize" /> </properties> <values> <float3 name="brickColor" value="0.750000,0.300000,0.100000" /> <float3 name="jointColor" value="0.750000,0.750000,0.750000" /> </values> <outputs> <float3 name="outColor" /> </outputs> <implementation> <implementation render="OGSRenderer" language="Cg" lang_version="2.1"> <function_name val="pluginBrickTexture" /> <source><![CDATA[ // // Helper function for implementing brick texture fragment // float btnplinearstep(float t, float a, float b) { if (t < a) return 0.0f; if (t > b) return 1.0f; return (t - a)/(b - a); } // // Actual brick texture fragment code, corresponds to the function_name tag // in the implementation definition and signature matches input/output // parameter definitions of the fragment // float3 pluginBrickTexture( float3 brickColor, float3 jointColor, float blurFactor, float2 uv, float2 uvFilterSize) { uv -= floor(uv); // map uv to 0-1 range float v1 = 0.05f; float v2 = 0.45f; float v3 = 0.55f; float v4 = 0.95f; float u1 = 0.05f; float u2 = 0.45f; float u3 = 0.55f; float u4 = 0.95f; float du = blurFactor*uvFilterSize.x/2.0f; float dv = blurFactor*uvFilterSize.y/2.0f; float t = max( min(btnplinearstep(uv.y, v1 - dv, v1 + dv) - btnplinearstep(uv.y, v2 - dv, v2 + dv), max(btnplinearstep(uv.x, u3 - du, u3 + du), 1.0f - btnplinearstep(uv.x, u2 - du, u2 + du))), min(btnplinearstep(uv.y, v3 - dv, v3 + dv) - btnplinearstep(uv.y, v4 - dv, v4 + dv), btnplinearstep(uv.x, u1 - du, u1 + du) - btnplinearstep(uv.x, u4 - du, u4 + du))); return t*brickColor + (1.0f - t)*jointColor; } ]]></source> </implementation> <implementation render="OGSRenderer" language="HLSL" lang_version="11.0"> <function_name val="pluginBrickTexture" /> <source><![CDATA[ // // Helper function for implementing brick texture fragment // float btnplinearstep(float t, float a, float b) { if (t < a) return 0.0f; if (t > b) return 1.0f; return (t - a)/(b - a); } // // Actual brick texture fragment code, corresponds to the function_name tag // in the implementation definition and signature matches input/output // parameter definitions of the fragment // float3 pluginBrickTexture( float3 brickColor, float3 jointColor, float blurFactor, float2 uv, float2 uvFilterSize) { uv -= floor(uv); // map uv to 0-1 range float v1 = 0.05f; float v2 = 0.45f; float v3 = 0.55f; float v4 = 0.95f; float u1 = 0.05f; float u2 = 0.45f; float u3 = 0.55f; float u4 = 0.95f; float du = blurFactor*uvFilterSize.x/2.0f; float dv = blurFactor*uvFilterSize.y/2.0f; float t = max( min(btnplinearstep(uv.y, v1 - dv, v1 + dv) - btnplinearstep(uv.y, v2 - dv, v2 + dv), max(btnplinearstep(uv.x, u3 - du, u3 + du), 1.0f - btnplinearstep(uv.x, u2 - du, u2 + du))), min(btnplinearstep(uv.y, v3 - dv, v3 + dv) - btnplinearstep(uv.y, v4 - dv, v4 + dv), btnplinearstep(uv.x, u1 - du, u1 + du) - btnplinearstep(uv.x, u4 - du, u4 + du))); return t*brickColor + (1.0f - t)*jointColor; } ]]></source> </implementation> </implementation> </fragment>
前述のように、Maya では、シェーディング ネットワーク内の各ノードのフラグメントが結合され、全体的なフラグメント グラフがシェーディング エフェクトにコンパイルされます。このエフェクトのパラメータは、すべてのフラグメントの入力パラメータから渡されます。複数のフラグメントで同じ名前のパラメータが定義される場合に名前の衝突を避けるため、Maya では、ほとんどのパラメータの名前が一意の名前に変更されます。
ほとんどの場合、シェーディング エフェクトのパラメータの値は、効果を作成するために使用された Maya ノードのアトリビュートによって自動的に制御されます。これは、各 Maya ノードのアトリビュートを対応するフラグメントのパラメータに一致させることによって行われます。アトリビュートの名前とタイプは、確立されるこの自動関係のパラメータの名前とタイプに一致する必要があります。上記の サンプル XML では、レンガ テクスチャ フラグメントの入力パラメータ(またはプロパティ)の名前およびデータ タイプが、brickTexture プラグイン ノードで定義された入力アトリビュートの名前およびデータ タイプと同じです。したがって、brickTexture ノードのアトリビュート値を使用して、最終的なシェーディング エフェクトのこれらのパラメータ値が自動的に設定されます。シェーディング ノード オーバーライドによる作業はこれ以上必要ありません。
また、プラグインは、同じタイプのアトリビュートとパラメータの関連付けを指定する場合がありますが、MPxShadingNodeOverride::getCustomMappings() を実装することにより、異なる名前で指定します。このメソッドは、フラグメントの作成直後に自動マッピングが実行される前に呼び出されます。既にカスタム マッピングを持つフラグメントのパラメータに対しては、自動マッピングは実行されません。
フラグメントのパラメータへのマッピングを持たないノードのアトリビュートは無視されます。同様に、ノードのアトリビュートにマッピングしないフラグメントのパラメータは無視されます(MPxShadingNodeOverride::updateShader() によってカスタム パラメータが設定されていない場合)。
すべての機能は、これらのアトリビュートのパラメータ マッピングを通じて制御されます。Maya で、シェーディング ネットワークがトラバースされ、フラグメントが作成および接続されるときは、定義されたマッピング(カスタムまたは自動)がノードの入力アトリビュートにある接続のみがトラバースされます。また、フラグメントが Maya シェーディング グラフのすべてのノード向けに統合されていると、衝突を避けるため、そのパラメータの名前が変更されます(同じフラグメント タイプがグラフで複数回使用できるようになります)。マッピングを行うパラメータの名前のみが変更されます。他のすべてのパラメータでは、名前の衝突が発生する可能性があり、発生した場合、予測不可能な結果が生成されます。
カスタム マッピングは、アトリビュートとパラメータの関係を Maya に通知することに加えて、他のフラグメントと特定のパラメータの接続試行を防止します。または、パラメータの名前変更を防止します(名前の衝突はユーザの責任になります)。また、カスタム マッピングを使用して、名前の衝突を避けるためにパラメータの名前を変更し、パラメータをアトリビュートに関連付けないようにすることもできます(マッピングのアトリビュート名を空の文字列に設定)。こうしたパラメータの値は、MPxShadingNodeOverride::updateShader() の実装によって手動で設定する必要があります。これは、パラメータがアトリビュートによって直接制御されないときに便利ですが、計算された値に設定する必要があります。
入力パラメータと同様に、オーバーライドで指定したフラグメントの出力パラメータが、関連付けられたシェーディング ノードの出力アトリビュートの名前とタイプに一致する場合は、シェーディング ネットワークの要求に応じて、フラグメントの出力と他のフラグメントの入力間の接続が自動的に確立されます。フラグメントに対応する出力パラメータがない Maya のノードの出力アトリビュートは無視されます。ノードの出力アトリビュートが一致しないフラグメントの出力パラメータも無視されます。
現在、フラグメント システムは、通常のシェーディング フラグメントのフラグメントごとに 1 つの出力パラメータのみをサポートしています。複数の出力を持つフラグメントを作成するには(Maya シェーディング ノードの複数の出力に一致させるために)、こうしたフラグメントでは、単一の出力パラメータを「struct」出力として定義する必要があります。個別のフラグメントを作成して、struct タイプを定義し、メイン フラグメントをフラグメント グラフでこの新しい struct 定義フラグメントに接続する必要があります。次に、Maya はグラフを使用して、struct メンバーの名前とタイプを、必要なシェーディング ノードの出力アトリビュートに自動的に一致させます。struct 出力フラグメントを作成および使用する方法の例については、checkerShader または fileTexture サンプル プラグインを参照してください。
入力パラメータと同様に、フラグメントの出力パラメータの名前がノードの出力アトリビュートの名前と一致しない場合に(タイプが一致している限り)、カスタム マッピングを定義することができます。MPxShadingNodeOverride::outputForConnection() を実装し、カスタム出力マッピングを処理します。
オプションのカスタム アトリビュート パラメータ マッピングとともに使用するフラグメントを指定する MPxShadingNodeOverride の実装は、ビューポート 2.0 シェーディング システムで正しく機能します。最終的なエフェクトのパラメータ値は、Maya ノードが変更されるたびに、Maya ノードのアトリビュート値に自動的に設定されます。ただし、追加のコントロールが必要な場合、この実装は updateDG() および updateShader() メソッドをオーバーライドする場合があります。これらの 2 つのメソッドは、最終的なシェーダのパラメータ値を更新する必要がある場合に呼び出され、シェーディング ノードのアトリビュートに直接マッピングされない最終的なエフェクトのパラメータ値を設定することができます。
updateDG() では、オーバーライドが必要な情報を Maya ディペンデンシー グラフから照会してキャッシュする必要があります。updateShader() の DG へのアクセス試行はエラーであり、これにより不安定になることがあります。
updateShader() では、オーバーライドに MShaderInstance が指定されています。指定されたフラグメントはその一部です。また、ノード(自動およびカスタム)の既知のアトリビュート パラメータ マッピングの完全なリストが指定されています。ほとんどのパラメータはフラグメントのオリジナルの名前から変更されるため、実装はマッピングから「解決された名前」を使用して、MShaderInstance の値を設定する必要があります。実装がシェーダ インスタンスのパラメータ値を設定する場合がありますが、アトリビュートを定義するマッピングを使用するパラメータは自動的に設定されます。マッピングを使用しないパラメータ、またはアトリビュートがないマッピングを使用するパラメータにのみが処理されます。Maya シェーディング ノード グラフ内の他のフラグメントからパラメータの MShaderInstance の値を設定することもできますが、この動作は推奨されておらず、サポートされていません。このような値が上書きされる可能性があり、動作は予想外の結果となります。
カスタム パラメータの設定の例については、デベロッパー キット サンプル phongShader および fileTexture を参照してください。
ハードウェア シェーディングの観点からは、これまで説明したすべてのフラグメント入力パラメータは、均一パラメータとみなされます。フラグメント コードの変更パラメータ(つまり、頂点データによって制御されるパラメータ)や、レンダリング システムによって値が自動的に入力される、セマンティックを使用するパラメータ(システム パラメータとも呼ばれます)にアクセスすることもできます。
どちらの場合も、入力パラメータを定義するときに、名前およびタイプに加え、「セマンティック」を指定することによって行われます。変更パラメータの場合は、パラメータを変更とマークする必要があります。上記のレンガ テクスチャの XML サンプルでは、「uvCoord」パラメータが変更パラメータの例です。セマンティック「mayaUvCoordSemantic」は、「uvCoord」という名前のパラメータで使用する場合に、正しい UV セットがフラグメント(UV リンクに基づく)で使用できることを確認する必要のある特別なセマンティックです。次の表は、変更パラメータで認識されるセマンティックのリストを示しています。
名前 | タイプ(Type) | 意味 |
Pm | 3-float | オブジェクト空間の位置 |
Pw | 3-float | ワールド空間の位置 |
Pv | 3-float | ビュー空間の位置 |
Nm | 3-float | オブジェクト空間の法線 |
Nw | 3-float | ワールド空間の法線 |
U0 - U7 | 2-float または 3-float | 8 つの特定チャネルの 1 つの UV 座標。Maya では、衝突がないようにするために、最終的なシェーディング エフェクトのすべてのフラグメントで UV チャネルの割り当てを処理するので、UV が必要な場合は、「mayaUvCoordSemantic」セマンティックを使用する方が適切です。 |
mayaUvCoordSemantic | 2-float または 3-float | 不特定の UV チャンネル。Maya では、Maya ディペンデンシー グラフの UV リンクに基づいて正しい UV データが入力されます。パラメータの名前は「uvCoord」に設定する必要があります。 |
Tw | 3-float | ワールド空間の接線。Maya では、衝突がないようにするために、最終的なシェーディング エフェクトのすべてのフラグメントでチャネルの割り当てを処理するので、接線が必要な場合は、「tangent」セマンティックを使用する方が適切です。 |
接線 | 3-float | ワールド空間の接線。Maya では、Maya ディペンデンシー グラフの UV リンクに基づいて正しい接線データが入力されます。パラメータの名前は「mayaTangentIn」に設定する必要があります。 |
Bw | 3-float | ワールド空間の複接線。Maya では、衝突がないようにするために、最終的なシェーディング エフェクトのすべてのフラグメントでチャネルの割り当てを処理するので、複接線が必要な場合は、「bitangent」セマンティックを使用する方が適切です。 |
複接線 | 3-float | ワールド空間の複接線。Maya では、Maya ディペンデンシー グラフの UV リンクに基づいて正しい複接線データが入力されます。パラメータの名前は「mayaBitangentIn」に設定する必要があります。 |
Vw | 3-float | ワールド空間のビュー ベクトル |
fcolor または C_4F | 4-float | 頂点カラー。OpenGL モードで 1 つの変更パラメータをサポートしています。 |
colorSet | 4-float | 頂点カラー。OpenGL モードおよび DX11 モードの両方で複数の変更パラメータをサポートしています。 |
システム パラメータのセマンティックの詳細については、「MShaderInstance で使用するためにビューポート 2.0 でサポートされるセマンティック」を参照してください。これらのセマンティックは、多くの場合、現在のワールド ビュー投影行列などのアクティブな行列にアクセスするために使用されます。システム パラメータの使用例については、depthShader デベロッパー キット サンプルを参照してください。
MPxSurfaceShadingNodeOverride は、特にサーフェス シェーダ用の MPxShadingNodeOverride の拡張機能です。Maya シェーディング エンジンに直接接続される可能性があるプラグイン サーフェス シェーダ ノードは、ビューポート 2.0 のサポートを提供するときに、MPxShadingNodeOverride ではなく、このクラスから派生するオーバーライドを定義する必要があります。
MPxShadingNodeOverride と同様に、MPxSurfaceShadingNodeOverride の実装は、シェーディング ノードの特定のタイプに関連付けられている必要があります。MPxSurfaceShadingNodeOverride の実装は、分類文字列を使用して MDrawRegistry に登録する必要があります。オーバーライドの分類を満たす分類文字列を使用するシェーディング ノードは、オーバーライドを使用してビューポート 2.0 用に変換されます。分類文字列は、システムによってサーフェス シェーディング ノードとして認識されるように、「drawdb/shader/surface」で始まる必要があります。
MPxShadingNodeOverride のすべての機能を提供することに加えて、MPxSurfaceShadingNodeOverride を使用すると、オーバーライドで、サーフェス シェーダ固有の方法で処理されるアトリビュートとパラメータが指定されます。
これらの特別な設定の使用例については、デベロッパー キットの lambertShader サンプル プラグインを参照してください。
また、MPxSurfaceShadingNodeOverride オブジェクトは、MPxShadingNodeOverride オブジェクトとは異なる方法で扱われます。特に、Maya ではライトのシェーダ フラグメントを MPxSurfaceShadingNodeOverride の実装によって提供されたフラグメントに接続しようとします。フラグメントの次の名前付き入力パラメータが認識され、指定された Maya ライティング パラメータに自動的に接続されます。
パラメータ名 | パラメータ タイプ | ライトから自動的に接続される値 |
Lw | 3-float | 拡散ライティングのワールド空間のライト方向ベクトル |
HLw および SLw | 3-float | 反射ライティングのワールド空間のライト方向ベクトル |
diffuseI | 3-float | ライトの拡散放射角度 |
specularI | 3-float | ライトの反射放射角度 |
ambientIn | 3-float | すべてのアンビエント ライトからの成分の合計 |
シーンに複数のライトがある場合、最終的なシェーディング エフェクトを作成するフラグメントからの成分は、各ライトに対して一度計算され、その後、結果が累積されます。したがって、上記のすべてのパラメータは、現在計算されているライトに適用されます。オーバーライドで、特殊なライト パラメータのカスタム アトリビュート パラメータ マッピングを定義しないでください。ライト情報を使用する方法の例(MFragmentManager を使用して、フラグメントおよびフラグメント グラフの XML をダンプします)については、Maya Phong シェーダ(mayaPhongSurface)のフラグメントおよびフラグメント グラフを参照してください。
MPxSurfaceShadingNodeOverride を実装するデベロッパー キットのサンプル プラグインには、lambertShader、phongShader、depthShader、onbShader などがあります。