OpenGL: Di mana saya harus menempatkan shader?

17

Saya mencoba mempelajari OpenGL ES 2.0 dan saya bertanya-tanya apa praktik yang paling umum untuk "mengelola" shader.
Saya mengajukan pertanyaan ini karena dalam contoh yang saya temukan (seperti yang termasuk dalam Demo API yang disediakan dengan SDK Android), saya biasanya melihat segala sesuatu di dalam kelas GLRenderer dan saya lebih suka memisahkan hal-hal sehingga saya dapat memiliki, misalnya, objek GLImage yang dapat saya gunakan kembali kapan pun saya ingin menggambar quad bertekstur (saya fokus pada 2D hanya saat ini), sama seperti yang saya miliki dalam kode OpenGL ES 1.0 saya. Di hampir setiap contoh yang saya temukan, shader hanya didefinisikan sebagai atribut kelas. Sebagai contoh:

public class Square {

public final String vertexShader =
        "uniform mat4 uMVPMatrix;\n" +
        "attribute vec4 aPosition;\n" +
        "attribute vec4 aColor;\n" +
        "varying vec4 vColor;\n" +
        "void main() {\n" +
        "  gl_Position = uMVPMatrix * aPosition;\n" +
        "  vColor = aColor;\n" +
        "}\n";

public final String fragmentShader =
        "precision mediump float;\n" +
        "varying vec4 vColor;\n" +
        "void main() {\n" +
        "  gl_FragColor = vColor;\n" +
        "}\n";
// ...
}

Saya minta maaf sebelumnya jika beberapa dari pertanyaan ini bodoh, tetapi saya belum pernah bekerja dengan shader sebelumnya.

1) Apakah kode di atas cara umum untuk mendefinisikan shader (properti kelas akhir publik)?
2) Haruskah saya memiliki kelas Shader yang terpisah?
3) Jika shader didefinisikan di luar kelas yang menggunakannya, bagaimana saya tahu nama atribut mereka (mis. "AColor" pada bagian kode berikut) sehingga saya dapat mengikatnya?

colorHandle = GLES20.glGetAttribLocation(program, "aColor");
miviclin
sumber

Jawaban:

16

Saya selalu tidak menyukai cara mendefinisikan shader (dalam sebuah string). Saya lebih suka mengerjakan milik saya dalam file teks dan membacanya saat memuat. Mendefinisikannya dalam sebuah string mengganggu untuk debugging dan itu hanya terlihat berantakan bagi saya. Ini jauh lebih mudah untuk bisa mengetiknya dan melihatnya diformat seperti seharusnya, daripada di dalam string.

Saya juga memiliki kelas terpisah yang memiliki fungsi shader umum, seperti membaca di shader dan mencetak info logging untuk debugging shader.

Di mana pun shader didefinisikan, Anda dapat mengakses nama-nama seperti yang Anda lakukan dalam contoh Anda. Menggunakan string literal dapat diterima oleh shader karena nilai-nilai itu tidak mungkin berubah setelah Anda menerapkannya.

Namun, pada akhirnya terserah Anda. Cara Anda saat ini bekerja sangat baik, jika itu tidak menimbulkan masalah bagi Anda.

MichaelHouse
sumber
2
Memiliki shader Anda dalam file yang terpisah juga berarti Anda dapat menggunakan editor shader yang berguna dan memiliki penyorotan sintaksis penuh, dan bahkan mempratinjau sebelum mengujinya di program Anda, jika Anda mendukungnya.
Raceimaztion
6
Satu-satunya alasan nyata untuk memiliki shader dalam string adalah untuk tes cepat dan tutorial .. di mana penanganan file menambah sebagian besar "kode yang tidak perlu".
Jari Komppa
2
Anda juga dapat menerapkan hot-reload pada file shader - memungkinkan Anda untuk men-debug perubahan tanpa meluncurkan ulang gim. Produktivitas ++
Liosan
Saya suka ide membaca mereka membentuk file dan memiliki kelas Shader yang terpisah. Melihat mereka selalu dalam sebuah String membingungkan saya karena saya tidak tahu apakah itu cara mereka biasanya didefinisikan atau hanya untuk tujuan belajar. Terima kasih!
miviclin
8

Manajemen Shader (dan karenanya material) adalah masalah yang agak rumit yang Anda hadapi ketika sistem grafis Anda menjadi lebih kompleks dan Anda melihat pengkodean yang keras setiap shader akan menyebabkan duplikasi kode besar-besaran. Berikut adalah beberapa cara alternatif untuk menyelesaikannya:

  • Contoh-contoh kecil di mana hanya ada beberapa shader cenderung mengkodekannya sebagai string untuk menghindari penanganan file sebagaimana dikomentari Jari Komppa
  • Lebih baik menggunakan file terpisah di mana Anda dapat memiliki penyorotan sintaks dan format yang tepat. Anda juga dapat membuat kode sistem debug sederhana yang mengawasi perubahan pada file-file itu dan menerapkan shader yang dimodifikasi saat Anda bermain.
  • Ketika jumlah materi meningkat, generator shader menjadi hampir suatu kebutuhan. Pada dasarnya Anda menentukan cuplikan umum seperti "cuplikan pemetaan fragmen normal shader" dan menyusun shader lengkap Anda dengan memasukkan komponen yang diinginkan.
    • Anda bisa menggunakan snipet string yang dikodekan, tetapi itu menjadi sangat cepat berantakan, jadi sekali lagi file adalah ide yang bagus.
    • Anda dapat memiliki bit kode dalam file terpisah (atau sama) atau sebagai alternatif menggunakan ubershader / supershader di mana Anda menggunakan preprocessor (atau flag seragam) untuk mengaktifkan / menonaktifkan hal-hal.

Adapun atribut dan nama seragam dan semacamnya, Anda hanya menggunakan penamaan yang konsisten di semua shader.

Tapio
sumber
Saya pasti akan memindahkan shader saya ke file terpisah. Terima kasih!
miviclin