使用gl.bufferSubData

时间:2017-07-15 19:34:52

标签: javascript webgl

我具有WebGL / OpenGL的基本知识,但不具备gl.bufferSubData的基本知识。 所以我的目标是创建一个SpriteBatch类,就像这个问题First Question 由于我认为问题与gl.bufferSubData有关,因此我只发布与渲染调用相关的代码片段。我还包括未知变量,但会在评论中显示它们的值。

因此,当构造SpriteBatch时,这段代码被调用(内部构造函数)

// this.capacity = 750, VERTEX_OFFSET = 18
this.vertexBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(this.capacity * VERTEX_OFFSET), this.gl.STREAM_DRAW);
this.gl.enableVertexAttribArray(this.program.vertexLocation);
this.gl.vertexAttribPointer(this.program.vertexLocation, 3, gl.FLOAT, false, 0, 0);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);

当我向SpriteBatch添加一个精灵时,这段代码被称为

//s == new Sprite()
// UNIT_QUAD_COORDS = new Float32Array([-0.5, -0.5, 1.0, 0.5, -0.5, 1.0, -0.5, 0.5, 1.0, -0.5, 0.5, 1.0, 0.5, -0.5, 1, 0.5, 0.5, 1.0]);
this.numberUsedVertices += VERTEX_OFFSET; //  VERTEX_OFFSET=18
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
let data = UNIT_QUAD_COORDS; // new Float32Array([-0.5, -0.5, 1.0, 0.5, -0.5, 1.0, -0.5, 0.5, 1.0, -0.5, 0.5, 1.0, 0.5, -0.5, 1, 0.5, 0.5, 1.0]);

for (let k = 0; k < VERTEX_OFFSET; k += 3) {
  let x = s.size * UNIT_QUAD_COORDS[k] * Math.cos(s.rotation) - s.size * UNIT_QUAD_COORDS[k + 1] * Math.sin(s.rotation);
  let y = s.size * UNIT_QUAD_COORDS[k] * Math.sin(s.rotation) + s.size * UNIT_QUAD_COORDS[k + 1] * Math.cos(s.rotation);
  x += s.x;
  y += s.y;
  data[k] = x;
  data[k + 1] = y;
}
// s.index = 0, VERTEX_OFFSET=18
gl.bufferSubData(gl.ARRAY_BUFFER, VERTEX_OFFSET * s.index, data)

最后当我画SpriteBatch时:

gl.useProgram(this.program.program);
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
gl.vertexAttribPointer(this.program.vertexLocation, 3, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, this.numberUsedVertices); // this.numberUsedVertices =18

请注意,使用gl.vertexAttribPointer(this.program.vertexLocation, 3, gl.FLOAT, false, 0, 0);时,我只看到一个白色屏幕。但是当我使用gl.vertexAttribPointer(this.program.vertexLocation, 2, gl.FLOAT, false, 0, 0);时会看到许多不同的三角形。 另请注意,当我正常绘制时,这意味着没有gl.bufferSubData和SpriteBatch,会显示四边形。

所以我的假设是我对gl.bufferSubData的使用是错误的。

1 个答案:

答案 0 :(得分:1)

gl.bufferSubData的偏移量以字节为单位,因此您可能需要

gl.bufferSubData(gl.ARRAY_BUFFER, VERTEX_OFFSET * s.index * 4, data);

或者如果你想迂腐

const offset = VERTEX_OFFSET * s.index * Float32Array.BYTES_PER_ELEMENT;
gl.bufferSubData(gl.ARRAY_BUFFER, offset, data);

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

const vs = `
attribute vec2 position;
void main() {
  gl_Position = vec4(position, 0, 1);
  gl_PointSize = 10.;
}
`
const fs = `
precision mediump float;
void main() {
  gl_FragColor = vec4(1, 0, 0, 1);
}
`

const program = twgl.createProgram(gl, [vs, fs]);

const positionLoc = gl.getAttribLocation(program, "position");

const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

const numVerts = 100;
const vertSize = 2 * 4;  // 2 floats, 4 bytes each
gl.bufferData(gl.ARRAY_BUFFER, numVerts * vertSize, gl.STREAM_DRAW);

const vert = new Float32Array(2);

function render() {
  // replace one vertex
  const ndx = Math.random() * numVerts | 0;
  vert[0] = Math.random() * 2 - 1;
  vert[1] = Math.random() * 2 - 1;
  const offset = ndx * vertSize;
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.bufferSubData(gl.ARRAY_BUFFER, offset, vert);
  
  gl.enableVertexAttribArray(positionLoc);
  gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);
  
  gl.useProgram(program);

  gl.drawArrays(gl.POINTS, 0, numVerts);
  
  requestAnimationFrame(render);
}
requestAnimationFrame(render);
canvas { border: 1px solid black }
<canvas></canvas>
<script src="https://twgljs.org/dist/3.x/twgl.min.js"></script>