MPxShaderOverride は、ビューポート 2.0 でプラグイン サーフェス シェーダのすべてのシェーディングとライティングをオーバーライドする API エントリ ポイントです。MPxGeometryOverride と同様に、このクラスでは、シェーダの Maya ノードを定義しません。このクラスは完全な描画をオーバーライドするため、オーバーライドが、テクスチャ、ライト、ジオメトリなどのリソースの定義とバインドを行います。MDrawContext(描画コンテキスト)のインスタンスが適切なポイントで提供されるので、デバイス情報にアクセスしてこれらのタスクを容易に実行できます。このクラスは未処理の描画コールが必要であるため、描画 API に依存していません。両方の API へのサポートが必要な場合は、DirectX および OpenGL 用に個別のコード パスを作成する必要があります。Maya CgFX および dx11Shader プラグインでのビューポート 2.0 のサポートは、このインタフェースを使用して実装されます。
MPxShaderOverride の実装は、特定のタイプのシェーディング ノードと関連付ける必要があります。ほとんどの場合は、プラグインでシェーディング ノードを定義し、シェーダを使用するオブジェクト用の描画コードを提供するために別の MPxShaderOverride が作成されます。CgFX プラグインでは MPxHwShaderNode インタフェースを使用して CgFX ノードを定義し、ビューポート 2.0 での描画をサポートする別の MPxShaderOverride が存在します。MPxShaderOverride の実装は、分類文字列を使用して MDrawRegistry に登録する必要があります。オーバーライドの分類を満たす分類文字列を使用するシェーダは、オーバーライドを使用して描画されます。分類文字列は、システムが認識できるように「drawdb/shader」で始まる必要があります。Maya では、シーンでアクティブに使用されている関連付けられたシェーダ タイプの各インスタンスに対して登録されたシェーダ オーバーライドの 1 つのインスタンスを作成します。
上位レベルでは、MPxShaderOverride に主なタスクが 2 つあります。描画する必要があるジオメトリ ストリームを指定し(ジオメトリ要件)、割り当て先のオブジェクトを描画することです。これは、新しいレンダリング モデルの producer-consumer (生成者-使用者)リレーションシップを示します。このクラスは、ジオメトリ要件(MGeometryRequirements)を生成します。この要件は、ジオメトリ ストリームを生成するためにジオメトリ システム(MPxGeometryOverride の内部クラスまたはプラグイン実装)で使用されます。次に、このクラスの描画メソッドが、描画するためにジオメトリ ストリームを使用します。

図 41: 2 つの異なる DAG オブジェクトに割り当てられたシェーダ オーバーライドのサンプル構成です。一方の DAG オブジェクトは、ジオメトリ オーバーライドを使用しています。もう一方は、内部ジオメトリ アップデータを使用しています。この構成は、NURBS サーフェス アップデータの例になります。シェーダ オーバーライドは、各アップデータの要件を「生成」します。各オブジェクトは、レンダリングする新しいジオメトリを「生成」します。このジオメトリは、シェーダ オーバーライドによって「使用」されるまでは、関連付けられたレンダー項目の下位のパイプラインに渡されます。
オーバーライドで実装する必要のある 3 つの主なフェーズは、初期化、更新、および描画です。
MPxShaderOverride のフェーズは、関連付けられたシェーダ タイプのインスタンスがオブジェクトにバインドされている場合、またはシェーダそれ自体の入力アトリビュートが変更された場合にトリガーされて実行されます。更新をトリガーするために、特別なロジックを追加する必要はありません。コールされる更新メソッドは、発生した変更のタイプによって異なります。シェーダの新しい割り当てによって、完全なリビルドがトリガーされます。同様に、rebuildAlways() が true を返す場合は、アトリビュートの変更でも完全なリビルドがトリガーされます。その他の場合はすべて、初期化はスキップされ、更新のみが行われます。描画フェーズは、シェーダでオブジェクトを描画する必要があるすべての更新時に発生します。
初期化フェーズ中に、addGeometryRequirement() を使用してジオメトリ ストリーム要件を指定することができます。この要件では、特定のシェーディング エフェクトが割り当てられるオブジェクトから、必要なジオメトリ ストリームを指定します。要件を指定しない場合、1 つの位置ストリーム要件が使用されます。initialize() メソッドは、シェーダ キーを表す文字列を返す必要があります。MPxShaderOverride の異なるインスタンスが本質的に同じシェーダを表していても、別のシェーダ パラメータを使用していることがよくあります。シェーダ キーは、同じシェーダを表す MPxShaderOverride インスタンスを識別するために使用されます。レンダリングを最適化するために、レンダラは、同じ MPxShaderOverride シェーダ キーを使用するオブジェクトのレンダリングを統合しようとします。これにより、プラグインはシーケンス全体で 1 回セットアップを実行するだけで済むようになります。各プラグインが、同じシェーダを表す目的を決定します。

