フルスクリーンクワッドでレンダーターゲットにピクセルパーフェクトレンダリング


9

一連の値をレンダーターゲットにレンダリングするときに問題が発生します。値が、希望する正確な範囲になることはありません。基本的に、フルスクリーンクワッドとピクセルシェーダーを使用してレンダーターゲットテクスチャにレンダリングし、テクスチャー座標をシェーダーでのいくつかの計算の基礎として使用するつもりです。左上隅の(0,0)から右下隅の(1,1)までのクワッド範囲のテクスチャ座標...問題は、補間後、これらの値がピクセルシェーダーに到達しないことです。 。

例: 4x4テクスチャにレンダリングし、この場合のシェーダーは、赤と緑のチャネルでテクスチャ座標(u、v)を出力するだけです。

return float4(texCoord.rg, 0, 1);

そこから取り出したいのは、左上のピクセルがRGB(0,0,0)であり、したがって黒であるテクスチャであり、右上のピクセルがRGB(255,0,0)であり、したがって明るい赤と左下のピクセルはRGB(0,255,0)-明るい緑です。

しかし、代わりに私はこれをここの右側に取得します:

(直線四角形レンダリング、補正なし)
四角形の直線レンダリング、補正は適用されません

左上のピクセルは黒ですが、他のコーナーでは比較的濃い赤と濃い緑しか表示されません。それらのRGB値は(191,0,0)と(0,191,0)です。私はそれがクワッドのサンプリング位置に関係していると強く思います:左上のピクセルはクワッドの左上隅を正しくサンプリングし、UV座標として(0,0)を取得しますが、他のコーナーのピクセルはクワッドの他のコーナー。左の画像でこれを示しました。四角形を表す青いボックスと、上部のサンプリング座標を表す白いドットです。

これで、Direct3D9で画面揃えのクワッドをレンダリングするときに座標に適用する必要があるハーフピクセルオフセットについて知っています。これからどのような結果が得られるか見てみましょう:

(DX9のハーフピクセルオフセットでレンダリングされたクワッド)
ハーフピクセルオフセットでレンダリングされたクワッド

赤と緑が明るくなりましたが、まだ正しくありません。赤または緑のカラーチャネルで取得できる最大値は223です。しかし今、私はもう純粋な黒すら持っていませんが、代わりにRGB(32,32,0)の暗い黄色がかった灰色です!

私が実際に必要とするのは、この種のレンダリングです。

(ターゲットレンダー、縮小されたクワッドサイズ)
正しい補間による純粋な黒、緑、赤

最初の図と比較して、クワッドの右と下の境界線を1ピクセル上および左に移動する必要があるようです。次に、右側の列と一番下の行のピクセルはすべて、クワッドの境界から正しくUV座標を取得します。

VertexPositionTexture[] quad = new VertexPositionTexture[]
{
    new VertexPositionTexture(new Vector3(-1.0f,  1.0f, 1f), new Vector2(0,0)),
    new VertexPositionTexture(new Vector3(1.0f - pixelSize.X,  1.0f, 1f), new Vector2(1,0)),
    new VertexPositionTexture(new Vector3(-1.0f, -1.0f + pixelSize.Y, 1f), new Vector2(0,1)),
    new VertexPositionTexture(new Vector3(1.0f - pixelSize.X, -1.0f + pixelSize.Y, 1f), new Vector2(1,1)),
};

しかし、これはうまくいかず、下と右のピクセルがまったくレンダリングされませんでした。これらのピクセルの中心はクワッドで覆われていないため、シェーダーで処理されないと思います。pixelSizeの計算を少しだけ変更して、クワッドを少し大きくすると、少なくとも4x4のテクスチャでは機能します。小さなテクスチャでは機能せず、大きなテクスチャでもuv値の均一な分布を微妙に歪めるのではないかと心配しています。

Vector2 pixelSize = new Vector2((2f / textureWidth) - 0.001f, (2f / textureHeight) - 0.001f);

(pixelSizeの計算を0.001fで変更しました。たとえば、1Dルックアップテーブルなどの小さなテクスチャの場合、これは機能せず、0.01f以上に大きくする必要があります)

もちろん、これは簡単な例であり、CPUでUVをピクセルの中心にマッピングすることを心配する必要なく、はるかに簡単にこの計算を行うことができます...それでも、完全に完全な[0、 1] rendertargetの範囲をピクセルに!?


それが助けになるというわけではありませんが、私はまったく同じ問題を抱えています。
IUsedToBeAPygmy

1
線形サンプリングも無効にすることを忘れないでください。
r2d2rigo 2013年

使用している座標系が画面のピクセルと一致していないようです。一致している場合は、ここでは2×2ピクセルしか描画していないようです。私が解決する最初の問題は、座標空間での+1が画面上の1ピクセルのシフトになるようにプロジェクトとモデルビューマトリックスをスケーリングすることです。
Slipp D. Thompson 2013

回答:


4

問題は、UVがテクスチャ座標になるように設計されていることです。座標0,0は、テクスチャの左上のピクセルの左上隅であり、通常はテクスチャを読みたくない場所です。2Dの場合、そのピクセルの中央にあるテクスチャを読み取ります。

私の数学が正しければ、それを実行するためにあなたがする必要があるのはそれです:

return float4((texCoord.rg - (0.5f/textureSize)) * (textureSize/(textureSize-1)), 0, 1);

つまり、適切なオフセットを差し引いて、左上のピクセルを0,0にしてから、スケールを適用して右下を正しくします。

同じことは、0-1の範囲外のジオメトリのUV座標を拡張することでも実現できます。


最後の文について詳しく説明しますreturn float4(texCoord.rg, 0, 1);。四角形の4つのコーナーの頂点バッファーでUVにこの変換を適用し、ピクセルシェーダーでを実行するだけです。
Nathan Reed、2012年

私は上記の提案された式を試してみましたが、うまくいきませんでした。上からの4x4サンプルレンダーターゲットでは、RチャネルとGチャネルで左から右または上から下に0、42、127、212を取得します。ただし、0〜255の値を等間隔のステップで設定します(0、85、170、255の4x4テクスチャの場合)。また、UV座標を変更しようとしましたが、適切なオフセットがまだ見つかりませんでした。
マリオ

0

最初の図と比較して、クワッドの右と下の境界線を1ピクセル上および左に移動する必要があるようです。

ほとんど、しかしピクセルの半分だけ。四角形の頂点から0.5を引くだけです。たとえば、同じテクスチャの256x256クワッドが必要な場合、ここにポイントがあります。

p1 = (-0.5, -0.5)
p2 = (-0.5, 255-0.5)
p3 = (255-0.5, 255-0.5)
p4 = (255-0.5, -0.5)

または、代わりにピクセルシェーダーにテクセルの半分を追加することもできます(texCoord.rg + 0.5 *(1.0 / texSize))

ハーフピクセルオフセットは、DX9では既知の事実です。これこの記事はあなたにも役立つかもしれません。


0

これは確かに線形サンプリングが原因です。フルブラックの左上ピクセルの右下にあるテクセルを見ると、RチャンネルまたはGチャンネルに63個あり、Bに2個あるテクセルが2つあることがわかります。次に、あなたが得る泥だらけの暗い黄色 これは、RとGで31、Bで1です。これは、2x2グループでテクセルを平均化した結果です。したがって、解決策は、テクスチャフィルターをポイントに設定することです。


-2

これは単に、頂点シェーダーの処理後にハードドライブによって補間される頂点出力からtexCoordsを使用しているためです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.