перебор большого объема данных во фрагментном шейдере

#glsl #webgl

#glsl #webgl

Вопрос:

Я пытаюсь выполнить итерацию по большому объему данных в моем фрагментном шейдере в webgl. Я хочу передать ему много данных, а затем выполнять итерацию при каждом проходе фрагментного шейдера. Однако у меня возникают некоторые проблемы с этим. Мои идеи были следующими: 1. передайте данные в форме в фрагментный шейдер, но я не могу отправить очень много данных таким образом. 2. используйте буфер для отправки данных, как я делаю verts, в шейдер vert, а затем используйте переменную для отправки данных в шейдер frag. к сожалению, это, похоже, связано с некоторыми проблемами. (а) переменные интерполируются между векторами, и я думаю, что это вызовет проблемы с моим кодом (хотя, возможно, это неизбежно) (б) что еще более важно, я не знаю, как перебирать данные, которые я передаю в свой фрагментный шейдер. Я уже использую буфер для своих координат 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. Для перебора большого количества данных передайте данные в виде текстуры. Текстура — это просто 2D массив данных, к которому вы можете получить случайный доступ.

2. да, это то, что я только что прочитал, но, похоже, я не могу найти какую-либо простую чистую документацию по этому вопросу. Не могли бы вы предоставить какой-нибудь псевдокод или, по крайней мере, рассказать мне, как я ввожу данные во фрагШейдер с помощью небольшого фрагмента кода? Я пытался использовать sampleCube или sample2D, но я думаю, что моя реализация была неверной, и я просто продолжал получать ошибки. О, и могу ли я записать в эту текстуру, если я хочу добавить больше данных во время выполнения?

3. кроме того, как я могу получить доступ к случайному элементу из массива в моем fragShader? на страницах, подобных следующей, похоже, не упоминается, как получить доступ к элементам текстуры: developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial /…

4. Есть функция GLSL, texture2D . Для этого требуется UV-координата. Используйте UV-координату для поиска значения из текстуры.. Также читайте лучшие учебные пособия 😉

5. хорошо, круто, использование текстур позволяет отправлять целые числа со знаком? Мне удалось отправить некоторые данные текстуры, но мне нужны отрицательные целые числа.

Ответ №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> 

Комментарии:

1. Боже, я ненавижу поиск SO. Я знаю, что уже писал этот ответ раньше. Потратил 20 минут на поиск, но не смог его найти