Нельзя l oop в массиве sampler2D после указания контекста WebGL2 в Three. js - PullRequest
0 голосов
/ 20 января 2020

Я использовал массив sampler2D в своем фрагментном шейдере (это карты теней, их может быть до 16, поэтому массив предпочтительнее, чем использование 16 отдельных переменных, конечно). Затем я добавил контекст WebGL2 (const context = canvas.getContext('webgl2');) к THREE.WebGLRenderer, который я использую, и теперь я не могу заставить программу работать: он говорит array index for samplers must be constant integral expressions, когда я пытаюсь получить доступ к элементам массива сэмплера в al oop вот так:

uniform sampler2D samplers[MAX_SPLITS];

for (int i = 0; i < MAX_SPLITS; ++i) {
    if (i >= splitCount) {
        break;
    }

    if (func(samplers[i])) { // that's where the error happens
      ...
    }
}

Неужели нет никакого способа обойти это? Должен ли я использовать шестнадцать отдельных переменных?

(в шейдере нет прямой директивы #version, но ТРИ. js, кажется, добавляет #version 300 es по умолчанию)

1 Ответ

0 голосов
/ 07 февраля 2020

Нельзя использовать динамическое индексирование c с сэмплерами в GLSL ES 3.0. От spe c

12.29 Пробоотборники

Должны ли пробоотборники быть разрешены как l-значения? Спецификация уже допускает эквивалентное поведение:

Текущая спецификация:

uniform sampler2D sampler[8];
int index = f(...);
vec4 tex = texture(sampler[index], xy); // allowed

Использование назначения типов сэмплера:

uniform sampler2D s;
s = g(...);
vec4 tex = texture(s, xy); // not allowed

РАЗРЕШЕНИЕ: Dynami c индексирование сэмплера массивы теперь запрещены по спецификации. Ограничьте индексирование массивов сэмплеров постоянными интегральными выражениями.

и

12.30 Dynami c Индексирование

Для GLSL ES 1.00, поддержка динамических файлов c индексирование массивов, векторов и матриц не было обязательным, поскольку некоторые реализации не поддерживали его напрямую. Программные решения (посредством программных преобразований) существуют для подмножества случаев, но приводят к низкой производительности. Должна ли быть обязательной поддержка динамического индексирования c для GLSL ES 3.00?

РЕШЕНИЕ: поддержка мандатов динамического c индексирования массивов , за исключением массивов сэмплеров , выходных массивов фрагментов и унифицированного блока массивы.

Должна ли поддерживаться динамическая c индексация векторов и матриц в GLSL ES 3.00?

РАЗРЕШЕНИЕ: Да.

Индексирование массивов сэмплеров по константе -index-выражения поддерживаются в GLSL ES 1.00. Постоянное индексное выражение - это выражение, сформированное из константных выражений и определенных индексов l oop, определенных для подмножества конструкций l oop. Должна ли эта функциональность быть включена в GLSL ES 3.00?

РАЗРЕШЕНИЕ: Нет. Массивы сэмплеров могут быть проиндексированы только с помощью константно-интегральных выражений.

Можно ли использовать текстуру 2D_ARRAY для решения вашей проблемы? Поместите каждую из ваших текущих 2D текстур в слой текстуры 2D_ARRAY, тогда координата z - это просто целочисленный индекс слоя. Преимущество: вы можете использовать гораздо больше слоев с 2D_ARRAY, чем получать сэмплеры. Реализации WebGL2 обычно имеют только 32 сэмплера, но допускают сотни или тысячи слоев в текстуре 2D_ARRAY.

или используют GLSL 1.0

const vs1 = `
void main() { gl_Position = vec4(0); }
`;
const vs3 = `#version 300 es
void main() { gl_Position = vec4(0); }
`;
const fs1 = `
precision highp float;

#define MAX_SPLITS 4

uniform sampler2D samplers[MAX_SPLITS];
uniform int splitCount;

bool func(sampler2D s) {
  return texture2D(s, vec2(0)).r > 0.5;
}

void main() {
  float v = 0.0;
  for (int i = 0; i < MAX_SPLITS; ++i) {
      if (i >= splitCount) {
          break;
      }

      if (func(samplers[i])) { // that's where the error happens
         v += 1.0;
      }
  }
  gl_FragColor = vec4(v);
}
`;

const fs3 = `#version 300 es
precision highp float;

#define MAX_SPLITS 4

uniform sampler2D samplers[MAX_SPLITS];
uniform int splitCount;

bool func(sampler2D s) {
  return texture(s, vec2(0)).r > 0.5;
}

out vec4 color;

void main() {
  float v = 0.0;
  for (int i = 0; i < MAX_SPLITS; ++i) {
      if (i >= splitCount) {
          break;
      }

      if (func(samplers[i])) { // that's where the error happens
         v += 1.0;
      }
  }
  color = vec4(v);
}
`;

function main() {
  const gl = document.createElement('canvas').getContext('webgl2');
  if (!gl) {
    return alert('need WebGL2');
  }
  
  test('glsl 1.0', vs1, fs1);
  test('glsl 3.0', vs3, fs3);
  
  function test(msg, vs, fs) {
    const p = twgl.createProgram(gl, [vs, fs]);
    log(msg, ':', p ? 'success' : 'fail');
  }
}
main();


function log(...args) {
  const elem = document.createElement('pre');
  elem.textContent = [...args].join(' ');
  document.body.appendChild(elem);
}
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
...