Повреждение данных при замене единого массива на 1d текстуру в WebGL - PullRequest
1 голос
/ 16 апреля 2019

Я выполняю некоторую обработку GPGPU на большом входном массиве 4D в WebGL2.Первоначально я просто сгладил входной массив и передал его как единый массив целых чисел с пользовательской функцией доступа в GLSL для преобразования 4D-координат в индекс массива следующим образом:

const int SIZE = 5; // The largest dimension that works; if I can switch to textures, this will be passed in as a uniform value.
const int SIZE2 = SIZE*SIZE;
const int SIZE3 = SIZE*SIZE2;
const int SIZE4 = SIZE*SIZE3;
uniform int u_map[SIZE4];

int get_cell(vec4 m){
  ivec4 i = ivec4(mod(m,float(SIZE)));
  return u_map[i.x*SIZE3+i.y*SIZE2+i.z*SIZE+i.w];
}

В JavaScriptКроме того, сглаженные данные передаются следующим образом:

const map_loc = gl.getUniformLocation(program, "u_map");
gl.uniform1iv(map_loc, data);

Где data - это Int32Array (потому что это то, что требуется для отображения на целочисленные значения GLSL), содержащее 8-битные значения.

Это работает, но сильно ограничивает размер входов, с которыми я могу работать.Увеличение размера до 6 приводит к использованию 1296 одинаковых слотов, когда для этих данных и других управляющих входов доступно только 1024.

Итак, я хочу перейти к использованию текстуры для хранения больших количествданные.Итак, я обновил код JS следующим образом:

const tex = gl.createTexture();
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.R8, data.length, 1, 0, gl.RED, gl.UNSIGNED_BYTE, data);

, где data был переупакован как Uint8Array, который должен использоваться для предоставления одноканальных значений r в текстуреобъект сэмплера в GLSL.Код GLSL обновляется следующим образом:

uniform sampler2D u_map;

int get_cell(vec4 m){
  ivec4 i = ivec4(mod(m,float(SIZE)));
  float r = texelFetch(u_map, ivec2(i.x*SIZE3+i.y*SIZE2+i.z*SIZE+i.w, 0), 0).r;
  return int(r);
}

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

Однако после выполненияэта замена, я просто получаю мусор.Значения, возвращаемые из get_cell, кажутся равными 1 или 0, и ни одно из них даже надежно не соответствует наличию фактических значений 1 или 0 в исходном буфере данных.

Что я делаю неправильно

Ответы [ 2 ]

1 голос
/ 16 апреля 2019

Вы использовали формат R8, который является нормализованным форматом с плавающей запятой со значениями от 0,0 до 1,1. Если вы хотите использовать формат int, подумайте об использовании внутреннего формата текстуры R32I, предоставьте данные текстуры в формате gl.RED_INTEGER, введите gl.INT и используйте Int32Array, измените свой сэмплер на isampler2D и используйте int r = textureFetch(....).r чтобы прочитать данные.

Если вы хотите получить целочисленный результат, вам также нужно будет создать целочисленную текстуру для результатов и прикрепить ее к кадровому буферу для получения целочисленных результатов.

1 голос
/ 16 апреля 2019

Если внутренний формат текстуры gl.R8, то значения, возвращаемые при поиске текстуры на texelFetch, находятся в диапазоне [0.0, 1.0].

Вы должны умножить значения на 255,0, если хотите поставить значения в диапазоне [0, 255]:

int get_cell(vec4 m){
    ivec4 i = ivec4(mod(m,float(SIZE)));
    float r = texelFetch(u_map, ivec2(i.x*SIZE3+i.y*SIZE2+i.z*SIZE+i.w, 0), 0).r;
    return int(r * 255.0);
}

Обратите внимание, форматы, такие как R8,RGB8 и RGBA8 - нормализованный формат с фиксированной запятой без знака.Предполагается, что значения цвета являются значениями с плавающей точкой в ​​диапазоне [0,0, 1,0], где наименьшее возможное значение 0 преобразуется в 0,0, а наибольшее возможное значение (2 ^ 8-1 == 255) преобразуется в 1,0.

...