Bagikan melalui


Adaptasi GLSL

API Penting

  • HLSL Semantics
  • Shader Constants (HLSL)

Setelah Anda memindahkan kode yang membuat dan mengonfigurasi buffer dan objek shader, saatnya untuk memindahkan kode di dalam shader tersebut dari Gl Shader Language (GLSL) OpenGL ES 2.0 ke Bahasa Shader Tingkat Tinggi (HLSL) Direct3D 11.

Di OpenGL ES 2.0, shader mengembalikan data setelah eksekusi menggunakan intrinsik seperti gl_Position, gl_FragColor, atau gl_FragData[n] (di mana n adalah indeks untuk target render tertentu). Dalam Direct3D, tidak ada intrinsik khusus, dan shader mengembalikan data sebagai tipe pengembalian dari fungsi main() masing-masing.

Data yang ingin Anda interpolasi di antara tahap shader, seperti posisi verteks atau normal, ditangani melalui penggunaan deklarasi varying. Namun, Direct3D tidak memiliki deklarasi ini; sebaliknya, data apa pun yang ingin Anda lewati di antara tahap shader harus ditandai dengan semantik HLSL. Semantik tertentu yang dipilih menunjukkan tujuan data, dan adalah. Misalnya, Anda akan mendeklarasikan data verteks yang ingin Anda interpolasi di antara shader fragmen sebagai berikut:

float4 vertPos : POSITION;

atau

float4 vertColor : COLOR;

Di mana POSITION adalah semantik yang digunakan untuk menunjukkan data posisi vertex. POSITION juga merupakan kasus khusus, karena setelah proses interpolasi, tidak dapat diakses oleh piksel shader. Oleh karena itu, Anda harus menentukan input ke shader piksel dengan SV_POSITION dan data vertex terinterpolasi akan ditempatkan dalam variabel tersebut.

float4 position : SV_POSITION;

Semantik dapat dideklarasikan pada metode tubuh (utama) shader. Untuk piksel shader, SV_TARGET[n], yang menunjukkan target render, diperlukan pada metode isi. (SV_TARGET tanpa akhiran numerik default untuk merender indeks target 0.)

Perhatikan juga bahwa shader vertex diperlukan untuk menghasilkan semantik nilai sistem SV_POSITION. Semantik ini mengonversi data posisi puncak menjadi nilai koordinat di mana x pada koordinat berada antara -1 dan 1, y pada koordinat berada antara -1 dan 1, z dihasilkan dari pembagian dengan nilai koordinat homogen asli w (z/w), dan w dihasilkan dari 1 dibagi dengan nilai w asli (1/w). Shader piksel menggunakan semantik nilai sistem SV_POSITION untuk mengambil lokasi piksel di layar, di mana x berada antara 0 dan lebar target tampilan dan y berada antara 0 dan tinggi target tampilan (masing-masing di-offset sebesar 0,5). Shader piksel tingkat fitur 9_x tidak dapat membaca dari nilai SV_POSITION.

Buffer konstanta harus dideklarasikan dengan cbuffer dan dikaitkan dengan register awal tertentu untuk pencarian.

Direct3D 11: Deklarasi penyangga konstan HLSL

cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
  matrix mvp;
};

Di sini, buffer konstanta menggunakan register b0 untuk menyimpan buffer yang terpaket. Semua register dirujuk dalam formulir b#. Untuk informasi selengkapnya tentang implementasi HLSL buffer konstan, register, dan pengemasan data, baca Shader Constants (HLSL).

Petunjuk

Langkah 1: Port vertex shader

Dalam contoh OpenGL ES 2.0 sederhana kami, shader vertex memiliki tiga input: matriks 4x4 model-view-projection yang konstan, dan dua vektor dengan 4 koordinat. Kedua vektor ini berisi posisi puncak dan warnanya. Shader mengubah vektor posisi menjadi koordinat perspektif dan menetapkannya ke intrinsik gl_Position untuk rasterisasi. Warna puncak disalin ke variabel yang bervariasi untuk interpolasi selama rasterisasi, juga.

OpenGL ES 2.0: Shader vertex untuk objek kubus (GLSL)

uniform mat4 u_mvpMatrix; 
attribute vec4 a_position;
attribute vec4 a_color;
varying vec4 destColor;

void main()
{           
  gl_Position = u_mvpMatrix * a_position;
  destColor = a_color;
}

Sekarang, di Direct3D, matriks proyeksi tampilan model konstan terkandung dalam buffer konstan yang dikemas pada register b0, dan posisi dan warna puncak secara khusus ditandai dengan semantik HLSL masing-masing yang sesuai: POSISI dan WARNA. Karena tata letak input kami menunjukkan pengaturan tertentu dari dua nilai vertex ini, Anda membuat struct untuk menahannya dan mendeklarasikannya sebagai tipe untuk parameter input pada fungsi utama shader (main). (Anda juga dapat menentukannya sebagai dua parameter individual, tetapi itu bisa menjadi rumit.) Anda juga menentukan jenis keluaran untuk tahap ini, yang berisi posisi dan warna terinterpolasi, dan mendeklarasikannya sebagai nilai pengembalian untuk fungsi utama dari shader vertex.

