Можно ли получить доступ к предварительно установленным блокам текстуры в шейдере? - PullRequest
0 голосов
/ 10 июля 2020

TL; DR: Я активировал и привязал текстуры к текстурным блокам 1-4, и теперь я использую sh, чтобы использовать их в шейдерах без использования c единой позиции программы. Можно ли читать данные из текстур, используя «глобальные» текстурные блоки?

Мне немного сложно понять, как получить доступ к текстурам в webgl. Здесь, в этом руководстве по текстурам , говорится: « Текстурные блоки - это глобальный массив ссылок на текстуры. », и это звучит великолепно. Я связал свои текстуры, используя

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

, где i - это индекс вновь созданной текстуры, а tex - сама текстура.

Но это не дает пример того, как получить доступ к текстуре в шейдере с помощью этой глобальной ссылки. В этом руководстве с той же страницы он дает пример того, как получить доступ к текстурам из шейдера, но только при использовании единообразной позиции (так же, как доступ к атрибуту), для чего требуется программа (и, таким образом, в некотором смысле удаляя глобальный аспект, поскольку он зависит от программы, к которой будет осуществляться доступ). В в этом предыдущем руководстве любые подробности о том, как на самом деле настроить текстуру «u_texture», вообще пропущены.

Короче говоря, у меня есть две программы, и я sh использую текстуры глобально в обоих из них без необходимости getUniformLocation для каждой программы, если это возможно. Увидев обещания текстурных блоков, я подумал, что могу их использовать, но я не знаю, как на самом деле сделать что-то вроде

sampler2D textureUnit2;

в шейдерах. Это возможно? Не путаю ли я реализацию textureUnits с практичностью их использования?

Большое спасибо!

1 Ответ

1 голос
/ 11 июля 2020

Я буду sh использовать текстуры глобально в обоих из них без необходимости getUniformLocation в каждой программе, если это возможно

Это не это возможно.

Текстурные блоки глобальные. Вы можете думать об этом как о глобальном массиве в JavaScript

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

. Вы можете привязать текстуру к текстурному модулю, сначала вызвав gl.activeTexture, а затем gl.bindTexture. Пример:

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

yetAnotherTexture теперь привязан к текстурному блоку 2

Отдельно у вас есть шейдерные программы. Чтобы получить доступ к текстуре, вы объявляете uniform sampler2d someName; в своем шейдере.

uniform sampler2D foobar;

Думайте об этом как об индексе в текстурных модулях. Затем вам нужно установить индекс (указать программе шейдера, какой глобальный блок текстуры использовать)

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

Сами текстурные блоки являются глобальными. Униформа программы уникальна для каждой программы. Вы должны указать им, на какой блок текстуры вы хотите ссылаться. По умолчанию для униформ установлено значение 0, поэтому, если вы хотите, чтобы они ссылались на текстурный блок 0, вам не нужно их устанавливать, но для любого другого текстурного блока вам нужно их установить.

Представьте, что функция GLSL texture2D была написана в JavaScript. Это будет работать примерно так:

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

Итак, если бы я сделал это

uniform sampler2D foobar;
varying vec2 v_texcoord;

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

Тогда я установил бы foobar uniform на 2

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

Это будет ссылка на глобальный блок текстуры с индексом 2.

Примечание: этот код в вашем вопросе

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

кажется неправильным. Он должен использовать TEXTURE0 в качестве основы, а не TEXTURE1

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

Эта диаграмма может помочь визуализировать, как это работает

введите описание изображения здесь

Выше вы можете увидеть, что программа шейдера (золото) имеет две формы: decal и diffuse.

  • decal установлено на 3, поэтому ссылка на блок текстуры 3. Блок текстуры 3 привязан к decalTexture (изображение F).

  • diffuse установлен на 6, поэтому он ссылается на блок текстуры 6. Блок текстуры 3 привязан к diffuseTexture (шахматная доска 4x4)

Обратите внимание, что блок текстуры 0 также привязан к decalTexture, но программа шейдера не ссылается на блок текстуры 0, поэтому по крайней мере, для отрисовки пикселей, другими словами при выполнении программы шейдера, блок текстуры 0 не используется.

...