在片段着色器中迭代大量数据

时间:2019-04-16 15:42:15

标签: glsl webgl

我正在尝试遍历webgl的片段着色器中的大量数据。我想向它传递大量数据,然后在片段着色器的每次传递中进行迭代。我在这样做时遇到了一些问题。我的想法如下: 1.将制服中的数据传递到碎片着色器,但是我不能以这种方式发送很多数据。 2.使用缓冲区将数据发送到vert着色器,然后将其发送到fragder着色器。不幸的是,这似乎涉及一些问题。 (a)向量之间的插值变化,我认为这会导致我的代码出现问题(尽管这是不可避免的)(b)更重要的是,我不知道如何迭代传递给片段着色器的数据。我已经在使用3d点坐标的缓冲区,但是webgl如何处理第二个缓冲区和通过它的数据。

*我的意思是说,从每个缓冲区(我的第一个缓冲区包含3d坐标,而我要添加的第二个缓冲区)中提取数据的顺序是什么?最后,如上所述,如果我想遍历每次通过片段着色器传递的所有数据,该怎么办? *

我已经尝试过使用统一数组,并且在片段着色器中对其进行迭代,但是我遇到了限制,因为统一的大小限制相对较小。我目前正在尝试上述第二种方法。

//pseudo code

vertexCode = `

attribute vec4 3dcoords;
varying vec4 3dcoords;

??? ??? my_special_data;


void main(){...}

`


fragCode = `

varying vec4 3dcoords;

void main(){

...

// perform math operation on 3dcoords for all values in my_special_data variable and store in variable my_results

if( my_results ... ){

gl_FragColor += ...;

}

`

1 个答案:

答案 0 :(得分:1)

WebGL中的纹理是随机访问的2D数据数组,因此您可以使用它们读取大量数据 示例:

const width = 256;
const height = 256;
const vs = `
attribute vec4 position;
void main() {
  gl_Position = position;
}
`;
const fs = `
precision highp float;
uniform sampler2D tex;
const int width = ${width};
const int height = ${height};
void main() {
  vec4 sums = vec4(0);
  for (int y = 0; y < height; ++y) {
    for (int x = 0; x < width; ++x) {
      vec2 xy = (vec2(x, y) + 0.5) / vec2(width, height);
      sums += texture2D(tex, xy);
    }
  }
  gl_FragColor = sums;
}
`;

function main() {
  const gl = document.createElement('canvas').getContext('webgl');
  // check if we can make floating point textures
  const ext1 = gl.getExtension('OES_texture_float');
  if (!ext1) {
    return alert('need OES_texture_float');
  }
  // check if we can render to floating point textures
  const ext2 = gl.getExtension('WEBGL_color_buffer_float');
  if (!ext2) {
    return alert('need WEBGL_color_buffer_float');
  }

  // make a 1x1 pixel floating point RGBA texture and attach it to a framebuffer
  const framebufferInfo = twgl.createFramebufferInfo(gl, [
    { type: gl.FLOAT, },
  ], 1, 1);
  
  // make random 256x256 texture
  const data = new Uint8Array(width * height * 4);
  for (let i = 0; i < data.length; ++i) {
    data[i] = Math.random() * 256;
  }
  const tex = twgl.createTexture(gl, {
    src: data,
    minMag: gl.NEAREST,
    wrap: gl.CLAMP_TO_EDGE,
  });
  
  // compile shaders, link, lookup locations
  const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
  
  // create a buffer and put a 2 unit
  // clip space quad in it using 2 triangles
  const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
    position: {
      numComponents: 2,
      data: [
        -1, -1,
         1, -1,
        -1,  1,
        -1,  1,
         1, -1,
         1,  1,
      ],
    },
  });

  // render to the 1 pixel texture
  gl.bindFramebuffer(gl.FRAMEBUFFER, framebufferInfo.framebuffer);
  // set the viewport for 1x1 pixels
  gl.viewport(0, 0, 1, 1);
  gl.useProgram(programInfo.program);
  // calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
  twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
  // calls gl.activeTexture, gl.bindTexture, gl.uniformXXX
  twgl.setUniforms(programInfo, {
    tex,
  });
  const offset = 0;
  const count = 6;
  gl.drawArrays(gl.TRIANGLES, offset, count);

  // read the result
  const pixels = new Float32Array(4);
  gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.FLOAT, pixels);
  console.log('webgl sums:', pixels);
  const sums = new Float32Array(4);
  for (let i = 0; i < data.length; i += 4) {
    for (let j = 0; j < 4; ++j) {
      sums[j] += data[i + j] / 255;
    }
  }
  console.log('js sums:', sums);
}

main();
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>