从不同的缓冲区绘制多个对象(数组切换)

Posted

技术标签:

【中文标题】从不同的缓冲区绘制多个对象(数组切换)【英文标题】:Draw multiple objects from different buffers (arrays switching) 【发布时间】:2014-05-12 07:23:37 【问题描述】:

目前我正在尝试使用缓冲区数量绘制多个对象。

我不确定我是否以正确的方式切换缓冲区以进行绘图,并且不知道该怎么做。

我有 2 个数组:

quad_strip2 的数量包含 34 个元素(要绘制的对象),每个元素的 QUAD_STRIP 使用 52 个顶点(总共 1767 个顶点)。 quad_strip3 包含 48 个元素,QUAD_STRIP 有 26 个顶点(总共 1247 个顶点)。

初始化代码

        gl.GenBuffers(2, Buffers);

        //SKIPED MATRICES AND SHADERS INITIALIZATION

        float[] quad_strip2 = new float[]
        
            // COUNT OF ELEMENTS: 34
            // COUNT OF VERTICES: 52

            -19.66171f, 8.161709f, 2f, //0
            -19.66171f, 8.161709f, 4f, //1
             ........
            -19.66171f, -6.838291f, 35f, //1767

        ;

        float[] quad_strip3 = new float[]
        
            // COUNT OF ELEMENTS: 48
            // COUNT OF VERTICES: 26
            -0.8537037f, 7.25f, 2f, //0
            -0.8537037f, 7.25f, 4f, //1
             ........
            -20f, -3.25f, 34.45f, //1247
        ;

        //bind first buffer
        gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, Buffers[0]);

        //fill buffer with vertices
        unsafe
        
            fixed (float* verts = quad_strip2)
            
                var prt = new IntPtr(verts);

                gl.BufferData(OpenGL.GL_ARRAY_BUFFER, quad_strip2.Length * sizeof(float), prt,
                    OpenGL.GL_STATIC_DRAW);

            
        

        //bind second buffer
        gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, Buffers[1]);

        //fill buffer
        unsafe
        
            fixed (float* verts = quad_strip3)
            
                var prt = new IntPtr(verts);

                gl.BufferData(OpenGL.GL_ARRAY_BUFFER, quad_strip3.Length * sizeof(float), prt,
                    OpenGL.GL_STATIC_DRAW);

            
        

        gl.VertexAttribPointer((uint)Attrib_IDs.vPosition, 3, OpenGL.GL_FLOAT, false, 0, new IntPtr(0));
        gl.EnableVertexAttribArray((uint)Attrib_IDs.vPosition);

绘图代码

    //SKIPED FILLING VERTEX SHADER WITH MATRIXES


     //DRAW ARRAYS
    //binf first array and draw it 
    gl.BindVertexArray(Buffers[0]);
    for (int i = 0; i < 34; i++)
    
        gl.DrawArrays(OpenGL.GL_QUAD_STRIP, i * 52, 52);
    


    //binf second array and draw it 
    gl.BindVertexArray(Buffers[1]);
    shaderProgram.SetUniform3(gl, "color", 0, 0.4f, 1);
    for (int i = 0; i < 48; i++)
    
        gl.DrawArrays(OpenGL.GL_QUAD_STRIP, i * 26, 26);
    


    //DRAW WIREFRAMES
    shaderProgram.SetUniform3(gl, "color", 0, 0, 0);
    gl.Enable(OpenGL.GL_POLYGON_OFFSET_FILL);

    gl.PolygonOffset(1.0f, 1.0f);

    gl.PolygonMode(FaceMode.FrontAndBack, PolygonMode.Lines);


    gl.BindVertexArray(Buffers[0]);
    for (int i = 0; i < 34; i++)
    
        gl.DrawArrays(OpenGL.GL_QUAD_STRIP, i * 52, 52);
    

    gl.BindVertexArray(Buffers[1]);
    for (int i = 0; i < 48; i++)
    
        gl.DrawArrays(OpenGL.GL_QUAD_STRIP, i * 26, 26);
    

    gl.PolygonMode(FaceMode.FrontAndBack, PolygonMode.Filled);

结果我有这样的输出,这看起来不像我需要得到的。

【问题讨论】:

【参考方案1】:

您需要在绘图代码中的每个BindBuffer 调用之后调用VertexAttribPointerVertexAttribPointer 适用于当前绑定的缓冲区。您当前的代码在初始化代码中只有一个 VertexAttribPointer 调用,这是在调用 Buffers[1] 时发生的。因此,您的所有绘图调用都将使用该缓冲区中的顶点数据。

编辑:我还注意到您在绘制代码中使用了BindVertexArray。顶点数组对象 (VAO) 是来自顶点缓冲区 (VBO) 的不同类型的对象,您不能只将 VBO 的 id 用于 BindVertexArray 调用。要让这一切暂时不使用 VAO,您可以从初始化代码中删除 VertexAttribPointer 调用。然后将两个VertexAttribPointer 调用添加到您的绘图代码中,并将BindVertexArray 替换为BindBuffer,使其结构如下:

gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, Buffers[0]);
gl.VertexAttribPointer((uint)Attrib_IDs.vPosition, 3, OpenGL.GL_FLOAT, false, 0, new IntPtr(0));
for (int i = 0; i < 34; i++)

    gl.DrawArrays(OpenGL.GL_QUAD_STRIP, i * 52, 52);


gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, Buffers[1]);
gl.VertexAttribPointer((uint)Attrib_IDs.vPosition, 3, OpenGL.GL_FLOAT, false, 0, new IntPtr(0));
shaderProgram.SetUniform3(gl, "color", 0, 0.4f, 1);
for (int i = 0; i < 48; i++)

    gl.DrawArrays(OpenGL.GL_QUAD_STRIP, i * 26, 26);

另一种选择是您一直使用顶点数组对象 (VAO)。为此,您必须在初始化代码 (glGenVertexArrays) 中创建这些对象,并在为每个缓冲区设置状态时绑定它们。它们允许您在设置期间设置所有状态,然后仅在准备绘制时进行一次绑定调用。您应该能够通过一些搜索找到相应的代码示例。

【讨论】:

能否提供小代码sn-p来解释你的答案? gl.VertexAttribPointer 中的什么参数应该指定我的缓冲区? 指定缓冲区的不是VertexAttribPointer 的参数。调用时当前绑定的缓冲区很重要。我会补充答案。

以上是关于从不同的缓冲区绘制多个对象(数组切换)的主要内容,如果未能解决你的问题,请参考以下文章

WebGL入门(四十)-通过切换着色器实现一个页面同时展示多个立方体

在Vulkan中使用纹理绘制多个对象

webgl 缓冲区

WebGl通过缓冲区绘制多个点

OpenGL:尝试使用 VBO(顶点缓冲区对象)绘制线条,它不显示

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