我正在WebGL2中进行GPGPU编程,我通过将其打包到纹理中以绕过统一的计数限制,将大型4维正方形数组传递给我的着色器。使自己不必使用相对较小的固定大小的数组,我希望能够指定实际以编程方式传递的数据的大小。
以前,我已经使用const int
对要读取的数据大小进行了硬编码,如下所示:
const int SIZE = 5;
const int SIZE2 = SIZE*SIZE;
const int SIZE3 = SIZE2*SIZE;
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 * 255.0);
}
如果我将SIZE2
和SIZE3
更新为非常量并在main中初始化,它仍然可以工作:
const int SIZE = 5;
int SIZE2;
int SIZE3;
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 * 255.0);
}
...
void main(){
SIZE2 = SIZE*SIZE;
SIZE3 = SIZE*SIZE2;
...
}
但是,如果我然后将const int SIZE = 5;
替换为uniform int SIZE;
,然后添加
const size_loc = gl.getUniformLocation(program, "SIZE");
gl.uniform1i(size_loc, 5);
在JavaScript端将其设置为以前用于硬编码的整数值,我开始看到从纹理读取了不正确的值。我在做什么错了?
更新1:我做了一个小实验,在其中我保持常数SIZE
的规范,但同时在它旁边传递了一个统一的int值。如果它们不相等,则使着色器退出,并返回所有零。这样,我可以验证是否确实在统一变量上设置了正确的整数值,但是,如果我随后使SIZE
为非常数,然后将其设置为统一变量的值,则只是被比较并发现是相等的,然后事情就破裂了。什么鬼?
更新2:
这有效:
int SIZE = 5;
uniform int u_size;
....
void main() {
if (u_size != SIZE) return;
SIZE = u_size;
...
}
这不是:
int SIZE = 5;
uniform int u_size;
....
void main() {
SIZE = u_size;
...
}
答案 0 :(得分:0)
我无法重现您的问题。在minimal, complete, verifiable, example
中发布snippet这是一个可行的例子
const vs = `#version 300 es
void main() {
gl_PointSize = 1.0;
gl_Position = vec4(0, 0, 0, 1);
}
`;
const fs = `#version 300 es
precision highp float;
uniform ivec4 cell;
uniform int SIZE;
int SIZE2;
int SIZE3;
uniform highp isampler2D u_map;
int get_cell(ivec4 m){
ivec4 i = m % SIZE;
int r = texelFetch(u_map, ivec2(i.x*SIZE3 + i.y*SIZE2 + i.z*SIZE + i.w, 0), 0).r;
return r;
}
out int result;
void main(){
SIZE2 = SIZE*SIZE;
SIZE3 = SIZE*SIZE2;
result = get_cell(cell);
}
`;
const gl = document.createElement('canvas').getContext('webgl2');
// compile shaders, link, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
// make a 1x1 R32I texture and attach to framebuffer
const framebufferInfo = twgl.createFramebufferInfo(gl, [
{ internalFormat: gl.R32I, minMag: gl.NEAREST, },
], 1, 1);
const size = 5;
const totalSize = size * size * size * size;
const data = new Int32Array(totalSize);
for (let i = 0; i < data.length; ++i) {
data[i] = 5 + i * 3;
}
// create a size*size*size*size by 1
// R32I texture
const tex = twgl.createTexture(gl, {
width: totalSize,
src: data,
minMag: gl.NEAREST,
internalFormat: gl.R32I,
});
gl.bindFramebuffer(gl.FRAMEBUFFER, framebufferInfo.framebuffer);
gl.viewport(0, 0, 1, 1);
gl.useProgram(programInfo.program);
const result = new Int32Array(1);
for (let w = 0; w < size; ++w) {
for (let z = 0; z < size; ++z) {
for (let y = 0; y < size; ++y) {
for (let x = 0; x < size; ++x) {
// calls gl.activeTexture, gl.bindTexture, gl.uniformXXX
twgl.setUniforms(programInfo, {
cell: [x, y, z, w],
u_map: tex,
SIZE: size,
});
gl.drawArrays(gl.POINTS, 0, 1); // draw 1 point
gl.readPixels(0, 0, 1, 1, gl.RED_INTEGER, gl.INT, result);
log(x, y, z, w, ':', result[0], data[x * size * size * size + y * size * size + z * size + w]);
}
}
}
}
function log(...args) {
const elem = document.createElement('pre');
elem.textContent = [...args].join(' ');
document.body.appendChild(elem);
}
pre { margin: 0; }
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
尝试使用您发布的代码,我也没有发现问题
const vs = `#version 300 es
void main() {
gl_PointSize = 1.0;
gl_Position = vec4(0, 0, 0, 1);
}
`;
const fs = `#version 300 es
precision highp float;
uniform vec4 cell;
uniform int SIZE;
int SIZE2;
int SIZE3;
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 * 255.0);
}
out float result;
void main(){
SIZE2 = SIZE*SIZE;
SIZE3 = SIZE*SIZE2;
// output to texture is normalized float
result = float(get_cell(cell)) / 255.0;
}
`;
const gl = document.createElement('canvas').getContext('webgl2');
// compile shaders, link, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const size = 5;
const totalSize = size * size * size * size;
const data = new Uint8Array(totalSize);
for (let i = 0; i < data.length; ++i) {
data[i] = (5 + i * 3) % 256;
}
// create a size*size*size*size by 1
// R8 texture
const tex = twgl.createTexture(gl, {
width: totalSize,
src: data,
minMag: gl.NEAREST,
internalFormat: gl.R8,
});
gl.viewport(0, 0, 1, 1);
gl.useProgram(programInfo.program);
const result = new Uint8Array(4);
for (let w = 0; w < size; ++w) {
for (let z = 0; z < size; ++z) {
for (let y = 0; y < size; ++y) {
for (let x = 0; x < size; ++x) {
// calls gl.activeTexture, gl.bindTexture, gl.uniformXXX
twgl.setUniforms(programInfo, {
cell: [x, y, z, w],
u_map: tex,
SIZE: size,
});
gl.drawArrays(gl.POINTS, 0, 1); // draw 1 point
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, result);
log(x, y, z, w, ':', result[0], data[x * size * size * size + y * size * size + z * size + w]);
}
}
}
}
function log(...args) {
const elem = document.createElement('pre');
elem.textContent = [...args].join(' ');
document.body.appendChild(elem);
}
pre { margin: 0; }
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
请注意,由于尺寸受到限制,因此我不会使用1维纹理。我会使用3D纹理来增加限制
const vs = `#version 300 es
void main() {
gl_PointSize = 1.0;
gl_Position = vec4(0, 0, 0, 1);
}
`;
const fs = `#version 300 es
precision highp float;
uniform ivec4 cell;
uniform int SIZE;
uniform highp isampler3D u_map;
int get_cell(ivec4 m){
// no idea why you made x major
ivec4 i = m % SIZE;
int r = texelFetch(
u_map,
ivec3(
i.z * SIZE + i.w,
i.yx),
0).r;
return r;
}
out int result;
void main(){
result = get_cell(cell);
}
`;
const gl = document.createElement('canvas').getContext('webgl2');
// compile shaders, link, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
// make a 1x1 R32I texture and attach to framebuffer
const framebufferInfo = twgl.createFramebufferInfo(gl, [
{ internalFormat: gl.R32I, minMag: gl.NEAREST, },
], 1, 1);
const size = 5;
const totalSize = size * size * size * size;
const data = new Int32Array(totalSize);
for (let i = 0; i < data.length; ++i) {
data[i] = 5 + i * 3;
}
// create a size*size*size*size by 1
// R32I texture 3D
const tex = twgl.createTexture(gl, {
target: gl.TEXTURE_3D,
width: size * size,
height: size,
src: data,
minMag: gl.NEAREST,
internalFormat: gl.R32I,
});
gl.bindFramebuffer(gl.FRAMEBUFFER, framebufferInfo.framebuffer);
gl.viewport(0, 0, 1, 1);
gl.useProgram(programInfo.program);
const result = new Int32Array(1);
for (let w = 0; w < size; ++w) {
for (let z = 0; z < size; ++z) {
for (let y = 0; y < size; ++y) {
for (let x = 0; x < size; ++x) {
// calls gl.activeTexture, gl.bindTexture, gl.uniformXXX
twgl.setUniforms(programInfo, {
cell: [x, y, z, w],
u_map: tex,
SIZE: size,
});
gl.drawArrays(gl.POINTS, 0, 1); // draw 1 point
gl.readPixels(0, 0, 1, 1, gl.RED_INTEGER, gl.INT, result);
log(x, y, z, w, ':', result[0], data[x * size * size * size + y * size * size + z * size + w]);
}
}
}
}
function log(...args) {
const elem = document.createElement('pre');
elem.textContent = [...args].join(' ');
document.body.appendChild(elem);
}
pre { margin: 0; }
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>