図 42: シェーダ オーバーライドによって提供されるシェーダ キーを 2 つのレンダー アイテムで同じにすることができます。この場合、統合によって、描画が行われる前にこれらの項目を 1 つのレンダー項目に「マージ」できます。
更新フェーズ中に、シェーディングに必要なすべてのデータ値が更新されます。インタフェースでは、ディペンデンシー グラフにアクセスできるポイント(updateDG())と、描画 API (OpenGL または DirectX)にアクセスできるポイント(updateDevice())間が明確に分割されています。中間データは、EndUpdate() がコールされるときにクリーンアップできます。たとえば、オーバーライドに、指定されたノードのアトリビュートからの入力が必要な場合があります。
オーバーライドは、シェーディングに半透明が含まれるどうかに関するヒントを提供することができます。このヒントは、updateDevice() と endUpdate() の間で呼びだされる isTransparent() メソッドをオーバーライドして提供することができます。
ディスプレイスメントなどの高度なシェーディング エフェクトによって、シェーディングされるオブジェクトのサイズが変更されることがあります。この場合は、誤ったタイミングでフラスタム カリングされないように、オブジェクトのバウンディング ボックスを調整することをお勧めします。これは、boundingBoxExtraScale() メソッドをオーバーライドして実現することができます。これによって、オーバーライドでオブジェクトの絶対値バウンディング ボックスを提供することはできなくなります。代わりに、オーバーライドは、計算されたバウンディング ボックスに適用されるスケール係数を提供します。これは、多数のシェーダが同じオブジェクトに影響を与える可能性があり、各シェーダは他のすべての要件を把握できないからです。
描画フェーズは、純粋な仮想 draw() メソッドによって実行されます。このメソッドは、正常に描画できる場合は true を返します。false を返す場合、描画はサポートされていないマテリアルで使用される既定のシェーダを使用して行われます。描画は意図的にデータ更新と混合されません。描画がコールされる時点で、すべての評価が完了している必要があります。更新フェーズと描画フェーズ間で受け渡す必要があるユーザ データがある場合は、オーバーライドでそのデータそのものをキャッシュする必要があります。描画中に Maya のディペンデンシー グラフにアクセスするとエラーになり、この操作によって不安定になることがあります。すべてのシェーダの設定とジオメトリの描画を処理する draw() メソッドの実装は可能ですが、draw() メソッドの使用が必要なのは、シェーダの設定に対してのみです。この後に、drawGeometry() がコールされて、Maya でジオメトリの描画を処理することができます。手動でのジオメトリのバインドが必要な場合は、draw() メソッドに渡されるレンダー項目リスト内の各レンダー項目のジオメトリを使用して、ハードウェア リソース ハンドルを照会できます。
また、activateKey() および terminateKey() メソッドは、レンダー項目が別のシェーダ キーを使用して描画されるたびに描画フェーズでも呼び出されます。activateKey() および terminateKey() メソッドは、同じシェーダ キーを共有している draw() コールのバッチに対して一度だけレンダリング状態を構成してレンダリングを最適化するために使用できます。すべてが同じシェーダ キーを返す 3 つのシェーダ オーバーライド(A、B、C)の場合、起動のサンプル シーケンスは次のようになります。
shaderOverrideA->activateKey(...) shaderOverrideA->draw(...) shaderOverrideB->draw(...) shaderOverrideC->draw(...) shaderOverrideA->terminateKey(...)
すべての描画メソッドは、MDrawContext パラメータを使用して描画コンテキストにアクセスします。これは、テクスチャ マネージャとともに、可能な限り、状態およびテクスチャを管理するために使用する必要があります。これらのインタフェースを使用すると(未処理の描画 API コールを行うのとは対照的に)、パフォーマンスが向上し、デバイス状態の破損に関する問題を回避できます。
handlesDraw() メソッドは、activateKey()、draw() および terminateKey() の前にコールされます。このメソッドを使用して、オーバーライドは、現在の描画コンテキストに基づいて描画を処理するかどうかを決定できます。たとえば、カラー パスの描画は処理しても、シャドウ マップ作成パスの描画は処理しないことを選択できます。このメソッドから false が返された場合、activateKey()、draw() および terminateKey() はコールされません。
Maya SDK の例「hwPhongShader」は、MPxShaderOverride の簡単な使用例を示しています。プラグインは、MPxHwShaderNode を使用するノードを定義し、クラス 「hwPhongShaderOverride」に MPxShaderOverride を実装してビューポート 2.0 のサポートを提供します。オーバーライドの draw() メソッドでは、(コンパイル時の定数によって制御される)描画の両方のメソッドが示されます。最初の例では、シェーダを設定してから、drawGeometry() をコールして描画を実行します。2 番目の例では、シェーダの設定後にすべてのジオメトリ バインドを手動で実行し、手動で OpenGL コール glDrawElements() を行って描画を実行します。
MPxShaderOverride の使用法の詳細な例については、CgFX プラグイン(cgFxShaderNode.h/.cpp)および dx11Shader プラグイン(dx11ShaderOverride.h/.cpp)を参照してください。dxShaderOverride には、handlesDraw() の使用例が含まれています。
MDrawContext は、描画時にデバイスの状態に対する読み取り専用アクセスを提供します。
このクラスを使用する主な利点は、状態がキャッシュされるので再計算を回避することができ、データのクエリーは通常 GPU デバイスにアクセスしないという点です。これは、コストのかかるパイプラインの区画を回避するのに役立ちます。たとえば、プラグインは OpenGL で次のようにモデル ビューと投影行列を取得するためのコールを行う場合があります。
float tmp[4][4]; glGetFloatv(GL_MODELVIEW_MATRIX, &tmp[0][0]); glGetFloatv(GL_PROJECTION_MATRIX, &tmp[0][0]);
HWRender::MDrawContext& context; MStatus status; MMatrix transform = context.getMatrix(MHWRender::MDrawContext::kWorldViewMtx, &status); MMatrix projection = context.getMatrix(MHWRender::MDrawContext::kProjectionMtx, &status);
アクセスできるデータをさまざまな頻度で更新できます。ビューポートのサイズは各フレーム データの例を示しています。モデリングの行列は、レンダー項目ごとのデータの例を示しています。
状態マネージャ(MStateManager)はこのクラスからのみアクセスできます。MDrawContext がアクティブな場合のみ状態を変更できるからです。
追加のセマンティックに関する情報は、「パス コンテキスト」(MPassContext)の形式で提供されます。現在、パスの識別子とセマンティックのリストを照会することができます。パスの識別子は、内部で生成された識別子、またはレンダリング ループ オーバーライドによって指定された識別子になります。詳細については、「3.6 レンダリング ループ オーバーライド」を参照してください。
セマンティック リスト内の項目は、パイプライン内の状態または場所に関する情報を段階的に洗練した一連の情報を提供します。次に、いくつかの例を示します。