更新 openGL VBO

Posted

技术标签:

【中文标题】更新 openGL VBO【英文标题】:Updating an openGL VBO 【发布时间】:2017-01-07 20:07:57 【问题描述】:

我是一名新的 openGL 程序员,到目前为止我已经取得了相当大的进展。我用 C# 编程,所以没有很多示例,我的最终任务是每帧使用新数据更新 VBO。我找不到任何例子。我也是 Vectors 的新手。所以这是基本代码和我尝试过的。我正在使用 opengl4csharp 和 freeglut 库。 我最初在渲染回调之外设置了一个简单的金字塔,如下所示:

        program = new ShaderProgram(VertexShader, FragmentShader)

        // set the view and projection matrix for pyramid
        program.Use();
        program["projection_matrix"].SetValue(Matrix4.CreatePerspectiveFieldOfView(0.45f, (float)width / height, 0.1f, 1000f));
        program["view_matrix"].SetValue(Matrix4.LookAt(new Vector3(0, 0, 10), Vector3.Zero, new Vector3(0, 1, 0)));


        // create a pyramid with vertices and colors
        pyramid = new VBO<Vector3>(new Vector3[] 
            new Vector3(0, 0.5f, 0), new Vector3(-0.5f, -0.5f, 0.5f), new Vector3(0.5f, -0.5f, 0.5f),        // front face
            new Vector3(0, 0.5f, 0), new Vector3(0.5f, -0.5f, 0.5f), new Vector3(0.5f, -0.5f, -0.5f),        // right face
            new Vector3(0, 0.5f, 0), new Vector3(0.5f, -0.5f, -0.5f), new Vector3(-0.5f, -0.5f, -0.5f),      // back face
            new Vector3(0, 0.5f, 0), new Vector3(-0.5f, -0.5f, -0.5f), new Vector3(-0.5f, -0.5f, 0.5f) );   // left face


        pyramidColor = new VBO<Vector3>(new Vector3[] 
            new Vector3(0.5f, 0, 0), new Vector3(0, 0.5f, 0), new Vector3(0, 0, 0.5f),
            new Vector3(0.5f, 0, 0), new Vector3(0, 0, 0.5f), new Vector3(0, 0.5f, 0),
            new Vector3(0.5f, 0, 0), new Vector3(0, 0.5f, 0), new Vector3(0, 0, 0.5f),
            new Vector3(0.5f, 0, 0), new Vector3(0, 0, 0.5f), new Vector3(0, 0.5f, 0) );


        pyramidTriangles = new VBO<int>(new int[]  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 , BufferTarget.ElementArrayBuffer);

然后我在 OnRender 回调中执行以下操作:

        // use our vertex shader program
        Gl.UseProgram(program);

        // bind the vertex positions, colors and elements of the pyramid
        program["model_matrix"].SetValue(Matrix4.CreateRotationY(yangle) * Matrix4.CreateRotationX(xangle));              
        Gl.BindBufferToShaderAttribute(pyramid, program, "vertexPosition");
        Gl.BindBufferToShaderAttribute(pyramidColor, program, "vertexColor");
        Gl.BindBuffer(pyramidTriangles);
        Gl.DrawElements(BeginMode.Triangles, pyramidTriangles.Count, DrawElementsType.UnsignedInt, IntPtr.Zero);

这很好用,然后我就有了一个漂亮的金字塔显示。现在在真正的应用程序中,它比单个金字塔要多得多,并且会实时更新。这就是我的问题所在。我不明白如何正确更新 VBO。这是我在 OnRender 回调中尝试过的。这只是一个改变第一个顶点的例子

        Gl.UseProgram(program);

        pyramid = new VBO<Vector3>(new Vector3[] 
            new Vector3(0, 0.5f, 0), new Vector3(-0.5f, -0.5f, 0.5f), new Vector3(0.5f, -0.5f, 0.5f),        // front face
            new Vector3(0, 0.5f, 0), new Vector3(0.5f, -0.5f, 0.5f), new Vector3(0.5f, -0.5f, -0.5f),        // right face
            new Vector3(0, 0.5f, 0), new Vector3(0.5f, -0.5f, -0.5f), new Vector3(-0.5f, -0.5f, -0.5f),      // back face
            new Vector3(0, 0.5f, 0), new Vector3(-0.5f, -0.5f, -0.5f), new Vector3(-0.5f, -0.5f, 0.5f) );   // left face


        // bind the vertex positions, colors and elements of the pyramid
        program["model_matrix"].SetValue(Matrix4.CreateRotationY(yangle) * Matrix4.CreateRotationX(xangle));              
        Gl.BindBufferToShaderAttribute(pyramid, program, "vertexPosition");
        Gl.BindBufferToShaderAttribute(pyramidColor, program, "vertexColor");
        Gl.BindBuffer(pyramidTriangles);
        Gl.DrawElements(BeginMode.Triangles, pyramidTriangles.Count, DrawElementsType.UnsignedInt, IntPtr.Zero);