Direct3D 11: Shader vertex untuk objek kubus (HLSL)

cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
  matrix mvp;
};

// Per-vertex data used as input to the vertex shader.
struct VertexShaderInput
{
  float3 pos : POSITION;
  float3 color : COLOR;
};

// Per-vertex color data passed through the pixel shader.
struct PixelShaderInput
{
  float3 pos : SV_POSITION;
  float3 color : COLOR;
};

PixelShaderInput main(VertexShaderInput input)
{
  PixelShaderInput output;
  float4 pos = float4(input.pos, 1.0f); // add the w-coordinate

  pos = mul(mvp, projection);
  output.pos = pos;

  output.color = input.color;

  return output;
}

Jenis data keluaran, PixelShaderInput, dibangun selama proses rasterisasi dan diteruskan ke shader fragmen piksel.

Langkah 2: Port fragment shader

Contoh shader fragmen kami di GLSL sangat sederhana: berikan gl_FragColor intrinsik dengan nilai warna terinterpolasi. OpenGL ES 2.0 akan menulisnya ke target render default.

OpenGL ES 2.0: Shader fragmen untuk objek kubus (GLSL)

varying vec4 destColor;

void main()
{
  gl_FragColor = destColor;
} 

Direct3D hampir sama sederhananya. Satu-satunya perbedaan signifikan adalah bahwa fungsi utama shader piksel wajib mengembalikan nilai. Karena warna adalah nilai float dengan 4 koordinat (RGBA), Anda menetapkan float4 sebagai jenis pengembalian, lalu menentukan target render default sebagai semantik nilai sistem SV_TARGET.

Direct3D 11: Piksel shader untuk objek kubus (HLSL)

struct PixelShaderInput
{
  float4 pos : SV_POSITION;
  float3 color : COLOR;
};


float4 main(PixelShaderInput input) : SV_TARGET
{
  return float4(input.color, 1.0f);
}

Warna untuk piksel pada posisi tersebut diatur ke target render. Sekarang, mari kita lihat cara menampilkan konten target render tersebut di Menggambar ke layar!

Langkah sebelumnya

Port buffer vertikal dan data

Langkah selanjutnya

Gambar ke layar

Komentar

Memahami semantik HLSL dan pengemasan buffer konstan dapat mengurangi kerepotan saat debugging, serta memberikan peluang untuk optimasi. Jika Anda mendapatkan kesempatan, baca melalui Sintaks Variabel (HLSL), Pengantar Buffer di Direct3D 11, dan Cara: Membuat Buffer Konstanta. Namun, jika tidak, berikut beberapa tips awal yang perlu diingat mengenai semantik dan buffer konstan.

  • Selalu periksa kembali kode konfigurasi Direct3D perender Anda untuk memastikan bahwa struktur untuk buffer konstanta Anda cocok dengan deklarasi struct cbuffer di HLSL Anda, dan bahwa jenis skalar komponen cocok di kedua deklarasi.
  • Dalam kode C++ perender Anda, gunakan tipe DirectXMath dalam deklarasi buffer konstan Anda untuk menjamin pengemasan data yang tepat.
  • Cara terbaik untuk menggunakan buffer konstanta secara efisien adalah dengan mengatur variabel shader ke dalam buffer konstan berdasarkan frekuensi pembaruannya. Misalnya, jika Anda memiliki beberapa data seragam yang diperbarui sekali per bingkai, dan data seragam lainnya yang diperbarui hanya ketika kamera bergerak, pertimbangkan untuk memisahkan data tersebut menjadi dua buffer konstan terpisah.
  • Semantik yang lupa Anda terapkan atau yang telah Anda terapkan secara tidak benar akan menjadi sumber paling awal kesalahan kompilasi shader (FXC). Periksa kembali mereka! Dokumen bisa sedikit membingungkan, karena banyak halaman dan sampel yang lebih lama mengacu pada versi semantik HLSL yang berbeda sebelum Direct3D 11.
  • Pastikan Anda tahu tingkat fitur Direct3D mana yang Anda targetkan untuk setiap shader. Semantik untuk tingkat fitur 9_* berbeda dari semantik untuk 11_1.
  • Semantik SV_POSITION menyelesaikan data posisi setelah interpolasi menjadi nilai koordinat di mana x berada antara 0 dan lebar target render, y berada antara 0 dan tinggi target render, z diperoleh dengan membagi nilai koordinat homogen asli oleh nilai w asli (z/w), dan w diperoleh dengan 1 dibagi dengan nilai w asli (1/w).

Cara: mem-port perender OpenGL ES 2.0 sederhana ke Direct3D 11

Portasi objek shader

Port buffer vertikal dan data

Gambar ke layar