MRenderOverride を実装する

MRenderOverride を使用してプラグインを作成し、レンダリング パイプラインを置き換えることができます。このプラグインでは、パイプラインの標準操作(またはパス)が使用でき、また他のカスタム操作も追加できます。このためには、プラグインで、まず現在のパイプラインを表す操作セットを取得し、次に、操作の追加、挿入、削除により、これを修正する必要があります。

標準操作は、パスの動作を決めるさまざまな設定およびフィルタによってコントロールされます。これにより、基本的なビューポートのコントロールが可能になり、表示するオブジェクトのフィルタリング、使用する表示モード、マテリアル オーバーライド、ポスト プロセスなどが便利になります。

操作リストに設定することによって MRenderOverride のプラグインを作成する利点は、ターゲットの作成または管理をプラグインの実装に含める必要がない点です。これは、システムによって自動的に処理され、操作レベルまで押し下げられます。

MRenderOverride を使用する欠点は、パイプライン全体をオーバーライドする必要があり、パイプラインに対するいかなるカスタマイズも、まったく新しいレンダラとして使用する必要がある点です。MRenderOverride の詳細については、「レンダリング オーバーライド」を参照してください。

クラスとインタフェース

次のクラスおよびインタフェースを使って、上記の MRenderOverride を作成できます。

MRenderOperationList クラスは、MRenderOperation のコレクションの所有権を保持、取得します。このクラスには、リスト内の操作について、インデックス作成、追加、削除、置換を行うための、リストの標準メソッドがあり、リストから操作の所有権を取得するメソッドも含まれています。

MRenderer::getStandardViewportOperations() インタフェースを使うと、オーバーライドされていない描画に使用される標準ビューポート操作でリストを埋めることができます。

MRenderOverride の保護されたメンバーである、

MRenderOperationList mOperations

は、このオーバーライド用の操作リストです。

標準操作のリストを取得するには

MRenderOverride から派生するクラスで必要なことは、標準リストを取得する、独自の操作を追加する、またはこの両方を組み合わせることにより、リストに操作を設定することだけです。

//Get the standard list of operations
MHWRender::MRenderer::theRenderer()->getStandardViewportOperations(mOperations);

//Create a custom quad render operation 
PostQuadRender* swirlOp = new PostQuadRender( kSwirlPassName, "FilterSwirl", "" );
swirlOp->setEnabled(false); // swirl is disabled by default

//Insert swirlOp in the pipeline after the kStandardSceneName operation
mOperations.insertAfter(MHWRender::MRenderOperation::kStandardSceneName, swirlOp);

使いやすくするために、標準操作の名前がいくつか定義されています。これらの名前は、標準操作リストの操作を見つけるのに使用できます。

static const MString kStandardBackgroundName;  
static const MString kStandardSceneName;    
static const MString kStandardHUDName;
static const MString kStandardPresentName;

操作でターゲットを管理する

大きな操作リストに追加されたときに、操作がより自律的で自己記述的であるようにするために、ターゲットの管理は操作レベルで処理されます。

MRenderOperation から派生するクラスでは、次の実装を行う必要があります。

  1. 必要な入力の名前を宣言し、生成する出力ターゲットの名前を宣言します。
  2. 名前が付けられた入力に対する MRenderTargetDescription を提供します。
  3. 開始インデックスと、このクラスが書き込むターゲットの数を指定します。

MRenderOperation には、上記の最初の手順で使用できる、保護されたメンバー変数が 2 つあります。

入力と出力を宣言するには、操作で使用するターゲットの名前(つまり、セマンティック)を追加する必要があります。MRenderOperation クラスでは、一般的なターゲット タイプがいくつか定義されています。