这也有效,但是当我退出程序时,我得到一个系统访问冲突异常。如果他们不处置顶点对象之一,这与人们得到的错误相同。但是在这种情况下,我确实调用了 dispose。这是否意味着我每次使用它时都需要调用 dispose ? 我也听说过有关 glMapBuffers 的一些信息,但找不到示例。 感谢您的帮助。

【问题讨论】:

您可以添加指向您使用的库的链接吗?您还可以包括调用 glBufferData() 的行吗? 您好,很抱歉库的名称不正确。它是opengl4csharp。这是链接github.com/giawa/opengl4csharp。至于在 Gl.BindBufferToShaderAttribute 中完成的 glBufferData,据我所知。 【参考方案1】:

您创建了新的 VBO 对象,而不是更新现有的。所以VBO在显卡上堆积如山。

当一个库的文档不好时,最好查看它的源代码。该库主要由 3 个部分组成:

    低级 OpenGL 绑定:https://github.com/giawa/opengl4csharp/blob/master/OpenGL/Core/GlCore.cs

    那里的代码只是从 OpenGL dll 调用函数。

    更高级别的功能。例如,您在评论中提到,您使用 BindBufferToShaderAttribute 函数将缓冲区上传到 GPU:https://github.com/giawa/opengl4csharp/blob/master/OpenGL/Core/GlMethods.cs#L600

    如您所见,该函数只是调用了一些较低级别的 OpenGL 函数。另请注意,它不会将缓冲区上传到 GPU,因此这会发生在其他地方。 (它只是标记缓冲区中的条目,以便将它们作为属性传递给着色器。)

    高级课程。例如,您在示例中使用的 VBO 类:https://github.com/giawa/opengl4csharp/blob/master/OpenGL/Constructs/VBO.cs

    注意它的构造函数调用了 CreateVBO:https://github.com/giawa/opengl4csharp/blob/master/OpenGL/Constructs/VBO.cs#L54

    并且该 CreateVBO 方法调用了 glBufferData,我在评论中提到了这一点:https://github.com/giawa/opengl4csharp/blob/master/OpenGL/Core/GlMethods.cs#L342

所以它是 VBO 类,它将缓冲区上传到 GPU。我们可以期望您可以使用相同的类修改缓冲区。就是这样:https://github.com/giawa/opengl4csharp/blob/master/OpenGL/Constructs/VBO.cs#L129

VBO 对象的 BufferSubData 方法可用于修改缓冲区。示例:

Vector3[] vertexBuffer = new Vector3[] 
    new Vector3(0, 0.5f, 0), new Vector3(-0.5f, -0.5f, 0.5f), new Vector3(0.5f, -0.5f, 0.5f),       // front face
    new Vector3(0, 0.5f, 0), new Vector3(0.5f, -0.5f, 0.5f), new Vector3(0.5f, -0.5f, -0.5f),       // right face
    new Vector3(0, 0.5f, 0), new Vector3(0.5f, -0.5f, -0.5f), new Vector3(-0.5f, -0.5f, -0.5f),     // back face
    new Vector3(0, 0.5f, 0), new Vector3(-0.5f, -0.5f, -0.5f), new Vector3(-0.5f, -0.5f, 0.5f) ;   // left face

pyramid.BufferSubData(vertexBuffer);

【讨论】:

太棒了!你可以说我不是专家。现在下一个问题是如何更新这是一个循环?例如,这会发生很大变化,真实对象会更大。我不明白如何循环访问这些向量。例如,一个数组被创建为 array[] _array = new array[x] 然后你可以访问一个元素为 _array[x] = 123;但是你如何用这个对象做到这一点?非常感谢! 所以你想在渲染过程中改变金字塔的顶点?那是一种什么样的变化?可以用仿射变换来实现吗? (例如:拉伸、旋转、平移、倾斜) 是的,转换没问题。实际的应用程序将实时更新 3d 网格,因此我需要更新顶点,但我不知道如何在对象中更新。 @Tom:如果你只想转换单个对象而不转换其他对象,那么首先确保调用了glMatrixMode(GL_MODELVIEW)(通常在 OpenGL 的 init 完成后调用,并且透视已设置)。然后通过调用glPushMatrix() 保存当前矩阵(因为我们稍后会恢复它)。然后应用您想要的转换,并绘制缓冲区。然后用glPopMatrix() 恢复原始矩阵。因此,如果只进行仿射变换,则无需更改缓冲区的内容。 好的。例如,我做 Vector3[] vertexBuffer = new Vector3[1000]。这行得通。然后是 vertexBuffer[100].X = 1 等。好的。终于我明白了!!学习 openGL 已经够难的了,但是我缺乏丰富的 C# 经验也妨碍了哈哈。非常感谢!我花了 2 天时间完成所有这些工作!

以上是关于更新 openGL VBO的主要内容,如果未能解决你的问题,请参考以下文章

不断更新OpenGL窗口

慢跑。 OpenGL。如何更新 VBO?

更新 openGL VBO

OpenGL 是不是仅更新 vSync fps 的屏幕?

控制台菜单更新 OpenGL 窗口

# OpenGL常用函数详解(持续更新)