【问题标题】:Why are we use twice bindVertexArray(vao)?为什么我们使用两次 bindVertexArray(vao)?
【发布时间】:2019-10-15 15:29:20
【问题描述】:

我是 WebGL 的新手,我正在努力学习 WebGL2。但我真的不明白如何使用 WebGL。尤其是 VAO 和 VBO。我查找了有关内存工作原理的图表,但找不到。我已经给出了以下示例,我将尝试解释该示例的工作原理。

function main(){
    // initialize GL
    // create vertex shader and fragment shader
    // create program

    var positionAttributeLocation = gl.getAttribLocation(program, "a_position");

    var positionBuffer = gl.createBuffer();

    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

    // define positions with array

    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

    var vao = gl.createVertexArray();

    gl.bindVertexArray(vao);

    gl.enableVertexAttribArray(positionAttributeLocation);

    // ....
    gl.vertexAttribPointer(
        positionAttributeLocation, size, type, normalize, stride, offset
    );

    gl.viewport(0, 0, 400, 300);

    // clear canvas
    // use program

    gl.bindVertexArray(vao);        // why we use that here ?

    var primitiveType = gl.TRIANGLES;
    var offset = 0;
    var count = 3;
    gl.drawArrays(primitiveType, offset, count);
}
  1. 首先,我在顶点着色器程序中获得了属性,我们将用于VAO。我可以认为它是插槽 0。
  2. 然后我为位置(数组)创建了缓冲区。
  3. 使用bindBuffer() 函数激活缓冲区。
  4. 然后将位置添加到缓冲区中。
  5. 创建了 VAO 并使用 bindVertexArray() 激活。
  6. 启用 slot 0,我将在 slot 0 中添加数据(位置)。它作为 vertexAttribFunction() 的参数。

这是我能理解的情况。然后情况变得混乱。为什么要再次调用 bindVertexArray(vao)?是否还有关于 VAO 和 VBO 如何在 WebGL 中工作的详细方案?

【问题讨论】:

  • OpenGL 作为 WebGL 是一个状态引擎。 gl.bindVertexArray(vao) 绑定顶点数组对象,打破现有的顶点数组对象绑定。再次绑定相同的VAO是没有用的。但请注意,如果您有不同的顶点数组对象,那么您必须在绘制调用之前绑定正确的 VAO。

标签: webgl


【解决方案1】:

在 WebGL 中绘制单个对象是不正常的。如果您有超过 1 个对象并且您正在使用顶点数组对象 (VAO),那么

在初始化时

for each object
  create a vertex array object VAO and bind it
  create all the buffers for this object
  setup all the attributes for this object

在绘制时

for each object
  bind the VAO for this object
  set uniforms for this object (and optionally bind textures for this object)
  draw

所以是的,如果你只绘制一个东西,那么绑定 VAO 两次可能看起来很奇怪,但是在初始化时绑定 VAO 一次并在绘制时再次绑定的模式是正常的事情,因为正常的事情是做的是绘制多个对象。

请注意,这与任何其他有状态 API 没有什么不同。例如画布 2d API。你可以这样写

ctx.fillStyle = 'red';

function renderLoop(time) {
   ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
   ctx.fillRect(x, y, 20, 20);  // assume X and Y are animated
   ...
}

但又是不正常只画一件事,所以大多数人,即使他们只从一件事开始也会这样做

function renderLoop(time) {
   ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
   ctx.fillStyle = 'red';
   ctx.fillRect(x, y, 20, 20);  // assume X and Y are animated
   ...
}

尽管每帧设置fillStyle 是多余的。他们这样做是因为他们希望以后画更多的东西,所以它成为一种模式,在你绘制它之前设置与你想要绘制的东西相关的状态

function renderLoop(time) {
   ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
   ctx.fillStyle = 'red';
   ctx.fillRect(x, y, 20, 20);  // assume X and Y are animated
   ctx.fillStyle = 'blue';
   ctx.fillRect(x2, y2, 20, 20);  // assume x2 and y2 are animated
   ...
}

VAO 状态见this,纹理状态见this

【讨论】:

    猜你喜欢
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多