OpenGL顶点数组对象不记录VBO和IBO绑定

Posted

技术标签:

【中文标题】OpenGL顶点数组对象不记录VBO和IBO绑定【英文标题】:OpenGL vertex array object not recording VBO and IBO bindings 【发布时间】:2015-03-26 18:19:53 【问题描述】:

我正在编写一个简单的场景图,并且我有一个网格类来跟踪顶点数组对象、顶点缓冲区对象和索引缓冲区对象。

当我初始化网格对象并用数据填充它们时,似乎最后创建的顶点缓冲区是绘制时使用的缓冲区,即使我绑定了不同的顶点数组对象也是如此。

渲染时,如果我只绑定顶点数组,除了最后一个初始化的网格之外的任何网格都具有最后一个初始化网格的顶点(但正确的索引,使它们看起来不对)。

我让它工作的唯一方法是在我绑定顶点数组对象之后再次绑定顶点缓冲区对象。这与我在任何地方阅读的每个文档或评论相矛盾。

// Geometry class
class Geometry 

    public override void Render()
    
        this.Mesh.bind(); // bind mesh
        this.Material.bind(); // bind shader. This also uses attribute locations stored in the shader object to enable vertex attributes

        this.Data.Render();
        this.Mesh.unbind(); // bind 0 to vertex array

        this.Material.unbind(); // use program 0
    


// base mesh class
class Mesh 

    public override void init()
    
        // ... truncated code for creating vertices ..

        vertexArray = GL.GenVertexArray();
        GL.BindVertexArray(vertexArray);

        GL.GenBuffers(2, buffers);

        GL.BindBuffer(BufferTarget.ArrayBuffer, buffers[0]);
        GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * Vertex.SizeInBytes), vertices, BufferUsageHint.StaticDraw);

        GL.BindBuffer(BufferTarget.ElementArrayBuffer, buffers[1]);
        GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(indices.Count * sizeof(uint)), indices.ToArray(), BufferUsageHint.StaticDraw);

        numPoints = vertices.Length;
        numIndices = indices.Count;
        GL.BindVertexArray(0);
    

    public void bind()
    
        GL.BindVertexArray(vertexArray);

        // I had to add this line to make meshes render correctly
        GL.BindBuffer(BufferTarget.ArrayBuffer, buffers[0]);
    

    public void unbind()
    
        GL.BindVertexArray(0);
    
    public override void Render()
    
        GL.DrawElements(PrimitiveType.Triangles, numIndices, DrawElementsType.UnsignedInt, IntPtr.Zero);
    

    public override void Update(float t, float deltaT, int xDelta, int yDelta, int zDelta, MouseState mouse, KeyboardState keyboard)
    
    

【问题讨论】:

【参考方案1】:

您的网格初始化方法缺少一些相当重要的东西。即,调用 glVertexAttribPointer。此方法设置您的 VAO 将在何处以及如何获取顶点数据。您创建缓冲区并向它们提交数据,您从不为缓冲区设置属性绑定。

属性绑定与 VAO 状态一起保存并在绑定 VAO 时自动使用,不会保存有关绑定到缓冲区目标(如 Element 数组缓冲区和数组缓冲区)的缓冲区的信息。

编辑

您似乎每次渲染时都在重新绑定属性,这不是您应该做的,而是导致您出现问题的原因。

在初始化时绑定一次属性。然后只需绑定 VAO 并渲染。很简单。

之所以如此,是因为您在 material.bind 中设置了属性绑定。如果你这样做时相关的缓冲区没有被绑定,你就会遇到问题。因此,它只有在您的缓冲区被绑定时才有效,因此当您在 mesh.bind 中添加绑定线时它才有效,这是之前发生的调用。但同样,您不应该在每次渲染调用时都这样做。

【讨论】:

对不起,我应该提到我在 Material.bind() 中这样做,因为我试图避免在我的着色器中使用布局(位置 = x)。因此,当着色器被绑定时,它使用存储在其中的属性位置来启用属性。谢谢你指出这一点。我用注释更新了代码以澄清这一点。那么如果只有属性绑定保存在 VAO 中,这是否意味着我每次绑定 VAO 时也必须调用 BindBuffer 呢?我看到的所有文档和教程都暗示我只需要绑定 VAO。我误会了吗? @Elias 仍然存在一些问题。您的 Material.bind() 正在渲染方法中被调用。您没有在渲染调用中设置属性绑定!它们很贵! 哦,我明白了。我想我应该使用硬编码的位置并在初始化时这样做。我会让你知道情况如何。非常感谢! 解决了。我真的需要了解这个 VAO 是如何工作的,但我并没有从我阅读的所有内容中得到它,哈哈。非常感谢你。标记为答案。 @Elias 应该有大量关于 VAO 如何工作的文档和教程。以前的问题也有很多答案。这是我自己的旧答案之一,它以相当通用的方式解释了 VAO:***.com/a/26229019。

以上是关于OpenGL顶点数组对象不记录VBO和IBO绑定的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL 基本 IBO/VBO 不工作

我的OpenGL学习进阶之旅介绍顶点缓冲区对象VBO和元素数组缓冲区对象EBO,并对比使用VBO和不使用VBO绘制三角形的效果

OpenGL 顶点数组对象是存储顶点缓冲区名称和索引,还是只存储索引?

opengl绘制三角形

为啥使用 VBO 和/或 IBO 而不是简单的顶点数据?

在 Android 上的 OpenGL ES 2.0 中使用 VBO/IBO