Webgl:跨步无效。不会跨过缓冲区中的值

Webgl: Stride not working. Doesn't stride past values in buffer

我正在 webgl 中做一个洛伦兹吸引子,并且正在研究一般的多维奇怪吸引子。我在 webgl 中为此制作了一个粒子系统,在大多数情况下效果很好。粒子系统的工作原理是渲染 gl.POINTS 的 x 和 y 值,同时在同一缓冲区中保持更高的维度以计算它们各自的导数。缓冲区示例:x=buffer[i]、y=buffer[i+1]、z=buffer[i+2]、w=buffer[i+3] 等等。

我注意到当 z 大于 1 时,点消失了。这是我目前无法解决的另一个问题,所以我通过简单地跨过这些值来绕过它,因为 z 不应该是反正是可视化的一部分,但是这个步幅系统不起作用。

我知道另一种解决方案是制作仅包含 x 和 y 值的位置数组的副本,并将其作为二维系统传递到着色器程序中,这很有效!这样做可以消除 "disappearing points" 问题,但由于我希望没有垃圾收集,它会导致大量粒子出现延迟。

这是缓冲区代码:

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

步幅不对。步幅应该只是 dims * 4 如果你只想要 x 和 y 那么大小就是 2.

其他问题

  1. 另外你不能标准化浮点数

  2. 您应该在初始化时而不是渲染时查找位置

  3. 您应该创建一个缓冲区并重新使用它

    该代码当前正在每帧创建一个新缓冲区,最终会 运行 内存不足

  4. 代码每帧都将原生 JavaScript 数组转换为新的 Float32Array。那也是一个分配。

    您应该只创建一个 Float32Array 并更新其中的值

  5. 代码可能会通过调用 gl.bufferData 在 WebGL 中为每一帧分配一个新数组。而是调用 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>

也更常见的是使用projection matrix and a view matrix来改变canvas代表的space。然后,除了不使用 Z,您还可以选择一个不同的 space 在 canvas 中表示,其中包含您的 Z 范围。