OpenGL - 顶点属性状态是否绑定到特定的VBO?

时间:2015-11-12 15:26:30

标签: opengl

据我了解VAO / VBO,VAO保留了自绑定以来已设置的所有属性信息,例如。 VBO中给定顶点属性的偏移量,步幅,组件数等。

我似乎不清楚VAO和VBO是如何协同工作的。我见过的很多例子都指定了相对于当前绑定的VBO的顶点属性,当绑定VAO时,VBO中的数据变得可访问。我可以看到以这种方式使用VAO的一种方法是每个对象有一个(每个对象使用自己的VBO),但我已经读过,由于不必要地在许多VAO之间切换,这在性能上是差的。我还希望避免将所有对象数据存储在一个单片VBO中,因为我需要随时在场景中添加和删除对象 - 作为3D编辑器,我觉得应用程序更适合拥有每个几何对象都拥有自己的缓冲区,而不是一些大的,预分配的VBO。 (这是正确的假设吗?)

因此,我的问题是,一个VAO是否可以独立于VBO存储顶点属性配置?我是否能够配置VAO以期望某种格式的数据(例如位置,正常,UV)然后"交换"不同的VBO,因为我绘制不同的几何对象,或者格式信息基本上只绑定到VBO本身?如果是后者,是否值得我使用VAO?

1 个答案:

答案 0 :(得分:2)

ARB_vertex_attrib_binding 允许您分离Vao属性格式和缓冲区绑定。

https://www.opengl.org/wiki/Vertex_Specification#Separate_attribute_format

在内部,配置Vao时,Vertex缓冲区会自动与属性索引关联。使用 ARB_vertex_attrib_binding ,您可以使用新的gl函数独立于绑定缓冲区定义属性格式,可以使用VertexBuffer函数进行切换。

这里是c#中使用openTK的一段代码:(完整的:https://github.com/jpbruyere/GGL/tree/ottd/Tetra

这里的解决方案是构建一个VAO,并将所有网格连接起来,仅为每个网格保留

  • BaseVertex = VAO中的顶点偏移
  • IndicesOffset =元素缓冲区中的偏移量(ebo索引)
  • IndicesCount =和模型的总指数

    protected void CreateVAOs()
    {
        //normal vao binding
    
        vaoHandle = GL.GenVertexArray();
        GL.BindVertexArray(vaoHandle);
    
        GL.EnableVertexAttribArray(0);
        GL.BindBuffer(BufferTarget.ArrayBuffer, positionVboHandle);
        GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, true, Vector3.SizeInBytes, 0);          
    
        ... other attrib bindings come here
    
        //ARB vertex attrib binding use for fast instance buffers switching
        //note that I use 4 attrib indices to bind a matrix
        GL.VertexBindingDivisor (instanceBufferIndex, 1);
        for (int i = 0; i < 4; i++) {                   
            GL.EnableVertexAttribArray (instanceBufferIndex + i);   
            GL.VertexAttribBinding (instanceBufferIndex+i, instanceBufferIndex);
            GL.VertexAttribFormat(instanceBufferIndex+i, 4, VertexAttribType.Float, false, Vector4.SizeInBytes * i);
        }
    
        if (indices != null)
            GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle);
    
        GL.BindVertexArray(0);
    }
    

然后,我使用每个矩阵数组定义网格实例,这是一个正常的缓冲区创建,但不是静态绑定到vao。

    instancesVboId = GL.GenBuffer ();       

    GL.BindBuffer (BufferTarget.ArrayBuffer, instancesVboId);
    GL.BufferData<Matrix4> (BufferTarget.ArrayBuffer,
                new IntPtr (modelMats.Length * Vector4.SizeInBytes * 4),
                modelMats, BufferUsageHint.DynamicDraw);
    GL.BindBuffer (BufferTarget.ArrayBuffer, 0);

为了渲染这样的vao,我在我的实例数组中循环:

    public void Bind(){
        GL.BindVertexArray(vaoHandle);
    }

    public void Render(PrimitiveType _primitiveType){
        foreach (VAOItem item in Meshes) {
            GL.ActiveTexture (TextureUnit.Texture1);
            GL.BindTexture (TextureTarget.Texture2D, item.NormalMapTexture);
            GL.ActiveTexture (TextureUnit.Texture0);
            GL.BindTexture (TextureTarget.Texture2D, item.DiffuseTexture);
            //Here I bind the Instance buffer with my matrices
            //that's a fast switch without changing vao confing
            GL.BindVertexBuffer (instanceBufferIndex, item.instancesVboId, IntPtr.Zero,Vector4.SizeInBytes * 4);
            //here I draw instanced with base vertex
            GL.DrawElementsInstancedBaseVertex(_primitiveType, item.IndicesCount, 
                DrawElementsType.UnsignedShort, new IntPtr(item.IndicesOffset*sizeof(ushort)),
                item.modelMats.Length, item.BaseVertex);
        }
    }

最终的VAO只绑定一次。