Выражение индекса должно быть постоянным - ошибка WebGL / GLSL

У меня возникли проблемы с доступом к массиву в фрагментном шейдере с использованием непостоянного int в качестве индекса. Я удалил формулу, так как в любом случае это не имело бы особого смысла, но мой код предназначен для вычисления tileID на основе текущего пикселя и использования его для определения цвета.

Вот мой код:

int tileID = <Insert formula here>;

vec3 colorTest;

int arrayTest[1024];
for (int x = 0; x < 1024; x++) {
    if (x == 1) arrayTest[x] = 1;
    else arrayTest[x] = 2;
}

if (arrayTest[tileID] == 1) colorTest = vec3(0.0, 1.0, 0.0);
else if (arrayTest[tileID] == 2) colorTest = vec3(1.0, 0.0, 0.0);
else colorTest = vec3(0.0, 0.0, 0.0);

Видимо GLSL это не нравится, и я получаю сообщение об ошибке:

'[]': Индексное выражение должно быть постоянным.

Кто-нибудь знает, как бы это исправить? Спасибо.


person Joey Morani    schedule 22.10.2013    source источник


Ответы (3)


В качестве фона - GLSL очень похож на C, но компилируется немного иначе. Вещи очень развернуты, и условные выражения могут выполняться параллельно и переключаться в конце, что-то в этом роде. Зависит от оборудования ...

Вы можете использовать индексы цикла или константы для индексации в массивы. Назначение в вашем цикле в порядке, но доступ по tileID - нет.

Язык шейдеров WebGL взят из GLES, задокументирован

http://www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf

Приложение, раздел 5, обсуждает:

Indexing of Arrays, Vectors and Matrices
Definition:
constant-index-expressions are a superset of constant-expressions. Constant-index-expressions can include loop indices as defined in Appendix A section 4.
The following are constant-index-expressions:
• Constant expressions
• Loop indices as defined in section 4
• Expressions composed of both of the above
When used as an index, a constant-index-expression must have integral type.

Надеюсь, это поможет!


О, что касается его исправления, в точном примере выше ... похоже, вы могли бы вычислить из tileID, а не предварительно вычислить и индексировать.

Или предварительно вычислите любой массив, который вам нравится, и передайте его как текстуру. Текстуру, конечно, можно индексировать как угодно.

Вот вспомогательный метод javascript, который я использую для передачи числа с плавающей запятой в шейдеры:

function glSetupStuff() { ...
...
if(!gl.getExtension("OES_texture_float"))   // <<-- enables RGBA float values, handy!
    alert("cant pass in floats, use 8-bit values instead.");
... }

/*
 * Pass in an array of rgba floats,
 * for example: var data = new Float32Array([0.1,0.2,0.3,1,  .5,.5,1.0,1]);
 */
function textureFromFloats(gl,width,height,float32Array) 
{
var oldActive = gl.getParameter(gl.ACTIVE_TEXTURE);
gl.activeTexture(gl.TEXTURE15); // working register 31, thanks.

var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);

gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 
                width, height, 0, 
                gl.RGBA, gl.FLOAT, float32Array);

gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.bindTexture(gl.TEXTURE_2D, null);

gl.activeTexture(oldActive);

return texture;
}

Обратите внимание на использование gl.NEAREST, чтобы он не «размывал» ваши значения! Затем вы можете настроить его перед вызовом gl.drawXxx, например,

textureUnit = 3;  // from 0 to 15 is ok
gl.activeTexture(gl.TEXTURE0 + textureUnit);
gl.bindTexture(gl.TEXTURE_2D, texture);

var z = gl.getUniformLocation(prog, "uSampler");
gl.uniform1i(z, textureUnit);

И в шейдере (я считаю, что это фрагмент или вершина; некоторые более ранние версии webgl не поддерживали текстуры вершин ...)

uniform sampler2D uSampler;
...
vec4 value = texture2D(uSampler, vec2(xValueBetween0And1,yValueBetween0And1));

Таким образом, вы должны индексировать соответственно размер массива как текстуры в диапазоне от 0 до 1. Попробуйте выполнить выборку из середины каждого значения / пикселя. Например, если массив имеет ширину 2 значения, индексируйте на 0,25 и 0,75.

В этом суть!

