次の方法で共有


テクセルからピクセルへの直接的なマッピング (Direct3D 9)

トランスフォーム前の頂点を使用して 2D 出力をレンダリングする場合は、各テクセル領域が単一のピクセル領域に正確に対応していることを慎重に確認する必要があります。対応していないと、テクスチャーの歪みが生じる場合があります。三角形をラスター化およびテクスチャー処理する際には、Direct3D が従うプロセスの基本を理解することで、Direct3D を使ってアプリケーションで確実に 2D 出力のレンダリングを実行するようにできます。

Ee417850.MapTex_fig1(ja-jp,VS.85).gif

図 1:6 x 6 解像度の表示

図 1 は、ピクセルが正方形としてモデル化されている図です。ただし、実際にはピクセルは正方形ではなくドットです。図 1 の正方形はそれぞれピクセルで照らされる領域を示しますが、ピクセルは常に正方形の中心の単なるドットです。ささいなことのように思われますが、この違いは重要です。図 2 は同じ表示をわかりやすく示したものです。

Ee417850.MapTex_fig2(ja-jp,VS.85).gif

図 2:表示はピクセルで構成されている

この図は、物理ピクセルがそれぞれ各セルの中心点であることを明確に示しています。スクリーン空間の座標 (0, 0) は、左上のピクセル、および従って左上のセルの中心に直接配置されています。従って、この表示の左上隅は (-0.5, -0.5) に位置します。これは左上のピクセルから、0.5 セル左、0.5 セル上にあるためです。図 3 に示すように、Direct3D は (0, 0) と (4, 4) に四隅を持つクワッドをレンダリングします。

Ee417850.MapTex_fig3(ja-jp,VS.85).gif

図 3:(0, 0) と (4, 4) の間のラスター化されていないクワッドの輪郭

図 3 は算術クワッドが表示を基準としている場合を示していますが、Direct3D によってラスター化され表示に送信されたクワッドの外観を示していません。実際には、クワッドのエッジはピクセル セル間の境界とは一致しないので、示されているとおり正確にクワッドを埋めるラスター表示は不可能です。言い換えれば、各ピクセルは 1 つのカラーのみ表示できるため、各ピクセル セルには 1 つのカラーしか埋まりません。表示が示されているとおりに正確にクワッドをレンダリングするのであれば、クワッドの輪郭に沿ったピクセル セルは 2 つの異なるカラーを示す必要があります。つまり、クワッドによって埋められる青、そして背景以外は見えない白です。

代わりに、クワッドを概算するためにどのピクセルを埋めるかの決定はグラフィック ハードウェアが実行します。このプロセスはラスター化と呼ばれ、「ラスター化ルール (Direct3D 9)」で詳細に説明されています。この特殊なケースについては、ラスター化されたクワッドを図 4 に示します。

Ee417850.MapTex_fig4(ja-jp,VS.85).gif

図 4:(0,0) から (4,4) に描画されたテクスチャーが適用されていないクワッド

Direct3D (図 3) に渡されたクワッドの四隅は (0, 0) と (4, 4) にありますが、ラスター化された出力 (図 4) の四隅は (-0.5,-0.5) と (3.5,3.5) にあります。レンダリングの違いについて、図 3 と 図 4 を比べてください。実際に正しくレンダリングされているものは正しいサイズですが、x および y 方向に -0.5 セルだけずれていることがわかります。ただし、マルチサンプリング テクニックを除いて、これは可能な限り最高のクワッドへの近似です (マルチサンプリングの詳細については、「アンチエイリアス サンプル」を参照)。ラスタライザーが交差するクワッドのすべてのセルを埋めた場合、表示される領域の寸法は必要とされる 4 x 4 ではなく 5 x 5 となることに注意してください。

スクリーン座標が左上のピクセルではなく表示グリッドの左上隅を原点とすると仮定すると、クワッドは予想どおり正確に表示されています。ただし、クワッドにテクスチャーを適用すると違いが明確になります。図 5 は、クワッドに直接マッピングする 4 x 4 のテクスチャーを示しています。

Ee417850.MapTex_fig5(ja-jp,VS.85).gif

図 5:4 x 4 のテクスチャー

テクスチャーは 4 x 4 のテクセルで、クワッドは 4 x 4 のピクセルであるため、クワッドが描画されているスクリーン上の場所に関係なく、テクスチャーと寸分違わないテクスチャー処理されたクワッドが表示されることを期待されるかもしれません。しかしながら、その位置でのわずかな光の変化でもテクスチャーの表示方法に影響するため、まったく同じというわけにはいきません。図 6 は、ラスター化およびテクスチャー処理した後、(0, 0) と (4, 4) の間のクワッドがどのように表示されるかを示しています。

