在WebGL中用1d纹理替换统一数组时数据损坏

时间:2019-04-16 17:30:27

标签: gpgpu webgl2

我正在WebGL2中的大型4D输入阵列上进行一些GPGPU处理。最初,我只是将输入数组展平并以int的统一数组形式传递,并使用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是包含8位值的Int32Array(因为这是映射到GLSL int所需要的)。

可以,但是严重限制了我可以使用的输入大小。当只有1024个可用于此数据和其他控制输入时,将尺寸扩展为6会导致使用1296个统一插槽。

因此,我想切换到使用纹理来保存大量数据。因此,我已经将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,应用于在GLSL中的纹理采样器对象中提供单通道r值。 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 个答案:

答案 0 :(得分:1)

如果纹理的内部格式为gl.R8,则texelFetch在纹理处返回的值在[0.0,1.0]范围内。

如果要下注[0,255]范围内的值,则必须将这些值乘以255.0:

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);
}

请注意,R8RGB8RGBA8之类的格式是无符号归一化定点格式。颜色值假定为[0.0,1.0]范围内的浮点值,其中最小的可能值0转换为0.0,最大的可能值(2 ^ 8-1 == 255)转换为1.0。

答案 1 :(得分:1)

您使用了R8格式,它是规格化的浮点格式,其值从0.0到1.1。如果要使用int格式,请考虑使用R32I纹理内部格式,以gl.RED_INTEGER格式提供纹理数据,键入gl.INT并使用Int32Array,然后更改采样到isampler2D并使用int r = textureFetch(....).r读取数据。

如果您想要整数结果,还需要为结果制作一个整数纹理,并将其附加到帧缓冲区以呈现整数结果。