Bagaimana cara kerja multipass shaders di OpenGL?


13

Di Direct3D, multipass shaders mudah digunakan karena Anda benar-benar dapat mendefinisikan lintasan dalam suatu program. Di OpenGL, tampaknya sedikit lebih rumit karena dimungkinkan untuk memberikan program shader sebanyak mungkin vertex, geometri, dan fragmen shader yang Anda inginkan.

Contoh populer dari multipass shader adalah toon shader. Satu pass melakukan efek cel-shading yang sebenarnya dan yang lainnya menciptakan garis besar. Jika saya memiliki dua vertex shaders, "cel.vert" dan "outline.vert", dan dua fragmen shaders, "cel.frag" dan "outline.frag" (mirip dengan cara Anda melakukannya di HLSL), bagaimana saya bisa menggabungkan mereka untuk membuat shader toon penuh?

Saya tidak ingin Anda mengatakan bahwa geometri shader dapat digunakan untuk ini karena saya hanya ingin tahu teori di balik multipass shaders GLSL;)


"Di Direct3D, multipass shaders mudah digunakan karena Anda benar-benar dapat mendefinisikan lintasan dalam suatu program." Tidak, kamu tidak bisa. Anda dapat menentukan lintasan dalam file FX, tetapi itu tidak sama dengan shader HLSL.
Nicol Bolas

Jawaban:


11

Tidak ada "teori" di balik multipass. Tidak ada "multipass shaders". Multipass sangat sederhana: Anda menggambar objek dengan satu program. Kemudian Anda menggambar objek dengan program yang berbeda .

Anda dapat menggunakan hal-hal D3DX seperti file FX untuk menyembunyikan pass tambahan ini. Tapi mereka tetap bekerja seperti itu. OpenGL tidak memiliki tempat persembunyian untuk itu.


1

Render objek dengan shader sel, dan kemudian render objek dengan shader garis besar.


1
Jadi saya harus membuat dua program shader yang berbeda? Mengapa kemudian saya bisa memberikan program shader sebanyak vertex / geometri / fragmen shader yang saya inginkan? Pasti ada cara untuk melakukannya dengan satu program.
jmegaffin

1
Anda tidak memberinya multi vertex (dll.) Shader. Hanya ada satu fungsi utama, jadi Anda tidak memiliki banyak titik masuk. Ini sangat mirip dengan program C di mana Anda dapat memiliki banyak file yang dihubungkan bersama untuk membuat suatu program. Anda dapat membagikan file-file ini di antara program-program yang berbeda sehingga Anda tidak perlu menduplikasi kodenya, tetapi setiap file tidak harus berupa program dengan sendirinya.
Chewy Gumball

1
Begitulah caranya, Render sekali dengan satu pasangan shader (vertex + fragmen) kemudian render lagi dengan pasangan lain (atau gunakan vertex shader yang sama + shader fragmen lain). Kadang-kadang Anda membuat buffer dan menggunakan (belum) shader lain untuk 'menyatukannya' ke hasil akhir.
Valmond

1

Di OpenGL 4.0 ada subrutin seragam . Ini memungkinkan Anda untuk mendefinisikan fungsi yang dapat ditukar saat runtime dengan overhead yang sangat sedikit. Jadi, Anda dapat membuat 1 fungsi untuk setiap pass. Juga 1 fungsi untuk setiap jenis shader.

Ada tutorial di sini .

Untuk versi OpenGL yang lebih tua, taruhan terbaik Anda adalah memiliki banyak shader yang berbeda dan bertukar di antaranya. Kalau tidak, Anda bisa menambahkan nilai-nilai bersama yang Anda kalikan dengan seragam yaitu 0,0 atau 1,0 untuk menyalakan atau mematikannya. Kalau tidak kondisional jika pernyataan dapat digunakan tetapi OpenGL akan mengeksekusi semua hasil yang mungkin setiap eksekusi / lulus jadi pastikan mereka tidak terlalu berat.


0

Ada beberapa orang yang tahu banyak tentang GLSL, jadi saya harap mereka datang meluruskan, tetapi berdasarkan apa yang saya lihat, Anda harus dapat, dalam shader fragmen Anda, melakukan sesuatu seperti ini (pseudocode, saya Akan menyerahkan GLSL yang sebenarnya kepada orang-orang yang mengenalnya lebih baik):

out vec4 fragment_color
vec4 final_color
final_color = flat_color
If this fragment is in shadow
    final_color = shadow_color
If this fragment is an edge
    final_color = edge_color
If this fragment is a highlight
    final_color = highlight_color
fragment_color = final_color

Dengan menggunakan ifs dengan cara ini, Anda mendapatkan sesuatu seperti beberapa lintasan. Apakah itu masuk akal?

Sunting: Juga, semoga pertanyaan tentang SO ini membantu menghilangkan beberapa kesalahpahaman.


2
Penting untuk dicatat bahwa GLSL akan mengeksekusi semua pernyataan di cabang if jika setiap pass walaupun tidak diaktifkan. Rupanya hanya menghitung semuanya dan menambahkan semua warna bersama tetapi mengalikan nilai dengan 1,0 atau 0,0 untuk mengaktifkan atau menonaktifkannya lebih cepat.
David C. Bishop

1
@ DavidC.Bishop: Itu tidak benar. Paling tidak, tidak dijamin benar. Compiler akan memutuskan apakah cabang aktual lebih cepat atau pendekatan "hitung semuanya dan atur nanti" lebih cepat.
Nicol Bolas

1
Selain itu, perilaku yang dirujuk oleh @ DavidC.Bishop hampir tidak spesifik untuk shader dan GPU. CPU modern yang menjalankan program normal akan secara spekulatif mengeksekusi setidaknya satu cabang jika nilai yang diuji belum tersedia. Jika ternyata salah, mereka mundur dan mengulang. Ini akhirnya menghasilkan speedup besar rata-rata.
ipeet
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.