Langsung Memetakan Texel ke Piksel (Direct3D 9)

Saat merender output 2D menggunakan simpul yang telah diubah sebelumnya, perawatan harus dilakukan untuk memastikan bahwa setiap area texel sesuai dengan area piksel tunggal, jika tidak, distorsi tekstur dapat terjadi. Dengan memahami dasar-dasar proses yang diikuti Direct3D saat melakukan rasterisasi dan tekstur segitiga, Anda dapat memastikan aplikasi Direct3D Anda merender output 2D dengan benar.

ilustrasi tampilan resolusi 6x6

Diagram sebelumnya menunjukkan piksel yang dimodelkan sebagai kuadrat. Namun, pada kenyataannya, piksel adalah titik, bukan persegi. Setiap persegi dalam diagram sebelumnya menunjukkan area yang dinyalakan oleh piksel, tetapi piksel selalu hanya titik di tengah persegi. Perbedaan ini, meskipun tampaknya kecil, penting. Ilustrasi yang lebih baik dari tampilan yang sama diperlihatkan dalam diagram berikut.

ilustrasi tampilan yang terdiri dari piksel

Diagram sebelumnya memperlihatkan setiap piksel fisik dengan benar sebagai titik di tengah setiap sel. Koordinat ruang layar (0, 0) terletak langsung di piksel kiri atas, dan karenanya di bagian tengah sel kiri atas. Oleh karena itu, sudut kiri atas tampilan berada di (-0,5, -0,5) karena 0,5 sel di sebelah kiri dan 0,5 sel ke atas dari piksel kiri atas. Direct3D akan merender quad dengan sudut pada (0, 0) dan (4, 4), seperti yang ditunjukkan dalam ilustrasi berikut.

ilustrasi kerangka quad yang tidak diraster antara (0, 0) dan (4, 4)

Ilustrasi sebelumnya menunjukkan di mana quad matematika terkait dengan tampilan, tetapi tidak menunjukkan seperti apa quad akan terlihat setelah Direct3D mem-rasterisasinya dan mengirimkannya ke layar. Bahkan, tidak mungkin bagi tampilan raster untuk mengisi quad persis seperti yang ditunjukkan karena tepi quad tidak bertepatan dengan batas antara sel piksel. Dengan kata lain, karena setiap piksel hanya dapat menampilkan satu warna, setiap sel piksel hanya diisi dengan satu warna; jika tampilan merender quad persis seperti yang ditunjukkan, sel piksel di sepanjang tepi quad perlu menampilkan dua warna yang berbeda: biru di mana ditutupi oleh quad dan putih di mana hanya latar belakang yang terlihat.

Sebaliknya, perangkat keras grafis ditugaskan untuk menentukan piksel mana yang harus diisi ke perkiraan quad. Proses ini disebut rasterisasi, dan dirinci dalam Aturan Rasterisasi (Direct3D 9). Untuk kasus khusus ini, quad raster ditunjukkan dalam ilustrasi berikut.

ilustrasi quad yang belum habis digambar dari (0,0) ke (4,4)

Perhatikan bahwa quad yang diteruskan ke Direct3D memiliki sudut pada (0, 0) dan (4, 4), tetapi output yang diraster (ilustrasi sebelumnya) memiliki sudut di (-0,5,-0,5) dan (3,5,3,5). Bandingkan dua ilustrasi sebelumnya untuk merender perbedaan. Anda dapat melihat bahwa apa yang sebenarnya dirender tampilan adalah ukuran yang benar, tetapi telah digeser oleh sel -0,5 dalam arah x dan y. Namun, kecuali untuk teknik multi-pengambilan sampel, ini adalah perkiraan terbaik untuk quad. (Lihat Sampel Antialias untuk cakupan menyeluruh dari multi-pengambilan sampel.) Ketahuilah bahwa jika rasterizer mengisi setiap sel quad yang disilangkan, area yang dihasilkan adalah dimensi 5 x 5 alih-alih 4 x 4 yang diinginkan.

Jika Anda mengasumsikan bahwa koordinat layar berasal dari sudut kiri atas kisi tampilan, bukan piksel kiri atas, quad akan terlihat persis seperti yang diharapkan. Namun, perbedaannya menjadi jelas ketika quad diberi tekstur. Ilustrasi berikut menunjukkan tekstur 4 x 4 yang akan Anda petakan langsung ke quad.

ilustrasi tekstur 4x4

Karena teksturnya adalah 4 x 4 texel dan quad adalah 4 x 4 piksel, Anda mungkin mengharapkan quad bertekstur muncul persis seperti tekstur terlepas dari lokasi di layar tempat quad digambar. Namun, ini tidak terjadi; bahkan sedikit perubahan posisi memengaruhi bagaimana tekstur ditampilkan. Ilustrasi berikut menunjukkan bagaimana quad antara (0, 0) dan (4, 4) ditampilkan setelah diraster dan diteksur.

ilustrasi quad berteksur yang digambar dari (0, 0) dan (4, 4)