Ee417850.MapTex_fig6(ja-jp,VS.85).gif

図 6:(0, 0) と (4, 4) から描画されたテクスチャー処理されたクワッド

図 6 に描画されたクワッドは、ラスター化された輪郭が重なり合った、テクスチャー処理された出力 (線形のフィルターリング モードとクランプ アドレッシング モードによって) を示します。この記事の後半では、テクスチャーのように表示されず、出力がなぜそのように表示されるのかについて詳しく説明しますが、ここで簡単に解決策をご紹介しておきます。入力クワッドのエッジは、ピクセル セルの間の境界線に沿っている必要があります。x と y のクワッド座標を単純に -0.5 単位ずらすと、テクセル セルは完全にピクセル セルを覆い、スクリーン上でクワッドを完璧に再作成できます(図 8 は修正された座標のクワッドを示しています)。

ラスター化された出力が入力テクスチャーに少しだけ似ている理由は、Direct3D がテクスチャーをアドレッシングおよびサンプリングする方法に直接関係します。以下の説明では、開発者がテクスチャー座標空間バイリニア テクスチャー フィルターリングに精通していることを前提としています。

不明なピクセル出力を調べることに戻りましょう。出力カラーをピクセル シェーダーまで遡ることが重要です。ピクセル シェーダーは、ラスター化された形状の一部として選択されるピクセルごとに呼び出されます。図 3 に示された塗りつぶされた青いクワッドは、とりわけシンプルなシェーダーを持つことができます。

 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 ); }  

そのコードは、図 5 の 4 x 4 テクスチャーが MyTexture に格納されることを想定しています。表示のとおり、MySampler テクスチャー サンプラーは、MyTexture でバイリニア フィルターリングを実行するように設定されています。ピクセル シェーダーはラスター化されたピクセルごとに 1 回呼び出され、毎回返されるカラーは vTexCoord のサンプル テクスチャー カラーです。ピクセル シェーダーが呼び出されるたびに、vTexCoord 引数がそのピクセルのテクスチャー座標に設定されます。つまり、図 7 に詳しく示されているとおり、シェーダーはピクセルの正確な位置でフィルターリングされたテクスチャー カラーをテクスチャー サンプラーに要求します。

Ee417850.MapTex_fig7(ja-jp,VS.85).gif

図 7:テクスチャー座標のサンプリング位置

テクスチャー (重ね合わせて表示) は、ピクセル位置 (黒いドットとして表示) で直接サンプリングされます。テクスチャー座標は、ラスター化の影響を受けません (テクスチャー座標は元のクワッドの計画されたスクリーン空間に残ります)。黒いドットは、ラスター化されたピクセルの場所を示します。各ピクセルのテクスチャー座標は、各頂点に格納されている座標を補間することで簡単に決定できます。(0,0) のピクセルは、(0, 0) の頂点と一致します。したがって、そのピクセルのテクスチャー座標は単にその頂点である UV (0.0, 0.0) に格納されるテクスチャー座標です。(3, 1) のピクセルについては、そのピクセルがテクスチャーの幅の 4 分の 3、高さの 4 分の 1 に配置されているため、補間された座標は UV (0.75, 0.25) です。ピクセル シェーダーに渡される座標は、これらの補間された座標です。

この例では、テクセルはピクセルと一致しません。各ピクセル (従って各サンプリング ポイント) は、4 つのテクセルの角に配置されます。フィルターリング モードは [線形](Linear) に設定されるため、サンプラーはその角を共有する 4 つのテクセルのカラーを平均します。これが、赤と予測されたピクセルが実際には 4 分の 3 の灰色と 4 分の 1 の赤を足したもので、緑と予測されたピクセルが2 分の 1 の灰色、4 分の 1 の赤、4 分の 1 の緑などを足したものである理由です。

この問題は、ラスター化されるピクセルにクワッドを正確にマッピングし、テクセルをピクセルに正確にマッピングするだけで解決できます。図 8 は、アウトセットから計画されたクワッドである、(-0.5, -0.5) と (3.5, 3.5) の間の同じクワッドの描画結果を示しています。

Ee417850.MapTex_fig8(ja-jp,VS.85).gif

図 8:テクスチャー処理されたクワッドは、ラスター化されたクワッドと一致する

図 8 は、クワッド ((-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;
}