MENGGUNAKAN HARDWARE GRAFIS
17.8 PANDANGAN PERTAMA PADA SHADER
Versi modern OpenGL mengharuskan shader digunakan untuk memproses simpul dan fragmen. Dengan demikian, tidak ada primitif yang dapat dirender tanpa setidaknya satu shader simpul untuk memproses simpul primitif yang masuk dan shader lain untuk memproses fragmen raster. Jenis shader tingkat lanjut ada dalam OpenGL dan OpenGL Shading Language: shader geometri dan shader komputasi. Shader geometri dirancang untuk memproses primitif, berpotensi membuat primitif tambahan, dan dapat mendukung operasi instance geometris. Compute shader dirancang untuk melakukan komputasi umum pada GPU,
dan dapat dihubungkan ke set shader yang diperlukan untuk aplikasi tertentu. Untuk informasi lebih lanjut tentang geometri dan shader komputasi, pembaca dirujuk ke dokumen spesifikasi OpenGL dan sumber daya lainnya.
Contoh Shader Vertex
Shader vertex memberikan kontrol atas bagaimana verteks ditransformasikan dan sering membantu menyiapkan data untuk digunakan dalam shader fragmen. Selain transformasi standar dan potensi operasi pencahayaan per titik, shader titik dapat digunakan untuk melakukan komputasi umum pada GPU. Misalnya, jika simpul mewakili partikel dan gerakan partikel dapat (hanya) dimodelkan dalam komputasi shader vertex, CPU sebagian besar dapat dihapus dari melakukan komputasi tersebut. Kemampuan untuk melakukan perhitungan pada simpul yang sudah disimpan dalam memori perangkat keras grafis adalah potensi peningkatan kinerja. Meskipun pendekatan ini berguna dalam beberapa situasi, komputasi umum tingkat lanjut mungkin lebih tepat dikodekan dengan computeshaders.
Matriks viewport Mvp diperkenalkan. Ini mengubah koordinat volume tampilan kanonik menjadi koordinat layar. Dalam volume tampilan kanonik, koordinat ada dalam kisaran [−1,1]. Apa pun di luar rentang ini terpotong. Jika kita membuat asumsi awal bahwa geometri ada dalam rentang ini dan nilai z diabaikan, kita dapat membuat shader simpul yang sangat sederhana. Shader vertex ini melewati posisi vertex ke tahap rasterisasi, di mana transformasi viewport terakhir akan terjadi. Perhatikan bahwa karena penyederhanaan ini, tidak ada proyeksi, tampilan, atau transformasi model yang akan diterapkan ke simpul masuk.
Ini awalnya rumit untuk membuat apa pun kecuali scene yang sangat sederhana, tetapi akan membantu memperkenalkan konsep shader dan memungkinkan Anda untuk membuat segitiga awal ke layar. Shader vertex passthrough berikut:
#version 330 core
layout(location=0) in vec3 in_Position;
void main(void) {
gl_Position = vec4(in_Position, 1.0);
}
Vertex shader ini hanya melakukan satu hal. Ini melewati posisi verteks masuk sebagai gl_Position yang digunakan OpenGL untuk rasterisasi fragmen. Perhatikan bahwa gl_Position adalah variabel cadangan bawaan yang menandakan salah satu output utama yang diperlukan dari shader simpul. Perhatikan juga versi string di baris pertama. Dalam hal ini, string menginstruksikan kompiler GLSL bahwa versi 3.3 dari profil GLSL Core akan digunakan untuk mengkompilasi bahasa bayangan.
Vertex dan fragmen shader adalah operasi SIMD yang masing-masing beroperasi pada semua simpul atau fragmen yang sedang diproses di dalam pipa. Data tambahan dapat dikomunikasikan dari host ke shader yang dieksekusi pada perangkat dengan menggunakan variabel input, output, atau seragam. Data yang dilewatkan ke dalam shader diawali dengan kata kunci in. Lokasi data tersebut yang terkait dengan atribut verteks tertentu atau indeks output fragmen juga ditentukan secara langsung di shader. Jadi,
layout(location=0) in vec3 in_Position;
menentukan bahwa in Position adalah variabel input yang bertipe vec3. Sumber data tersebut adalah indeks atribut 0 yang diasosiasikan dengan geometri. Nama variabel ini ditentukan oleh programmer, dan hubungan antara geometri yang masuk dan shader terjadi saat menyiapkan data vertex pada perangkat. GLSL berisi berbagai jenis bagus yang berguna untuk program grafis, termasuk vec2, vec3, vec4, mat2, mat3, dan mat4 untuk beberapa nama. Tipe standar seperti int atau float juga ada. Dalam pemrograman shader, vektor, seperti vec4 menampung 4 komponen yang sesuai dengan komponen x, y, z, dan w dari koordinat homogen, atau komponen r, g, b, dan dari tupel RGBA. Label untuk tipe dapat dipertukarkan sesuai kebutuhan (dan bahkan diulang) dalam apa yang disebut swizzling (misalnya, di Position.zyxa). Selain itu, label komponen-bijaksana kelebihan beban dan dapat digunakan dengan tepat untuk menyediakan konteks.
Semua shader harus memiliki fungsi utama yang melakukan komputasi utama di semua input. Dalam contoh ini, fungsi utama hanya menyalin posisi simpul input (in Position), yang bertipe vec3 ke dalam variabel output shader simpul built-in, yang bertipe vec4.
Perhatikan bahwa banyak tipe bawaan memiliki konstruktor yang berguna untuk konversi seperti yang disajikan di sini untuk mengonversi tipe vec3 posisi verteks masuk menjadi tipe gl Position’s vec4. Koordinat homogen digunakan dengan OpenGL, jadi 1.0 ditetapkan sebagai koordinat keempat untuk menunjukkan bahwa vektor adalah posisi.
Contoh Shader Fragmen
Jika shader simpul paling sederhana hanya melewatkan koordinat klip, shader fragmen paling sederhana menetapkan warna fragmen ke nilai konstan.
#version 330 core
layout(location=0) out vec4 out_FragmentColor;
void main(void) {
out_FragmentColor = vec4(0.49, 0.87, 0.59, 1.0);
}
Dalam contoh ini, semua fragmen akan diatur ke warna hijau muda. Salah satu perbedaan utama adalah penggunaan kata kunci out. Secara umum, kata kunci masuk dan keluar dalam program shader menunjukkan aliran data masuk dan keluar dari shader.
Sementara shader simpul menerima simpul masuk dan mengeluarkannya ke variabel bawaan, shader fragmen mendeklarasikan nilai keluarnya yang ditulis ke buffer warna:
layout(location=0) out vec4 out_FragmentColor;
Variabel output dari out FragmentColor sekali lagi ditentukan oleh pengguna. Lokasi output adalah indeks buffer warna 0. Fragment shader dapat menghasilkan beberapa buffer, tetapi ini adalah topik lanjutan yang diserahkan kepada pembaca yang akan dibutuhkan jika objek framebuffer OpenGL diselidiki. Penggunaan kata kunci layout dan location membuat
hubungan eksplisit antara data geometris aplikasi di vertex shader dan buffer warna output di fragment shader.