Quad yang digambar dalam ilustrasi sebelumnya menunjukkan output bertekskus (dengan mode pemfilteran linier dan mode pengalamatan klem) dengan kerangka raster yang ditumbukkan. Sisa artikel ini menjelaskan dengan tepat mengapa output terlihat seperti yang dilakukannya alih-alih terlihat seperti tekstur, tetapi bagi mereka yang menginginkan solusinya, ini dia: Tepi quad input perlu terletak pada garis batas di antara sel piksel. Hanya dengan menggeser koordinat x dan y quad sebesar -0,5 unit, sel texel akan menutupi sel piksel dengan sempurna dan quad dapat dibuat ulang dengan sempurna di layar. (Ilustrasi terakhir dalam topik ini menunjukkan quad pada koordinat yang dikoreksi.)

Detail mengapa output yang diraster hanya memiliki sedikit kesesatan dengan tekstur input yang terkait langsung dengan cara direct3D alamat dan tekstur sampel. Apa berikut mengasumsikan Anda memiliki pemahaman yang baik tentang ruang koordinat tekstur Dan pemfilteran tekstur bilinear.

Kembali ke penyelidikan kami tentang output piksel yang aneh, masuk akal untuk melacak warna output kembali ke shader piksel: Shader piksel dipanggil untuk setiap piksel yang dipilih untuk menjadi bagian dari bentuk rasterisasi. Quad biru solid yang digambarkan dalam ilustrasi sebelumnya dapat memiliki shader yang sangat sederhana:

float4 SolidBluePS() : COLOR
{ 
    return float4( 0, 0, 1, 1 );
} 

Untuk quad berteksur, shader piksel harus sedikit diubah:

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

Kode itu mengasumsikan tekstur 4 x 4 disimpan dalam MyTexture. Seperti yang ditunjukkan, sampler tekstur MySampler diatur untuk melakukan pemfilteran bilinear pada MyTexture. Shader piksel dipanggil sekali untuk setiap piksel yang diraster, dan setiap kali warna yang dikembalikan adalah warna tekstur sampel di vTexCoord. Setiap kali shader piksel dipanggil, argumen vTexCoord diatur ke koordinat tekstur pada piksel tersebut. Itu berarti shader meminta sampler tekstur untuk warna tekstur yang difilter di lokasi piksel yang tepat, seperti yang dijelaskan dalam ilustrasi berikut.

ilustrasi lokasi pengambilan sampel untuk koordinat tekstur

Tekstur (ditampilkan ditumbukkan) diambil sampelnya langsung di lokasi piksel (ditampilkan sebagai titik hitam). Koordinat tekstur tidak terpengaruh oleh rasterisasi (koordinat tetap berada di ruang layar yang diproyeksikan dari quad asli). Titik-titik hitam menunjukkan di mana piksel rasterisasi berada. Koordinat tekstur pada setiap piksel mudah ditentukan dengan menginterpolasi koordinat yang disimpan di setiap puncak: Piksel pada (0,0) bertepatan dengan puncak pada (0, 0); oleh karena itu, koordinat tekstur pada piksel tersebut hanyalah koordinat tekstur yang disimpan di puncak tersebut, UV (0,0, 0,0). Untuk piksel pada (3, 1), koordinat terinterpolasi adalah UV (0,75, 0,25) karena piksel tersebut terletak pada tiga perempat lebar tekstur dan sebelas dari tingginya. Koordinat terinterpolasi inilah yang diteruskan ke piksel shader.

Texel tidak sejajar dengan piksel dalam contoh ini; setiap piksel (dan oleh karena itu setiap titik pengambilan sampel) diposisikan di sudut empat texel. Karena mode pemfilteran diatur ke Linear, sampler akan rata-rata warna empat texel yang berbagi sudut tersebut. Ini menjelaskan mengapa piksel yang diharapkan menjadi merah sebenarnya abu-abu tiga-keempat ditambah merah seperempat, piksel yang diharapkan berwarna hijau adalah satu setengah abu-abu ditambah merah seperempat ditambah hijau seperempat, dan sebagainya.

Untuk memperbaiki masalah ini, yang perlu Anda lakukan adalah memetakan quad dengan benar ke piksel yang akan dirasterisasi, dan dengan demikian memetakan texel dengan benar ke piksel. Ilustrasi berikut menunjukkan hasil menggambar quad yang sama antara (-0,5, -0,5) dan (3,5, 3,5), yang merupakan quad yang dimaksudkan dari awal.

ilustrasi quad berteksur yang cocok dengan quad raster

Ilustrasi sebelumnya menunjukkan bahwa quad (ditampilkan diuraikan dari (-0,5, -0,5) hingga (3,5, 3,5)) sama persis dengan area yang dirasterisasi.

Ringkasan

Singkatnya, piksel dan texel sebenarnya adalah titik, bukan blok padat. Ruang layar berasal dari piksel kiri atas, tetapi koordinat tekstur berasal dari sudut kiri atas kisi tekstur. Yang paling penting, ingatlah untuk mengurangi unit 0,5 dari komponen x dan y dari posisi puncak Anda saat bekerja di ruang layar yang diubah untuk menyelaraskan texel dengan piksel dengan benar.

Kode berikut adalah contoh mengimbangi simpul dari persegi 256 sebesar 256 untuk menampilkan tekstur 256 kali 256 dengan 256 dengan benar dalam ruang layar yang diubah.

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

Koordinat Tekstur