Webgl: Stride не работает. Не проходит мимо значений в буфере

Я делаю аттрактор Лоренца в webgl и вообще играю с многомерными странными аттракторами. Я сделал для этого систему частиц, основанную на webgl, которая по большей части работает нормально. Система частиц работает, отображая значения x и y gl.POINTS, сохраняя при этом более высокие измерения в том же буфере для вычисления их соответствующей производной. Пример буфера: x=buffer[i], y=buffer[i+1], z=buffer[i+2], w=buffer[i+3] и так далее.

Я заметил, что точки исчезают, когда z выше 1. Это еще одна проблема, которую я не могу решить в данный момент, поэтому я обхожу ее, просто полностью перебирая значения, поскольку z в любом случае не должен быть частью визуализации. , но эта система шагов не работает.

Я знаю, что альтернативным решением было бы сделать копию массива позиций, содержащую только значения x и y, и передать ее в шейдерную программу как двумерную систему, и это работает! Это устраняет проблему «исчезающих точек», но вызывает некоторую задержку при большом количестве частиц из-за сборки мусора, без которой я бы хотел обойтись.

Это код буфера:

dims = 3;
drawScene(gl, program, positions) {
        gl.clearColor(0.0, 0.0, 0.0, 1.0);
        gl.clear(gl.COLOR_BUFFER_BIT);

        var positionAttributeLocation = gl.getAttribLocation(program, "a_position");        
        var positionBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

        // positions is array of x,y,z coordinates 
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
        gl.enableVertexAttribArray(positionAttributeLocation);

        const size = this.dims;         
        const type = gl.FLOAT;
        const normalize = true; 
        const stride = 4 * (this.dims-2); // gl.FLOAT=4 bytes, then stride +1 extra per dim above 2
        const offset = 0;
        gl.vertexAttribPointer(
            positionAttributeLocation, size, type, normalize, stride, offset);

        const primitiveType = gl.POINTS;
        const count = positions.length / this.dims;

        gl.drawArrays(primitiveType, offset, count);
    }

person baal_imago    schedule 31.12.2019    source источник


Ответы (1)


Шаг неправильный. Шаг должен быть просто dims * 4, и если вам нужны только x и y, то размер равен всего 2.

Другие вопросы

  1. Плюс вы не можете нормализовать поплавки

  2. Вы должны искать местоположения во время инициализации, а не во время рендеринга.

  3. Вы должны создать один буфер и повторно использовать его

    В настоящее время код создает новый буфер для каждого кадра, и в конечном итоге ему не хватит памяти.

  4. Код выполняет преобразование из собственного массива JavaScript в новый массив Float32Array каждый кадр. Это тоже распределение.

    Вы должны просто создать один Float32Array и обновить значения в нем.

  5. Код потенциально выделяет новый массив внутри WebGL для каждого кадра, вызывая gl.bufferData. Вместо этого вызовите gl.bufferSubData, чтобы просто загрузить данные

  6. Если вы часто меняете данные в буфере, вы должны пометить его как gl.DYNAMIC_DRAW, чтобы сообщить WebGL, что вы планируете часто обновлять его. Он может использовать это как подсказку.

const gl = document.querySelector('canvas').getContext('webgl');

const vs = `
attribute vec2 a_position;
void main() {
  gl_Position = vec4(a_position, 0, 1);
  gl_PointSize = 5.0;
}`;

const fs = `
precision mediump float;
void main() {
  gl_FragColor = vec4(1, 0, 0, 1);
}`;

const prg = twgl.createProgram(gl, [vs, fs]);
const positionAttributeLocation = gl.getAttribLocation(prg, 'a_position');

const dims = 3;
const num = 100;
const positions = new Float32Array(dims * num);

// create the buffer at init time
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// just allocate space
gl.bufferData(gl.ARRAY_BUFFER, positions.byteLength, gl.DYNAMIC_DRAW);

function drawScene(gl, program, positions) {
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT);

  // update positions
  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  gl.bufferSubData(gl.ARRAY_BUFFER, 0, positions);
  
  gl.enableVertexAttribArray(positionAttributeLocation);

  const size = 2;
  const type = gl.FLOAT;
  const normalize = false;
  const stride = 4 * dims;
  const offset = 0;
  gl.vertexAttribPointer(
    positionAttributeLocation, size, type, normalize, stride, offset);
    
  gl.useProgram(program);

  const primitiveType = gl.POINTS;
  const count = positions.length / dims;

  gl.drawArrays(primitiveType, offset, count);
}

function render(time) {
  time *= 0.001;
  
  for (let i = 0; i < num * dims; i += dims) {
    const u = i / dims / num;
    const a = u * Math.PI * 2 + time;
    positions[i    ] = Math.sin(a);
    positions[i + 1] = Math.cos(a * 1.1);
    positions[i + 2] = Math.cos(a * 1.2) * 1.2;
  }
  drawScene(gl, prg, positions);
  requestAnimationFrame(render);
}
requestAnimationFrame(render);
canvas {
  border: 1px solid black;
}
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>

Также чаще используется проекционная матрица и матрица просмотра, чтобы изменить пространство, представленное холстом. Затем вместо того, чтобы не использовать Z, вы можете просто выбрать другое пространство для представления на холсте, которое содержит ваш диапазон Z.

person gman    schedule 31.12.2019