我正在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值。
我在做什么错了?
答案 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);
}
请注意,R8
,RGB8
和RGBA8
之类的格式是无符号归一化定点格式。颜色值假定为[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
读取数据。
如果您想要整数结果,还需要为结果制作一个整数纹理,并将其附加到帧缓冲区以呈现整数结果。