使用统一值替换GLSL常量时数据损坏

问题描述 投票:0回答:1

跟进this recent question

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

如果我将SIZE2SIZE3更新为非常量并在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;
  ...
}
gpgpu webgl2
1个回答
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维纹理,因为尺寸有限制。我会使用3维纹理来增加限制

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>
© www.soinside.com 2019 - 2024. All rights reserved.