このセクションでは、ビューポート 1.0 (既定のビューポート)の MPxSurfaceShapeUI インタフェースと MPxSurfaceShape インタフェース、およびコンセプトのビューポート 2.0 インタフェースへのマッピングに焦点を当てています。MPxGeometryOverride および MPxSubSceneOverride に焦点が当てられ、この 2 つのインタフェース間のアプローチにおける重要な相違点がハイライトされています。
主な目的は、カスタムのレンダリング可能項目を「カスタム」描画にインスタンス化する方法を示すことです。
ビューポート 2.0 API では、レンダリング/描画インタフェースのみが提供されます。
既に存在するビューポート 1.0 インタフェースが、選択とコンポーネントの処理に使用されます。これは、MPxSurfaceShapeUI::select() および MPxSurfaceShapeUI::snap() などのメソッドを含んでいます。
UV エディタへの描画は変更されません。既存のビューポート 1.0 の方法を使用する必要がありますが、ビューポート 2.0 には UV エディタでの描画を行う特定のインタフェースがないため、MPxSurfaceShapeUI::drawUV()/MPxSurfaceShapeUI::canDrawUV() を使用します。
関連するマテリアルをオーバーライドするビューポート 1.0 の方法には、ビューポート 2.0 のレンダリングには必要ありません。 これには、MPxSurfaceShapeUI::material() および MPxSurfaceShapeUI::materials() が含まれます。
ビューポート 1.0 では、レンダリング可能項目は描画要求(MDrawRequest)として表されます。ビューポート 2.0 では、これに最も近いコンストラクトはレンダー アイテム(MRenderItem)です。これらの集合が、オブジェクトのレンダリング可能項目の合計セットを表すものと考えられます。
ビューポート 1.0 では、定義済みの MDrawRequest はありません。
ビューポート 2.0 では、オブジェクトに対して割り当てられたマテリアルを使用する描画を表す MRenderItem が提供されます。これらのマテリアルをレンダー アイテムと呼びます。 レンダラによって事前定義されていない項目は、「カスタム」と見なされます。
ビューポート 1.0 の手法では、描画要求を作成して適切なコレクションに返し、描画時に要求を明示的に描画します。ビューポート 2.0 の手法では、既存のレンダー アイテムを作成、更新、または選択的にオーバーライドして、ジオメトリ更新と最終的な内部描画に適したコレクションに返します。
レンダー アイテムには永続的な性質があるため、使用する予定のレンダー アイテム全体を事前に作成しておくことを検討する必要があります。
ビューポート 2.0 レンダラは、マテリアルおよびバウンディング ボックスのレンダー アイテムを保持します。
マテリアル レンダー アイテムに使用されるシェーダをオーバーライドすることは可能ですが、必須ではありません。これらのレンダー アイテムを無効にして、カスタム レンダー アイテムに置き換えることもできます。
シェーダの割り当てがまったくないオブジェクトの処理は、プラグインに委ねられることに注意してください。ビューポート 1.0 では、マテリアル インタフェースが既定のマテリアルを返します。ビューポート 2.0 では、プラグインでないオブジェクトのフォールバックとしてワイヤフレームが表示されます。既定値のワイヤフレーム レンダー アイテムを提供できないため、これ(または、フォールバックとして適切なもの)をプラグインによって明示的に提供する必要があります。
マテリアルとバウンディング ボックスのレンダー アイテムのみが提供される場合、追加の「カスタム」レンダー アイテムがいつ必要になるのかについての疑問が発生します。 これは、書かれているプラグインの種類に大きく依存しますが、1 つの共通する状況は非マテリアル レンダー アイテムのレンダリング、もう1つは既存のマテリアルまたはバウンディング ボックスの描画の上書きです。
一般的に、カスタム シェイプの場合は、ワイヤフレーム表示モードの描画のための最小限のサポートの実装が必要です。プラグインおよび描画する必要がある追加の UI 要素のタイプによって、追加されるものが異なります。
経験上、レンダリングの方法とタイミングが変わることで、新たにレンダー アイテム インスタンスが生成されます。 MRenderItem のスキャンは可能なバリエーションを示します。
描画モードのフィルタリングによって、描画フェーズに進む過程でアイテムがどのように除去されるかを示す基本的なパイプライン。 通常これは、アイテムがシェーディングされているかいないかに基づいたフィルタよりも優先されます。
アクティブ カメラに向かってレンダー アイテムを移動させる深度の優先順位設定の違いとその効果を論理的に示す図。 ストックの優先順位に代わり、「カスタム」の優先順位を使用することができます。 矢印は、カメラ(ビューア)の方向を示します。
プラグイン オブジェクトとのインタラクション中に使用する可能性のあるすべてのレンダー アイテムについて事前に計画を立てることを推奨します。 このアイテムの作業用セットは、シェーダ、テクスチャおよびジオメトリ、および可能な再使用の量など、必要な依存関係のあるリソースを判断するのに役立ちます。
一般に、レンダー アイテム セットは固定されていますが、プラグインの存続期間中にパラメータが変更されたり、各種のアイテムについて有効化と無効化が切り替わることがあります。
バリエーションを作成し、一度に有効にするバリエーションの数を制限していれば、レンダー アイテムの数が多くてもパフォーマンスには影響しません。 同じバリエーションが大量に必要な場合は、プラグインを作成するときに MPxGeometryOverride ではなく MPxSubSceneOverride を使用することを検討してください。
UI 描画の場合、上書きコストを回避するためにオーバーラップする要素の数を最小限に抑えることをお勧めします。 この問題を回避することができない場合、同時に有効にできる要素の数を決定することが最良の方法です。 これによって、深度の優先度が異なるレンダー アイテムのバリアントがいくつ必要になるかをコントロールすることができます。 たとえば、休止状態のライン コンポーネント上にアクティブなライン コンポーネントを描画する場合、ワイヤフレーム上には 3 つのレンダー アイテムが必要ですが、これらのアイテムは深度の優先順位を除いてまったく同じ場合もあります。
DAG オブジェクトのインスタンスごとにレンダー アイテムが必要となる場合は、インスタンスごとに異なるレンダー アイテムを作成できるということを覚えておくと便利です。 アイテムとインスタンス間の明示的な関連を保持しておくかどうかは、プラグイン作成者の判断によります。
レンダー アイテムのシェーダを選択するオプションにはさまざまな複雑さがあり、その用途も異なります。 選択したオプションに関係なく、ジオメトリの処理からシェーダを分離することが最善です。
最も単純なオプションは MShaderManager によって提供されるストック シェーダを使用することです。 これらは、ポイント、ラインおよび三角形の UI 描画に使用できるシェーダ、およびいくつかのストック マテリアル シェーダの既定の構成を供給します。 ストック シェーダのインスタンスは、プリミティブ タイプに固有です。たとえば、破線シェーダは三角形をレンダーするには不適切です。
また、カスタムのエフェクト ファイル シェーダを使用してさらにコントロールの精度を高めることもできますが、それにはすべての描画 API (DirectX11 や OpenGL など)に対する実装が必要です。 カスタム シェーダを使用する 1 つの理由は、大量のスタティックなレンダー アイテム バリアントのセットを使用するのではなく、より複雑なパラメータのセットを使用してダイナミックに更新できるようにすることです。
フラグメントに基づいたシェーダは、Maya のシェーディング ネットワークとの統合に最も適したもので、UI 描画には推奨されません。 組み込みのフラグメントの使用は、完全なシェーディングとライティングのサポートを得るための簡単な方法です。
最高度の柔軟性を得るには、シェーダをジオメトリ オーバーライドの一部として制御するのではなく、個別の MPxShaderOverride を使用することを推奨します。つまり、ジオメトリ オーバーライドはジオメトリ ハンドラとなり、シェーダ オーバーライドはマテリアル ハンドラとなります。
各シェーダには、パラメータのセットおよびジオメトリ要件が関連付けられています。 シェーダのインスタンスにはそれぞれ異なるシェーダ パラメータと要件があり、それにより、各シェーダ インスタンスのレンダー アイテムの特徴が決まります。
更新の頻度にもよりますが、パラメータの更新には MShaderInstance へのコールバックをアタッチした方が簡単な場合があります。 例えば、これによって、線の厚さパラメータ値が異なる 2 つのシェーダ インスタンス(つまりレンダー アイテム)を個別に作成することなくコールバック中にライン シェーダの厚さパラメータを変更することができます。
異なるストリームが同じジオメトリ要件のセットにバインドされる場合、ジオメトリ バインディングはダイナミックに行なわれるので、異なるシェーダ インスタンスは必要ありません。
既定では、プラグインは、関連する DAG オブジェクトの表示状態が変更したときにその UI レンダー アイテムを更新するために呼び出されます。 これは、次のような状況で発生します。
選択状態の変更は、一般にレンダー アイテムのカラーの変更を意味します。 これには 2 つのアプローチが考えられます。つまり、各選択状態のために複数のレンダー アイテムを作成するか、あるいは十分なシェーダ パラメータを備えた単一のレンダー アイテムを使用することができます。 ジオメトリが一般に共有される場合、複数のアイテムを持つことによる自明のコストは小さくなります。 描画モードが異なる場合は、異なるレンダー アイテムが必要です。 たとえば、休止状態とアクティブのワイヤフレームでは異なるアイテムが使用されます。前者はワイヤフレーム モードでのみ描画されますが、後者はすべての描画モードで描画されます。
カラーの実際のコントロールは、一般に MGeometryUtilities::wireframeColor() などのユーティリティによって扱うことができ、現在のオブジェクトの状態を考慮して、正確なカラーが返されます。
オブジェクトの可視性については、マテリアル レンダー アイテムは UI レンダー アイテムと同様に自動的に扱われます。 ただし、テンプレートの状態変更は特定のレンダー アイテムに関しては可視性の変更と考えることができます。 たとえば、コンポーネントのレンダー アイテムは Maya の内部の振る舞いと一致するように手動で無効にする必要があります。 MGeometryUtilities::displayStatus() は状態の確認に役立つユーティリティです。
描画オーバーライド(アトリビュート エディタ(Attribute Editor) 描画オーバーライド(Draw Overrides)タブに公開)の場合は、カスタム カラー オーバーライドとともにテンプレート コントロールを扱う必要があります。 上記と同じユーティリティを使用できます。
ディスプレイ レイヤは、テンプレート化およびカラー オーバーライドのために更新を呼び出すことができます。
Maya によってコントロールされない追加の項目には、それぞれ内部プラグイン ロジックと対応する更新ロジックがあります。 たとえば、フェース センターの表示を追加することを、カスタム レンダー アイテムの表示を駆動してこれらのセンターを表示するノード上のアトリビュートにすることができます。
既定では、レンダリングの表示モードが変更されると、オーバーライドは呼び出されません。 これは、すべての可能な表示モードのすべてのレンダー アイテムを考慮しなければならないということであり、重要な意味があります。 推奨されるアプローチは、適切なパラメータを使用してすべてのレンダー アイテムを作成し、表示モードに関係のない更新は、必要に応じて「更新」時に扱うというものです。
ジオメトリ オーバーライドとサブシーン オーバーライドの重要な相違点は、サブシーン オーバーライドは、フレーム コンテキストが提供される更新呼び出しを常時受け取るということです。 この場合、レンダー アイテムはオンデマンドで作成または修正することができます。
Maya で発生する一般的なイベントの場合、どのイベントをモニタすべきか、イベントに対してカスタムのレンダー アイテムの更新が必要かどうか、を決めるのはプラグインの責任です。 たとえば、ビュー依存のレンダー アイテムは自分自身のカメラ モニタ(MUIMessageなどによる)を実行する必要があります。
カスタムのレンダー アイテムには名前が付いているため、管理する名前付きレンダー アイテムのセットがあります。 また、セマンティックは同じで名前が異なるジオメトリ ストリームの要件が存在する可能性もあります。
たとえば、マテリアルのレンダー アイテムの描画と、面法線を描画するレンダー アイテムが必要となる場合には、位置の 2 つのストリーム(セマンティック)が必要となる場合があります。 前者を「My shaded item」、後者を「My face center item」のように命名することができます。 後者は、「フェース センター」のカスタムのストリーム名を使用して MRenderItem::setShader() を呼び出すことができました。
さらに、ストリームとレンダー アイテムの間には明示的な関連性が存在しないため、特定のカスタムのレンダー アイテムで使用する必要がある場合には、ストリームに名前をつけると役に立つ場合があります。 ただし、ストリームごとに名前を付けることによって、追加のジオメトリ データが発生し、インデックスの割り当ても必要になるため、一概にメリットがあるとはいえません。 また、ジオメトリの更新では、ストリームの名前付けはレンダー アイテム単位で行われるという事実を考慮する必要があります。 すなわち、名前は 1 つのアイテムのすべてのストリームに適用されます。 使用例を「4.4.5.5 基本コンポーネントの処理」に示します。
上の図は、左側の 3 つのレンダー アイテムを示します。 一番上のアイテムはフェース センターの描画に使用されます。 これは位置のみを必要とし、「フェース センター」のカスタム名を持っています。 次はアクティブな頂点を描画するためのアイテムで、位置を必要とし、「アクティブな頂点」のカスタム ストリーム名を持っています。 最後はマテリアル レンダー アイテムで位置と法線を必要とします。 カスタム名はありません。 オーバーライドがジオメトリを供給しなければならない要件が累積した最終的な一式が戻ってきたときに、必要なデータのストリーム 4 つ(位置ストリームが 3 つで法線ストリームが 1 つ)に関する説明(MVertexBufferDescriptor)があります。位置ストリームは、マテリアルとアクティブな頂点の表示に共通のものを使用することができます。
データがいつ必要になるかについての想定はされないため、すべての要件が常に満たされるようにする必要があります。 適切なデータが提供されない場合、レンダラは、既定のデータを提供しようとする場合があります。しかし適切なデータを提供できるという保証はありません。 たとえば、ビューポートの構成において、1 つのパネルがシェーディング モードでもう 1 つのパネルがワイヤオン シェーディング モードを有効にしている場合、1 つのビューポート パネルは、シェーディング レンダー アイテムに加えてワイヤフレーム レンダー アイテムを必要とします。 シェーディングされたレンダー アイテムでは、接線が必要になる場合があります。
コンポーネントが変更された場合、オーバーライドは DG 評価時にプラグイン オブジェクトから適切なコンポーネント情報を抽出する必要があります。 たとえば、コンポーネントのインデックス処理をキャッシュに入れることができます。 (MPxGeometryOverride の場合、これは updatedDG() 中に行われます)。 このインデックス処理は、サポート対象コンポーネントに関連付けられたレンダー アイテムに対するプリミティブ インデックス処理を提供するために使用することができます。 たとえば、頂点のような単一のインデックス付きコンポーネントの場合、頂点の識別子をキャッシュに入れることができます。
各コンポーネント タイプでは、必要な表示バリエーションに応じて、オーバーライドに 1 つまたは複数のレンダー アイテムが作成される場合があります(MPxGeometryOverride の場合、これは updateRenderItems() 中に行われます)。 前述の頂点コンポーネントの例では、未選択の頂点を表示するための 1 つのアイテムと選択済みの頂点を表示するための 1 つのアイテムがあります。 それらのアイテムは、たとえばカラーやサイズ、深度の優先順位が異なります(それらがオーバーラップする場合)。
各レンダー アイテムには、ポイントの描画に適切なストック シェーダ インスタンスが関連付けられている場合があります。 未選択頂点のレンダー アイテムはワイヤーフレーム モードでのみ適用され、その場合には描画モードを関連付ける必要があります。 選択済み頂点のレンダー アイテムは、シェーディング、テクスチャ、ワイヤフレーム モードで描画するように設定されます。このアイテムは、これらのモードすべてで表示されるためです。 既定では、アイテムは、頂点表示が有効の場合、あるいはオブジェクトの表示状態が「ハイライト」モードの場合に有効となります。
ジオメトリの更新時(MPxGeometryOverride の場合、これは populateGeometry() 中に行われます)に、シェーダ ジオメトリ要件に基づいて適切なストリーム データが要求されます。以前に評価されたコンポーネント インデックス処理に応じて、適切なプリミティブ インデックス処理を作成/更新する必要があります。
サブシーン オーバーライドの場合、すべてのトランザクションは update() メソッド内で処理されます。
名前付きのストリームを使用する例として、1 つの位置ストリームを未選択の描画に、もう 1 つの位置ストリームを選択された頂点び描画に使用することができます。 プラスの側面としては、選択される頂点の数が少ないため、インデックス処理とデータ転送の負荷が小さくなります。 マイナスの側面としては、追加のストリームを割り当てる必要があるため、メモリのコストが増大します。 同じストリームを再利用することは、同じメモリを再利用するということであり、複雑なインデックス処理の計算や過度の描画が行われる可能性があります。
たとえば、プラグインは以下に対するカスタムのレンダー アイテムを作成することができます。
緑色のボックスは、プラグインが作成し管理する領域を表します。 白いボックスはレンダラによって提供されます。
以下に、上記のアイテムのパラメータの例と、それぞれのアイテムに適した更新の頻度を示します。
三日月の形の「コンテナ」は、ジオメトリとサブシーンのオーバーライド レンダー アイテムの両方が、どれくらい論理的にレンダー アイテムのセットに収集されるかを示します。 主な違いは、サブシーンのオーバーライド コンテナ クラスは明示的に API に公開されるということです。
以下に、ユーザ ワークフローの例、およびプラグインがどのようにそれらのレンダー アイテムを処理することができたかを示します。
上記の 5 つのアクションを上から下に、そして左から右に図で表しています。 どんな場合でも、すべてレンダー項目の保持は、基本的な有効と無効の発生、およびカラーなどの起こりうるパラメータの変化によって行われます。 有効なアイテムは緑色で表示され、それ以外のすべてのレンダー アイテムは無効になります。
ジオメトリ オーバーライドの場合、処理の大多数は updateRenderItems() 内で行われ、サブシーンのオーバーライドは update() 内で行われます。 SDK プラグイン apiMeshShape には、上記のようなワークフロー、および多くの「標準の」ワークフローをサポートするロジックを含むコードの例が含まれています。カスタム マテリアルのレンダリングが必要な場合、統合のレベルは使用されるインタフェースに依存します。 以下の表は、それぞれのインタフェースに関する主なトレードオフをまとめたものです。 柔軟性を高めるには、プラグイン作成者はより多くの作業を行う必要があります。 ある程度は、より単純なシェーダをジオメトリ ハンドラ/オーバーライド内部で維持することができます。
フラグメント(Fragment)、エフェクト(Effects) およびストック(Stock) は、シェーダ マネージャを介して利用可能なオプションです。そのため、サポートされるオプションは内部レンダラによって決定されます。シェーダのオーバーライド(Shader Override) は MPxShaderOverride です。
フラグメント シェーダ | エフェクト シェーダ | ストック シェーダ | シェーダ オーバーライド | |
柔軟性: 複雑さの比 | 高: 高 | 中: 低 | 低: 低 | 高: 高 |
使用例 | 一般に、既存のフラグメントのセットを強化するために使用されます。 「ストック」シェーダとして使用できますが、より複雑化することで適切なシェーディング ネットワークをセットアップすることもできます。 すべての内部セマンティック バインディングがサポートされます。 |
既定のセマンティック バインディングを使用できる自己完結型のエフェクト。 | 単純な組み込みのエフェクトで「十分に機能」。 以前の簡単に記述できる機能限定のコードに代わって複雑な UI シェーダを記述する作業を避けたい場合に役に立ちます。 |
内部レンダラが提供するサポートよりも複雑なシェーディングのサポートが必要です。たとえばテッセレーション シェーダなどです。 |
レンダー アイテムの「タイプ」 | カスタム。 | カスタム。 | カスタム。 | 非カスタム。 |
シェーディング グラフのサポート | 個々のフラグメントを使用する場合は、なし。 フラグメント シェーダが Maya シェーダ ツリーの一部としてノード内で使用される場合は、完全に統合されます。 フラグメント シェーダを使用して MShaderInstance を作成する場合、明示的なサポートはありません。 |
なし。 | なし。 | プラグインにより決定。 |
ライティングのサポート | 統合。 | 自動バインドなし。 | 設計では無視されます。 | プラグインは描画コンテキストへのアクセスを介してバインドします。 |
ポスト エフェクトのサポート | 統合。 | 統合されていません。 | 設計では無視されます。 | プラグインは、エフェクトによって要求される各種のパスをサポートする技術を提供します。 |
描画 API サポート | カスタムの場合は、各描画 API ごとの実装が必要です。そうでなければ API 非依存になります。 | プラグイン作成者は、サポートする API のバージョンを作成します。 | 組み込み。 | プラグイン作成者は、サポートする API のバージョンを作成します。 |
シェーダ ステージをサポート | 頂点、ピクセル。 | 頂点、ピクセル、ジオメトリ。 | 公開されていません。 | プラグインによって決定。 |
ジオメトリ ハンドラ(オーバーライド)からの分離 | ジオメトリ ハンドラによって作成されたレンダー アイテム上のシェーダ インスタンスのために使用することができます。 | ジオメトリ ハンドラによって作成されたレンダー アイテム上のシェーダ インスタンスのために使用することができます。 | ジオメトリ ハンドラによって作成されたレンダー アイテム上のシェーダ インスタンスのために使用することができます。 | ジオメトリの処理から独立しています。 |
マテリアル アイテムを扱う場合、一般に、「シェーディング」または、「シェーディングとテクスチャ」描画モードがオーバーライドにパスされるレンダー アイテムがあります。 DAG オブジェクトに割り当てられたマテリアルの数に応じて、このようなパスされるアイテムのセットの数は 0 またはそれ以上になります。
この例では、DAG オブジェクトは DAG オブジェクト上の異なるコンポーネントに 2 つのシェーダを割り当てます。 4 つの「マテリアル」レンダー アイテムを持つことができます。1 つは「シェーディング」描画モードで描画される各コンポーネント シェーダ、1 つは「シェーディングとテクスチャ」モードで描画される各コンポーネント シェーダに対するものです。
これらのレンダー アイテムのパラメータはそのまま使用することも、修正したり、無効にすることもできます。 無効にした場合、プラグインは代わりのパラメータを提供しなければなりません。 代わりのパラメータが提供されない場合、オブジェクトはシェーディングまたはテクスチャ モードのときに「消えた」ように見えます。 代わりのパラメータのタイプに応じて、統合のレベルは異なったものになります。
あるレンダー アイテムのシェーダ処理の複雑さが MPxShaderOverride が必要となるレベルに達すると、ジオメトリ ハンドラの複雑さが低減され、これらのレンダー アイテムのジオメトリ要件のみを満たすようになります。
たとえば、プラグインは完全に統合されたいくつかのプリセット シェーディング構成を持つビルトインの Blinn シェーダのみを必要とする場合があります。 この場合はストック フラグメント シェーダを使用することができます。 別の例では、ヘア シェーダのためのテッセレーションが必要になる場合があります。 この場合の最善の対応は、ジオメトリ ハンドラの内部からこれを制御せず、代りにカスタムの MPxShaderOverride の「ヘア シェーダ ノード」を作成し、レンダー アイテムをカスタムの「ヘア ジオメトリ ノード」オーバーライドに「フィードする」ことです。
レンダラが提供する(マテリアル)レンダー アイテムは、カラーなしで表示されます。 内部シェーダとプラグイン シェーダの組み合わせによってこれらのアイテムを派生させる場合もあります。 ノードには、カスタムのフラグメント シェーダを提供するもの、あるいはシェーダ オーバーライドが関連付けられるものがあります。 ジオメトリ ハンドラ(オーバーライド)は、これらを非カスタムのレンダー アイテムとして受け取ります。
カスタムのレンダー アイテム(緑色で表示)は、フラグメント、ストックあるいはエフェクト ファイル インタフェースを使用して、シェーダ マネージャを介して作成されるシェーダ インスタンスを用いてインスタンス化することができます。
MUIDrawManager クラスは、一般にはオブジェクトの一部としての関連性をもたない追加の UI 描画をキューに入れるための簡易インタフェースを提供します。 キューに入れることのできる「描画可能項目」は、レンダー アイテムとほぼ同じであると考えることができます。
マネージャを使用することの直接的な意味は、「描画可能項目」は永続的ではないので、このインタフェースを介してキューに入れられる描画可能項目の数は比較的少なくすることができるということです より多くのアイテムが必要な場合、またはデータ コンテンツが大きい場合、mesh() 呼び出しなどのインタフェースを使用することができます。 そうでなければ、カスタムのレンダー アイテムが推奨されます。
たとえば、プラグイン オブジェクト上に大量の頂点を描画する場合は、描画マネージャ内で個々の点を描画するよりも、カスタムのレンダー アイテムを使用することが推奨されます。 ただし、オブジェクト上で 3D または 2D のラベルを描画する場合は、描画マネージャが推奨されます。
検討が必要なもう 1 つの側面は、マネージャを使用して描画された UI は、パイプライン全体の中の固定された場所に描画され、より厳密な定義済み描画プロパティのセットを持つ場合があるということです。
既定では、UI 描画(ライン、ポイント)に使用されるレンダー アイテムは、スクリーンスペース アンビエント オクルージョン、モーション ブラーおよび被写界深度のようなシーン エフェクトから除外されます。 また一般に、それらはシャドウの投影や受像を行いません。 内部マテリアル シェーダ インスタンスを使用するレンダー アイテムは、これらのエフェクトの要素となります。
エフェクトの描画は、いくつかの描画コンテキスト内で実行されます。
ジオメトリ オーバーライドにはコンテキスト情報は渡されず、その動作はほとんどの場合コンテキストに依存しません(シェーダ コールバックは例外)。 サブシーンのオーバーライドにはコンテキストが提供されますが、これはフレーム コンテキストであり、パス コンテキストへのアクセスを提供しません。 したがって、どのアイテムも、呼び出し元のパスに関係なく動作します。
ビューポート 1.0 | ビューポート 2.0 (Viewport 2.0) | |
カスタムのレンダリング可能項目の作成 | MDrawInfo::getPrototype() | MRenderItem::Create() |
カスタムのレンダリング可能項目の削除 | 描画要求は一時的なもので、更新のたびに内部的に解放されます。 | MRenderItem::Destroy() |
レンダリング可能項目を待ち行列に入れる | MPxSurfaceShapeUI:: getDrawRequests () | MPxGeometryOverride::updatedDG() および MPxGeometryOverride::updateRenderItems() MPxSubSceneOverride:: Update () |
レンダリング | MPxSurfaceShapeUI:: draw () | 適用できません。レンダリングはレンダラによって行われます。 |
マテリアルの処理 | テンプレート修正関数のマテリアルが提供されます。任意にオーバーライドできます。 | MShaderInstance に基づいています。パラメータは更新時に修正できます。レンダー アイテムへのシェーダ バインド(再バインド)が可能です。 より複雑または分離されたマテリアルの扱いは、MPxShaderOverride を介して実行します。 |
表示モードの処理 | 表示モードは入力として提供され、任意に無視できます。 | 描画モードは、レンダー アイテムの固有のパートです。内部ロジックは、表示モードのメンバーシップに基づいてアイテムを削減します。 |
ジオメトリ要件のインタフェース | 概念がありません。 | MPxGeometryOverride:: populateGeometry () MPxSubSceneOverride:: setGeometryForRenderItem () |
ジオメトリ要件の満足 | 概念がありません。 | 別のレンダー アイテムに対する明示的なストリームの命名が可能です。結果として追加のバッファとインデックスが処理されます。 |
バウンディング ボックスの描画 | 内部でコントロールします。 | 内部でコントロールします。 |
ゴースト化のコントロール | 複数の描画呼び出しは、単一の描画要求のセットに対して実行されます。 | プラグインでコントロールします。すべてのゴーストに対する呼び出しの単一セット。 |
シャドウの投影/受像 | オブジェクトの「投影」および「受像」アトリビュートがあれば、それらを使用して制御します。そうでなければ、制御は行われません。 | 必要に応じてカスタム レンダー アイテムごとにコントロールします。 |
表示状態の照会 | MDrawInfo の一部として渡された表示状態の情報。 | 表示状態は MDagPath、MGeometryUtilities から照会することができます。 |
コンポーネントの管理 | 要求の描画は可能です。プラグインは管理を実行します。 | コンポーネント情報は適切なレンダー アイテムを使用して描画するために渡すことができます。 ビューポート 1.0 のインタフェースはコンポーネント管理を実行します。 |
可視性の処理 | 描画要求または描画を待ち行列に入れる場合の要求を削減します。 | プラグインは、必要に応じてレンダー アイテムを有効/無効にするか、内部描画モード フィルタを使用するために描画モードを設定します。 |
UV のレンダリング | MPxSurfaceShapeUI:: drawUV () | 概念がありません。ビューポート 1.0 インタフェースを使用します。 |
セレクション | MPxSurfaceShapeUI: : select () | 概念がありません。ビューポート 1.0 インタフェースを使用します。 |
選択状態の照会 | MDrawInfo クラス内で見つかった情報は、選択したものについて描画が発生しているかどうかを示します。 | 選択はビューポート 2.0 の一部ではないため、適用できません。 |
ユーザ インタラクションのフィードバック | いくつかの情報は MDrawInfo を介して利用可能です。 | プラグインは、明示的に対象のユーザ イベントをモニタします。 |
apiMeshShape Developer Kit サンプルは、UI の処理およびプロキシ シェーダの処理に関連する多くのワークフローを考慮に入れます。
ワイヤフレーム モードにおける apiMeshShape のシーンのサンプル。
シェーディング モードにおける apiMeshShape のシーンのサンプル。
上のスナップショットは、使用されている多くの異なるカスタムのレンダー アイテムを示します。 プレーンと IK チェーンを除くすべてのオブジェクトは、同じプラグインを使用して描画されます。 以下が含まれます。
次のコードは、MPxGeometryOverride::updateRenderItems() 内部からの「アクティブなワイヤフレーム」のレンダー アイテムの処理を示します。 コード ロジックは、MPxSubSceneOverride とともに使用した場合は類似したものになります。例外は、レンダー アイテムが MRenderItemList ではなくコンテナ(MPxSubSceneContainer)に属するということです。
以下に、シェーダ上にカラー パラメータを設定する方法の例を示します。
// Utility to set the color on a shader instance. void setSolidColor(MHWRender::MShaderInstance* shaderInstance, const float *value) { if (!shaderInstance) return; const MString colorParameterName = "solidColor"; shaderInstance->setParameter(colorParameterName, value); }
updateRenderItems() の実行中に、「アクティブ」なワイヤフレーム アイテムがまだ存在しない場合は、新しく作成されます。 新しいワイヤフレームが作成されると、描画モードは「すべての」モードに設定され、アイテムは、上のシェーディングされたレンダー アイテムを描画するように設定されます。
// ************************** Update during updateRenderItems() ****************** … // Unique name for active wireframe MString fSelectedWireframeItemName = “selectedWireframeName”; // Create the item once. Use enable/disable toggle to control when it should // be drawn (below) MHWRender::MRenderItem* selectItem = NULL; int index = list.indexOf( // list = MRenderItemList passed as an input argument fSelectedWireframeItemName, MHWRender::MGeometry::kLines, // Type of primitive is lines MHWRender::MGeometry::kAll); // Draw in all display modes if (index < 0) { static const bool raiseAboveShaded = true; selectItem = MHWRender::MRenderItem::Create( fSelectedWireframeItemName, MHWRender::MGeometry::kLines, MHWRender::MGeometry::kAll, raiseAboveShaded); // This is the same as setting the argument raiseAboveShaded = true, // since it sets the priority value to be the same. This line is just // an example of another way to do the same thing after creation of // the render item. selectItem->depthPriority( MHWRender::MRenderItem::sActiveWireDepthPriority); list.append(selectItem); // Choose an line shader to match primitive type MHWRender::MShaderInstance* shader = shaderMgr->getStockShader( MHWRender::MShaderManager::k3dSolidShader ); if (shader) { // Assign shader selectItem->setShader(shader); // Once assigned, no need to hold on to shader instance shaderMgr->releaseShader(shader); } } else { selectItem = list.itemAt(index); }
// Perform updates on the render item parameters. In this case // update the shader instance. // MHWRender::MShaderInstance* shader = NULL; if (selectItem) { shader = selectItem->getShader(); } // Check the current display status of the object and color to use for this // instance of the object. MHWRender::DisplayStatus displayStatus = MHWRender::MGeometryUtilities::displayStatus(path); MColor wireColor = MHWRender::MGeometryUtilities::wireframeColor(path); // It is not necessary to use the colors provided and instead a custom color could be // used if (fUseCustomColors) is set. bool fUseCustomColors = false; switch (displayStatus) { case MHWRender::kLead: selectItem->enable(true); if (shader) { static const float theColor[] = { 0.0f, 0.8f, 0.0f, 1.0f }; setSolidColor( shader, !fUseCustomColors ? &(wireColor.r) : theColor ); } break; case MHWRender::kActive: if (shader) { static const float theColor[] = { 1.0f, 1.0f, 1.0f, 1.0f }; setSolidColor( shader, !fUseCustomColors ? &(wireColor.r) : theColor ); } selectItem->enable(true); // Enable if the object is active break; case MHWRender::kHilite: case MHWRender::kActiveComponent: if (shader) { static const float theColor[] = { 0.0f, 0.5f, 0.7f, 1.0f }; setSolidColor( shader, !fUseCustomColors ? &(wireColor.r) : theColor ); } selectItem->enable(true); // Enable if the object is hilite, or // its components are active. break; default: // Otherwise make sure to disable it. The item is still present, it will just // not be sent down the rendering pipeline to draw. selectItem->enable(false); break; };
以下に、MPxGeometryOverride::updateRenderItems() の内部から「アクティブな頂点」レンダー アイテムを処理するためのサンプル コードを示します。 表示状態をチェックして、コンポーネントのレンダー アイテムを無効にするかどうかを判断するための個別のユーティリティ メソッドがあります。
テストはまた、アクティブな頂点があるかどかを考慮します。これは、DG 更新時(updatedDG())に決定されます。
このコード パスは、名前付きストリームを使用可能にするように記述されます。 populateGeometry() メソッド内部では、これらの名前付きストリームをチェックして、位置の異なるセットを使用してアクティブな頂点を描画することができます。
以下のコードは、DG 更新時に実行されます。 これは、オブジェクトからコンポーネント リストを取得し、要素 ID を整数配列の形式でキャッシュに入れます。
/***** Call in MPxGeometryOverride::updatedDG() to perform any DG operations ****/ void updateDG() { fActiveVertices.clear(); // fActiveVertices is an MIntArray MObjectArray clist = // Get the active vertex components – plug-in specific ; if (clist.length()) { MFnSingleIndexedComponent fnComponent( clist[0] ); if (fnComponent.elementCount()) { // Cache the vertex identifiers for later usage. fnComponent.getElements( fActiveVertices ); } } }
/* Test to see if active components should be enabled. Based on active vertices + non-template state */ bool enableActiveComponentDisplay(const MDagPath &path) const { bool enable = true; // If no active components then disable the active // component render item if (fActiveVertices.length() == 0) { enable = false; } else { // If there are components then we need to check // either the display status of the object, or // in the case of a templated object make sure // to hide components to be consistent with how // internal objects behave // MHWRender::DisplayStatus displayStatus = MHWRender::MGeometryUtilities::displayStatus(path); if (displayStatus == MHWRender::kTemplate || displayStatus == MHWRender::kActiveTemplate) { enable = false; } else { // Do an explicit path test for templated // since display status does not indicate this. if (path.isTemplated()) enable = false; } } return enable; }
updateRenderItems() の実行中に、適切なアイテムが必要に応じて作成され、「すべて」のモードで描画されます。 深度の優先順位は、休止中の頂点および任意のワイヤフレーム アイテムによって非表示にならないように設定されます。 アイテムはコンポーネントを表示するかどうかに基づいて有効になります。
… // Unique name identifier for the render item MString fActiveVertexItemName = “activeVertexItemName”; MHWRender::MRenderItem* activeItem = NULL; int index = list.indexOf( fActiveVertexItemName, MHWRender::MGeometry::kPoints,// Primitive type is points. MHWRender::MGeometry::kAll); // Render item should display in all display modes. if (index < 0) { activeItem = MHWRender::MRenderItem::Create( fActiveVertexItemName, MHWRender::MGeometry::kPoints, MHWRender::MGeometry::kAll, false); // Set depth priority to be active point. This should offset it // to be visible above items with "dormant point" priority. activeItem->depthPriority( MHWRender::MRenderItem::sActivePointDepthPriority ); list.append(activeItem); MHWRender::MShaderInstance* shader = shaderMgr->getStockShader( MHWRender::MShaderManager::k3dFatPointShader ); if (shader) { // Set the point size parameter. Make it slightly larger for active // vertices static const float pointSize = 5.0f; setSolidPointSize( shader, pointSize ); // Assign shader. Use a named stream if we want to supply a different // set of "shared" vertices for drawing active vertices bool fDrawSharedActiveVertices = true; MString fActiveVertexStreamName = “activeVertexStreamName”; if (fDrawSharedActiveVertices) { activeItem->setShader(shader, &fActiveVertexStreamName ); } else { activeItem->setShader(shader, NULL); } // once assigned, no need to hold on to shader instance shaderMgr->releaseShader(shader); } } else { activeItem = list.itemAt(index); } // Update the color and enable / disable the render item as appropriate. // Just using a fixed color and not checking display status. bool enableActiveDisplay = enableActiveComponentDisplay( <dagpath> ); if (activeItem) { MHWRender::MShaderInstance* shader = activeItem->getShader(); if (shader) { // Set active color static const float theColor[] = { 1.0f, 1.0f, 0.0f, 1.0f }; setSolidColor( shader, theColor); // See code for active // wireframe for this code utility. } activeItem->enable( enableActiveDisplay ); }
以下に、populateGeometry() 内の名前付きカスタム ストリームを処理するためのコード ロジックの一部を示します。 コードの主要な部分は、頂点バッファ記述子名をチェックして、上の updateRenderItems() の実行中に MRenderItem::setShader() を呼び出したときに設定された名前と一致するかを確認することです。 次にプラグインは自由にデータを挿入し、変数 fActiveVertexItemName に格納された値に一致する名前をもつレンダー アイテムに対する適切なインデックス構造を作成します。
const MHWRender::MVertexBufferDescriptorList& descList = requirements.vertexRequirements(); int numVertexReqs = descList.length(); MHWRender::MVertexBufferDescriptor desc; for (int reqNum=0; reqNum<numVertexReqs; reqNum++) { if (!descList.getDescriptor(reqNum, desc)) { continue; } // Fill in vertex data for drawing active vertex components // if (fDrawSharedActiveVertices && (desc.name() == fActiveVertexStreamName)) switch (desc.semantic()) { case MHWRender::MGeometry::kPosition: { if (!activeVertexPositionBuffer) { activeVertexPositionBuffer = data.createVertexBuffer(desc); if (activeVertexPositionBuffer) { // Allocate a position buffer to fit the # of active vertices unsigned int activeVertexCount = fActiveVertices.length() activeVertexPositions = (float*)activeVertexPositionBuffer>acquire( activeVertexCount, true /*writeOnly*/ } } } break; default: break; } }