ピクセルへのテクセルの直接マッピング (Direct3D 9)
事前に変換された頂点を使用して 2D 出力をレンダリングする場合は、各テクセル領域が 1 つのピクセル領域に正しく対応するように注意する必要があります。そうしないと、テクスチャの歪みが発生する可能性があります。 三角形をラスター化してテクスチャリングするときに Direct3D が従うプロセスの基本を理解することで、Direct3D アプリケーションで 2D 出力が正しくレンダリングされるようにすることができます。
上の図は、正方形としてモデル化されたピクセルを示しています。 ただし、実際には、ピクセルはドットであり、正方形ではありません。 上の図の各四角形は、ピクセルによって照らされた領域を示していますが、ピクセルは常に正方形の中心にあるドットにすぎません。 この区別は、一見小さいですが、重要です。 次の図に、同じディスプレイのより良い図を示します。
上の図は、各セルの中央の点として各物理ピクセルを正しく示しています。 画面空間座標 (0, 0) は、左上のピクセルに直接配置されるため、左上のセルの中央に配置されます。 したがって、ディスプレイの左上隅は (-0.5、-0.5) になります。これは、左側が 0.5 セル、左上のピクセルから 0.5 セル上にあるためです。 Direct3D では、次の図に示すように、角が (0、0) と (4、4) の四角形がレンダリングされます。
上の図は、数学的な四角形がディスプレイに対してどこにあるかを示していますが、Direct3D がラスター化してディスプレイに送信すると、その四角形の外観は示されていません。 実際、ラスター表示では、四角形の端がピクセル セル間の境界と一致しないため、表示されているとおりに四角形を塗りつぶすことはできません。 つまり、各ピクセルは 1 つの色しか表示できないため、各ピクセル セルは 1 つの色のみで塗りつぶされます。表示が表示されているとおりに四角形をレンダリングする場合、四角形の端に沿ったピクセル セルには、2 つの異なる色 (四角形で覆われた青と背景のみが表示される白) を表示する必要があります。
代わりに、グラフィックス ハードウェアには、四角形を近似するために塗りつぶすピクセルを決定する必要があります。 このプロセスはラスター化と呼ばれ、「 ラスター化ルール (Direct3D 9)」で詳しく説明されています。 この特定のケースでは、ラスター化されたクワッドを次の図に示します。
Direct3D に渡されるクワッドの角は (0,0) と (4, 4) ですが、ラスター化された出力 (前の図) の角は (-0.5,-0.5) と (3.5,3.5) です。 上の 2 つの図を比較して、違いをレンダリングします。 ディスプレイが実際にレンダリングするものは正しいサイズですが、x 方向と y 方向では -0.5 セルシフトされていることがわかります。 ただし、マルチサンプリング手法を除き、これはクワッドに対して可能な限り最適な近似値です。 (マルチサンプリングの詳細なカバレッジについては、「 Antialias サンプル 」を参照してください)。ラスタライザーが四角形が交差するすべてのセルに塗りつぶされた場合、結果の領域は目的の 4 x 4 ではなく次元 5 x 5 になります。
画面座標が左上のピクセルではなく、表示グリッドの左上隅に由来すると仮定した場合、四角形は期待どおりに表示されます。 ただし、クワッドにテクスチャが与えられると、違いが明確になります。 次の図は、クワッドに直接マップする 4 x 4 テクスチャを示しています。
テクスチャは 4 x 4 テクセルで、クワッドは 4 x 4 ピクセルであるため、四角形が描画される画面上の場所に関係なく、テクスチャの四角形がテクスチャとまったく同じように表示される可能性があります。 ただし、これは当てはまれません。位置がわずかに変化しても、テクスチャの表示方法に影響します。 次の図は、ラスター化およびテクスチャ化された後に (0,0) と (4, 4) の間の四角形がどのように表示されるかを示しています。
上の図に示した四角形は、テクスチャ出力 (線形フィルタリング モードとクランプ アドレッシング モード) と、重ね合わせたラスター化されたアウトラインを示しています。 この記事の残りの部分では、出力がテクスチャのように見えるのではなく、その方法で表示される理由を正確に説明しますが、ソリューションが必要な場合は、入力クワッドの端をピクセル セル間の境界線に配置する必要があります。 x と y の四角形の座標を -0.5 単位だけシフトするだけで、テクセル セルはピクセル セルを完全にカバーし、四角形を画面上で完全に再作成できます。 (このトピックの最後の図は、修正された座標の四角形を示しています。
ラスター化された出力が入力テクスチャとわずかに類似している理由の詳細は、Direct3D アドレスとサンプル テクスチャの方法に直接関連しています。 次に示す内容は、 テクスチャ座標空間 と バイリニア テクスチャ フィルタリングについて十分に理解していることを前提としています。
奇妙なピクセル出力の調査に戻ると、出力色をピクセル シェーダーにトレースし直すのが理にかなっています。ピクセル シェーダーは、ラスター化された図形の一部として選択された各ピクセルに対して呼び出されます。 前の図に示した青色のソリッド クワッドには、特に単純なシェーダーを使用できます。
float4 SolidBluePS() : COLOR
{
return float4( 0, 0, 1, 1 );
}
テクスチャ付きクワッドの場合、ピクセル シェーダーを少し変更する必要があります。
texture MyTexture;
sampler MySampler =
sampler_state
{
Texture = <MyTexture>;
MinFilter = Linear;
MagFilter = Linear;
AddressU = Clamp;
AddressV = Clamp;
};
float4 TextureLookupPS( float2 vTexCoord : TEXCOORD0 ) : COLOR
{
return tex2D( MySampler, vTexCoord );
}
このコードでは、4 x 4 テクスチャが MyTexture に格納されていることを前提としています。 示されているように、MySampler テクスチャ サンプラーは、MyTexture でバイリニア フィルター処理を実行するように設定されています。 ピクセル シェーダーはラスター化されたピクセルごとに 1 回呼び出され、返される色は vTexCoord でサンプリングされたテクスチャの色になります。 ピクセル シェーダーが呼び出されるたびに、vTexCoord 引数はそのピクセルのテクスチャ座標に設定されます。 つまり、次の図で詳しく説明するように、シェーダーはピクセルの正確な位置でフィルター処理されたテクスチャの色をテクスチャ サンプラーに求めていることを意味します。
テクスチャ (重ね合わせて表示) は、ピクセル位置 (黒いドットとして表示) で直接サンプリングされます。 テクスチャ座標はラスター化の影響を受けません (それらは元のクワッドの投影された画面空間に残ります)。 黒い点は、ラスター化ピクセルがどこにあるかを示しています。 各ピクセルのテクスチャ座標は、各頂点に格納されている座標を補間することによって簡単に決定できます。(0,0) のピクセルは、(0, 0) の頂点と一致します。したがって、そのピクセルのテクスチャ座標は、単にその頂点 UV (0.0、0.0) に格納されているテクスチャ座標です。 (3, 1) のピクセルの場合、補間された座標は UV (0.75, 0.25) です。これは、そのピクセルがテクスチャの幅の 4 分の 3 とその高さの 4 分の 1 に位置するためです。 これらの補間座標は、ピクセル シェーダーに渡される座標です。
この例では、テクセルはピクセルと並びません。各ピクセル (したがって、各サンプリング ポイント) は、4 つのテクセルの角に配置されます。 フィルター モードが Linear に設定されているため、サンプラーは、そのコーナーを共有する 4 つのテクセルの色を平均化します。 これは、赤と予想されるピクセルが実際には 4 分の 3 の灰色と 1/4 の赤、緑と予想されるピクセルが 1/5 グレーと 1/4 の赤と 1/4 の緑である理由を説明します。
この問題を解決するには、四角形をラスター化するピクセルに正しくマップし、テクセルをピクセルに正しくマップするだけです。 次の図は、(-0.5、-0.5) と (3.5、3.5) の間で同じ四角形を描画した結果を示しています。これは、最初から意図されたクワッドです。
上の図は、四角形 (-0.5、-0.5) から (3.5、3.5) のアウトラインがラスター化された領域と完全に一致することを示しています。
まとめ
まとめると、ピクセルとテクセルは実際にはポイントであり、ソリッド ブロックではありません。 画面スペースは左上のピクセルから生成されますが、テクスチャ座標はテクスチャのグリッドの左上隅から生成されます。 最も重要なのは、ピクセルでテクセルを正しく配置するために、変換された画面空間で作業する場合は、頂点位置の x および y コンポーネントから 0.5 単位を減算することを忘れないでください。
次のコードは、256 x 256 の正方形の頂点をオフセットして、変換された画面空間に 256 x 256 テクスチャを適切に表示する例です。
//define FVF with vertex values in transformed screen space
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_TEX1)
struct CUSTOMVERTEX
{
FLOAT x, y, z, rhw; // position
FLOAT tu, tv; // texture coordinates
};
//unadjusted vertex values
float left = 0.0f;
float right = 255.0f;
float top = 0.0f;
float bottom = 255.0f;
//256 by 256 rectangle matching 256 by 256 texture
CUSTOMVERTEX vertices[] =
{
{ left, top, 0.5f, 1.0f, 0.0f, 0.0f}, // x, y, z, rhw, u, v
{ right, top, 0.5f, 1.0f, 1.0f, 0.0f},
{ right, bottom, 0.5f, 1.0f, 1.0f, 1.0f},
{ left, top, 0.5f, 1.0f, 0.0f, 0.0f},
{ right, bottom, 0.5f, 1.0f, 1.0f, 1.0f},
{ left, bottom, 0.5f, 1.0f, 0.0f, 1.0f},
};
//adjust all the vertices to correctly line up texels with pixels
for (int i=0; i<6; i++)
{
vertices[i].x -= 0.5f;
vertices[i].y -= 0.5f;
}
関連トピック