直接將紋素對應至圖元 (Direct3D 9)
使用預先轉換頂點轉譯 2D 輸出時,請務必小心確保每個紋素區域都正確對應至單一圖元區域,否則可能會發生紋理失真。 藉由瞭解 Direct3D 在點陣化和紋理三角形時所遵循的程式基本概念,您可以確定 Direct3D 應用程式正確地轉譯 2D 輸出。
上圖顯示模型化為平方的圖元。 不過,事實上,圖元是點,而不是正方形。 上圖中的每個方塊都表示圖元所光線的區域,但圖元一律只是正方形中央的點。 雖然似乎很小,但這種區別很重要。 下圖顯示相同顯示器的較佳圖例。
上圖正確顯示每個實體圖元,作為每個儲存格中央的點。 螢幕空間座標 (0,0) 直接位於左上方圖元,因此位於左上方儲存格的中心。 因此,顯示器的左上角是 (-0.5、-0.5) ,因為它是左邊的 0.5 儲存格,從左上方圖元向上 0.5 個儲存格。 Direct3D 會轉譯四邊形,其邊角位於 (0、0) 和 (4、4) ,如下圖所示。
上圖顯示數學四邊形相對於顯示器的位置,但不會顯示四邊形在 Direct3D 點陣化後的外觀,並將它傳送至顯示器。 事實上,點陣顯示器無法完全填滿四邊形,因為四邊形的邊緣與圖元儲存格之間的界限不一致。 換句話說,因為每個圖元只能顯示單一色彩,所以每個圖元儲存格只會填滿單一色彩;如果顯示器要完全如所示呈現四邊形,則四邊形上的圖元儲存格必須顯示兩個不同的色彩:四邊形所涵蓋的藍色,而白色則只顯示背景。
相反地,圖形硬體會決定應該填滿哪些圖元大約四邊形。 此程式稱為點陣化,並詳述于 點陣化規則 (Direct3D 9) 。 在此特定案例中,下圖顯示點陣化四邊形。
請注意,傳遞至 Direct3D 的四邊形 ( (0、0) 和 (4、4) ,但上圖 (點化輸出) 在 (-0.5,-0.5) 和 (3.5,3.5) 。 比較上述兩個圖例的轉譯差異。 您可以看到顯示實際呈現的內容是正確的大小,但已由 x 和 y 方向中的 -0.5 儲存格移位。 不過,除了多重取樣技術之外,這是四邊形的最佳可能近似值。 (請參閱 Antialias 範例 以取得多重取樣的完整涵蓋範圍。) 請注意,如果點陣化器填滿四邊形圖的每個儲存格,產生的區域會是維度 5 x 5,而不是所需的 4 x 4。
如果您假設螢幕座標源自顯示格線的左上角,而不是左上方圖元,則四邊形會如預期般顯示。 不過,當四邊形有紋理時,差異就會變得清楚。 下圖顯示您將直接對應到四邊形的 4 x 4 紋理。
因為紋理是 4 x 4 紋素,而四邊形是 4 x 4 圖元,所以您可能會預期紋理四邊形看起來與紋理完全相同,而不論繪製四邊形的畫面上的位置為何。 不過,這不是這種情況;即使位置稍有變更,也會影響紋理的顯示方式。 下圖顯示 (0、0) 和 (4、4) 之間的四邊形如何在點陣化和紋理之後顯示。
上圖中繪製的四邊形顯示紋理輸出 (線性篩選模式,以及具有迭迭點陣化外框的固定定址模式) 。 本文的其餘部分會確切說明輸出看起來的方式,而不是像紋理,但對於想要解決方案的人而言,這就是:輸入四邊形的邊緣必須位於圖元儲存格之間的界限線。 只要以 -0.5 單位移動 x 和 y 四邊座標,紋素儲存格就會完美地覆蓋圖元儲存格,而四邊形可以在畫面上完全重新建立。 (本主題中的最後一個圖例顯示更正座標處的四邊形。)
點陣化輸出只與輸入紋理稍微相等的原因詳細資料,與 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 上執行雙向篩選。 圖元著色器會針對每個點陣化圖元呼叫一次,而每次傳回的色彩都是 vTexCoord 的取樣紋理色彩。 每次呼叫圖元著色器時,vTexCoord 引數都會設定為該圖元的紋理座標。 這表示著色器會向紋理取樣器詢問圖元確切位置的篩選紋理色彩,如下圖所示。
紋理 (顯示的迭加) 會直接取樣圖元位置, (顯示為黑色點) 。 紋理座標不會受到點陣化的影響, (它們會保留在原始四邊形) 的投影螢幕空間中。 黑色點會顯示點陣化圖元的位置。 每個圖元的紋理座標很容易透過插補儲存在每個頂點的座標來判斷:位於 (0,0) 的圖元與頂 (點位於 0,0) ;因此,該圖元的紋理座標只是儲存在該頂點的紋理座標,UV (0.0,0.0) 。 針對 (3、1) 的圖元,插補座標為 UV (0.75、0.25) ,因為該圖元位於紋理寬度的三分之四,且高度為 14 秒。 這些插補座標是傳遞至圖元著色器的內容。
紋素不會與本範例中的圖元對齊;每個圖元 (,因此每個取樣點) 都位於四個材質的角落。 由於篩選模式設定為 [線性],因此取樣器會平均共用該角落之四個材質的色彩。 這說明為什麼預期為紅色的圖元實際上是三分之四灰色加上一四分之一紅色,預期為綠色的圖元是一半灰色加上一四四紅色加上四分之一綠色等等。
若要修正此問題,您只需要正確地將四邊形對應至要點陣化的圖元,進而正確地將紋素對應至圖元。 下圖顯示繪製 (-0.5、-0.5) 和 (3.5、3.5) 之間的相同四邊形的結果,這是從頭開始的四邊形。
上圖示范從 (-0.5、 -0.5) 到 (3.5, 3.5) ) 所顯示的四邊形 (完全符合點陣化區域。
摘要
總而言之,圖元和紋素實際上是點,而不是實心區塊。 螢幕空間源自左上方圖元,但紋理座標源自紋理格線左上角。 最重要的是,在轉換的螢幕空間中工作時,請記得從頂點位置的 x 和 y 元件減去 0.5 單位,以便正確地對齊紋素與圖元。
下列程式碼範例是將 256 乘 256 平方的頂點位移,以在轉換的螢幕空間中正確顯示 256 by 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;
}
相關主題