person david van brink    schedule 22.10.2013
comment
Ах, похоже, здесь тот же вопрос, stackoverflow.com/questions/6247572/ - person david van brink; 23.10.2013
comment
Спасибо, Дэвид. Я думаю, что лучше всего передать данные в виде текстуры. Не могли бы вы объяснить, как я бы это сделал, или указать мне правильное направление? Я предполагал, что текстуры предназначены только для изображений. Спасибо еще раз. - person Joey Morani; 23.10.2013
comment
Добавлен код, чтобы показать, как это сделать ... Да, текстуры обычно предназначены для изображений, но если вы отключите интерполяцию, ваш шейдер сможет надежно получить доступ к любому пикселю в нем и к тому, что вы вставляете в R, G, B, и слоты на ваше усмотрение. Вы можете передавать значения с плавающей запятой на большинстве оборудования, так что здесь есть большая гибкость! - person david van brink; 25.10.2013
comment
@ Joey.Morani: Также обратите внимание, что тип разрешенной индексации массива зависит от типа ресурса и стадии шейдера. Например, в вершинном шейдере в OpenGL ES 2.0 вы можете индексировать однородный массив, используя неконстантное целочисленное выражение. Во фрагментном шейдере он должен быть const-index (скорее, он должен это поддерживать - однако реализации могут выходить за рамки этого требования). Это подробно объясняется в официальной спецификации GLSL. ‹Стр. 109-110 - A.5 ›, возможно, стоит прочитать ... - person Andon M. Coleman; 26.10.2013
comment
Спасибо, Андон! Не знал этого. Еще один способ решить возникшую у меня проблему. :) - person Joey Morani; 27.10.2013
comment
Pixi.js кто-нибудь? :( Мне нужно решить эту проблему, но все решения используют необработанный webGL. - person Tomáš Zato - Reinstate Monica; 28.10.2015
comment
Это было полезно и правильно в отношении индексации, но мне любопытно, есть ли у кого-нибудь совет, как избежать зависимого чтения текстур (stackoverflow.com/a/27028431/827441) при использовании этой реализации. Похоже, что извлечение значений из этой текстуры данных будет составлять зависимую текстуру, прочитанную в любом случае, когда «положение x / y» ваших данных не было точно таким же, как у вашего фрагмента. - person bradleygriffith; 19.01.2016
comment
Это правда, да ... использование текстуры для передачи таких данных является точным зависимым чтением текстуры. Это (должно быть?) Такое же влияние на производительность, как и любой другой способ передачи массива данных. Если текстура читается в вершинном шейдере, то это совсем неплохо. // Как упоминалось в вопросе SO, который вы цитируете, в настоящее время чтение зависимых текстур не является большим злом. - person david van brink; 19.01.2016

Протестировано в Safari 9.1.2 на OS X 10.11.6

uniform float data[32];

float getData(int id) {
    for (int i=0; i<32; i++) {
        if (i == id) return data[i];
    }
}

void main(void) {
    float f = getData(yourVariable);
}
person asdf    schedule 20.08.2016
comment
В Chrome: 'i' : Loop index cannot be compared with non-constant expression - person Sturm; 24.06.2019

Я столкнулся с этой ошибкой, потому что пытался использовать целочисленную переменную, чтобы взять n-ю текстуру из массива текстур:

// this doesn't compile!

varying vec2 vUv; // uv coords
varying float vTexture; // texture index in array of textures

uniform sampler2D textures[3]; // identify that there are 3 textures

void main() {
  int textureIndex = int(floor(vTexture));
  gl_FragColor = texture2D(textures[textureIndex], vUv);
}

Решением было разбить индексирование текстуры на последовательность условных выражений:

// this compiles!

varying vec2 vUv; // uv coords
varying float vTexture; // texture index in array of textures

uniform sampler2D textures[3]; // identify that there are 3 textures

void main() {
  int textureIndex = int(floor(vTexture));
  if (textureIndex == 0) {
    gl_FragColor = texture2D(textures[0], vUv);
  } else if (textureIndex == 1) {
    gl_FragColor = texture2D(textures[1], vUv);
  } else if (textureIndex == 2) {
    gl_FragColor = texture2D(textures[2], vUv);
  } 
}
person duhaime    schedule 30.04.2018
comment
Кто-нибудь может сказать что-нибудь о производительности этого решения? - person wilddev; 24.02.2021
comment
@wilddev Чтобы ускорить это, можно, конечно, изменить условную последовательность на алгоритм двоичного поиска. Я не знаю более быстрого способа, но если вы столкнетесь с другим потенциальным подходом, я буду рад изучить его! - person duhaime; 24.02.2021