TL;DR: Saya telah mengaktifkan dan mengikat tekstur ke unit tekstur 1-4 dan sekarang saya ingin menggunakannya dalam shader tanpa menggunakan posisi seragam khusus program. Apakah mungkin membaca data dari tekstur menggunakan unit tekstur "global"?

Saya mengalami sedikit kesulitan memahami cara mengakses tekstur di webgl. Di sini, di tutorial tentang tekstur ini tertulis "Unit tekstur adalah kumpulan referensi global untuk tekstur.", dan ini terdengar bagus. Saya telah mengikat tekstur saya menggunakan

gl.activeTexture(gl.TEXTURE1 + i);
gl.bindTexture(gl.TEXTURE_2D, tex);

Di mana i adalah indeks dari tekstur yang baru dibuat dan tex adalah tekstur itu sendiri.

Tapi itu tidak memberikan contoh bagaimana mengakses tekstur di dalam shader menggunakan referensi global ini. Dalam tutorial ini dari halaman yang sama ini memberikan contoh bagaimana untuk mengakses tekstur dari dalam shader, tetapi hanya ketika menggunakan posisi yang seragam (seperti bagaimana atribut diakses), yang memerlukan program (dan dengan demikian, menghapus aspek global, dengan cara, karena bergantung pada program untuk diakses). Dalam tutorial sebelumnya ini detail tentang cara menyiapkan tekstur "u_texture" dilewati sama sekali.

Singkatnya, saya memiliki dua program, dan saya ingin menggunakan tekstur secara global di keduanya tanpa harus mendapatkanUniformLocation di setiap program, jika memungkinkan. Melihat janji unit tekstur, saya pikir saya bisa menggunakannya, tetapi saya tidak tahu bagaimana melakukan sesuatu seperti

sampler2D textureUnit2;

Dalam shader. Apakah ini mungkin? Apakah saya membingungkan penerapan textureUnits dengan kepraktisan menggunakannya?

Terimakasih banyak!

0
baal_imago 10 Juli 2020, 17:06

1 menjawab

Jawaban Terbaik

Saya ingin menggunakan tekstur secara global di keduanya tanpa harus mendapatkanUniformLocation di setiap program, jika memungkinkan untuk melakukannya

Hal ini tidak mungkin dilakukan.

Unit tekstur bersifat global. Anda dapat menganggapnya seperti array global dalam JavaScript

const textureUnits = [
  { TEXTURE_2D: someTexture, },       // unit 0
  { TEXTURE_2D: someOtherTexture, },  // unit 1
  { TEXTURE_2D: yetAnotherTexture, }, // unit 2
  ...
];

Anda dapat mengikat tekstur ke unit tekstur dengan terlebih dahulu memanggil gl.activeTexture lalu memanggil gl.bindTexture. Contoh:

const unit = 2;
gl.activeTexture(gl.TEXTURE0 + unit);
gl.bindTexture(gl.TEXTURE_2D, yetAnotherTexture);

yetAnotherTexture sekarang terikat ke unit tekstur 2

Secara terpisah Anda memiliki program shader. Untuk mengakses tekstur, Anda mendeklarasikan uniform sampler2d someName; di shader Anda.

uniform sampler2D foobar;

Anggap itu sebagai indeks ke dalam unit tekstur. Anda kemudian perlu mengatur indeks (beri tahu program shader unit tekstur global mana yang akan digunakan)

const foobarLocation = gl.getUniformLocation(someProgram, "foobar");
...
// tell the program to use the texture on unit 2
const indexOfTextureUnit = 2;
gl.uniform1i(foobarLocation, indexOfTextureUnit);

Unit tekstur itu sendiri bersifat global. Seragam program adalah unik untuk setiap program. Anda perlu mengaturnya untuk memberi tahu mereka unit tekstur mana yang Anda inginkan untuk referensi seragam itu. Seragam default ke 0 jadi jika Anda ingin mereka mereferensikan unit tekstur 0 maka Anda tidak perlu mengaturnya tetapi untuk unit tekstur lainnya Anda perlu mengaturnya.

Bayangkan fungsi texture2D GLSL ditulis dalam JavaScript. Itu akan bekerja seperti

function texture2d(sampler, texcoord) {
  const texture = textureUnits[sampler].TEXTURE_2D;
  return getColorFromTextureAtTexcoord(texture, texcoord);
}

Jadi jika saya melakukan ini

uniform sampler2D foobar;
varying vec2 v_texcoord;

void main() {
  gl_FragColor = texture2D(foobar, v_texcoord);
}

Lalu saya mengatur seragam foobar menjadi 2

const foobarLocation = gl.getUniformLocation(someProgram, "foobar");
...
// tell the program to use the texture on unit 2
const indexOfTextureUnit = 2;
gl.uniform1i(foobarLocation, indexOfTextureUnit);

Ini akan merujuk unit tekstur global pada indeks 2.

Catatan: Kode ini dalam pertanyaan Anda

gl.activeTexture(gl.TEXTURE1 + i);
gl.bindTexture(gl.TEXTURE_2D, tex);

Tampaknya salah. Itu harus menggunakan TEXTURE0 sebagai basis, bukan TEXTURE1

gl.activeTexture(gl.TEXTURE0 + i);
gl.bindTexture(gl.TEXTURE_2D, tex);

Diagram ini dapat membantu memvisualisasikan cara kerjanya

enter image description here

Di atas Anda dapat melihat program shader (emas) memiliki dua seragam decal dan diffuse.

  • decal disetel ke 3 sehingga mereferensikan unit tekstur 3. unit tekstur 3 terikat ke decalTexture (gambar dari F)

  • diffuse disetel ke 6 sehingga mereferensikan unit tekstur 6. unit tekstur 3 terikat ke diffuseTexture (kotak-kotak 4x4)

Perhatikan bahwa unit tekstur 0 juga terikat pada decalTexture tetapi program shader tidak merujuk unit tekstur 0 jadi setidaknya untuk tujuan menggambar piksel, dengan kata lain menjalankan program shader, unit tekstur 0 tidak digunakan .

1
gman 11 Juli 2020, 06:08