static const MString kColorTargetName;  
static const MString kDepthTargetName;
static const MString kAuxiliaryTargetName;
static const MString kAuxiliaryTarget2Name;
static const MString kAuxiliaryTarget3Name;
static const MString kAuxiliaryTarget4Name;
static const MString kAuxiliaryDepthTargetName;
ヒント:ポスト エフェクトを書く場合、現在のレンダリング結果から読み取り、そして新しい結果を書き出すときに、補助ターゲットが必要になります。同じバッファを使って読み取りと書き込みを同時に行うことはできないため、前のパスで使用されるターゲットに似た新しいレンダー ターゲットを作成する必要があります。補助ターゲットのサイズおよびフォーマットは、標準カラー ターゲットと同じである必要があります。書き込まれた後、補助ターゲット入力は、他のポスト パスで読み取りまたは書き込みに使用される、新しい標準カラー ターゲットとして返されます。前の標準カラー ターゲットは、追加の補助ターゲットが必要な他のポスト エフェクトで再利用できるように、補助ターゲットとして返される必要があります。

既定では、すべての MRenderOperation は、標準のカラー ターゲットおよび深度ターゲットの名前を入力として使用するため、書き込みまたは読み取りに標準ターゲットを使用する、リスト内の他の操作に自動的に接続します。現在アクティブなターゲットに単に書き込む操作に必要なことはこれだけであり、これはベース クラスで実装されています。

たとえば、次のコードの断片では、2 つの既定の入力と、2 つの既定の出力を宣言しています。

mInputTargetNames.append(kColorTargetName);
mInputTargetNames.append(kDepthTargetName);
mOutputTargetNames.append(kColorTargetName);
mOutputTargetNames.append(kDepthTargetName);

複数のターゲットに対して読み取りまたは書き込みを行う MRenderOperation クラスでは、リストをクリアして独自の入力、出力を追加することにより、既定の入力および出力をオーバーライドできます。

mInputTargetNames.append(kAuxiliaryTargetName);
mInputTargetNames.append(kAuxiliaryDepthTargetName);
mInputTargetNames.append(“sceneTarget”);
mInputTargetNames.append(“sceneDepthTarget”);

mOutputTargetNames.append(kColorTargetName);
mOutputTargetNames.append(kDepthTargetName);

次に、カスタム パスにおいて、名前が付けられた入力ターゲットのディスクリプションを提供できます。次の例では、マルチサンプル アンチエイリアシングのプロパティおよびサイズが一致するように、補助ターゲットからディスクリプションをコピーしています。

bool PostQuadRender::getInputTargetDescription(const MString& name, 
MHWRender::MRenderTargetDescription& description) 
{ 
    if (name == “sceneTarget”)
    {
        MHWRender::MRenderTarget* outTarget = getInputTarget(kAuxiliaryTargetName);
        if (outTarget)
            outTarget->targetDescription(description);
        description.setName("_post_target_1");
        return true;
    }
    else if (name == “sceneDepthTarget”)   
    {
        MHWRender::MRenderTarget* outTarget = getInputTarget(kAuxiliaryDepthTargetName);
        if (outTarget)
            outTarget->targetDescription(description);
        description.setName("_post_target_depth");
        return true;
    }
    return false;
}

MRenderOverride プラグインでは、名前が一致するように操作を接続できます。

//Get MRenderOperationList of the standard viewport operations
MHWRender::MRenderer::theRenderer()->getStandardViewportOperations(mOperations);

//Get the index of the operation kStandardSceneName
int sceneOpID = mOperations.indexOf(MHWRender::MRenderOperation::kStandardSceneName);

//Set sceneOp to point to the kStandardSceneName operation in the MRenderOperationList
MRenderOperation* sceneOp = mOperations[sceneOpID];

//Rename the output target of the kStandardSceneName operation from kColorTargetName to sceneTarget
sceneOp->renameOutputTarget(MHWRender::MRenderOperation::kColorTargetName, “sceneTarget”);

//Create the new MRenderOperation swirlOp
PostQuadRender* swirlOp = new PostQuadRender( kSwirlPassName, "FilterSwirl", "" );

// Insert swirlOp after the operation named kStandardSceneName
// Because swirlOp has an input named sceneTarget, and you have renamed the output target
// of kStandardSceneName to sceneTarget, the two operations will share the same target.
// The target is constructed from the description provided by the swirl
// operation and is the target that the scene operation should render to.
mOperations.insertAfter(MHWRender::MRenderOperation::kStandardSceneName, swirlOp);

開始インデックスと、MRenderOperation が書き込むターゲット数を指定するには、次のようにします。

int PostQuadRender::writableTargets(unsigned int& count)
{
    count = 2;  
    return 0;
}