繁体   English   中英

VBO如何画初学者

[英]Vbo how to draw primitivies

嗨,我正在尝试使用本教程http://www.opengl-tutorial.org/beginners-tutorials/tutorial-2-the-first-triangle/学习OpenGl,我认为本教程对刚开始的人不利。 他们展示了许多适用于1个三角形的代码,但是没有更多示例了。 Atm我正在尝试编写绘制函数。 线条或矩形,我有问题,因为这对我来说很难。 我想编写可重用的函数。 但是我不明白VBO:/我想编写将从主循环执行的函数draw。

class lines{
    public: lines(){
    }
    static void draw(GLuint ve){

        float vertices[] = {-0.5f, -0.5f, 0.5f, 0.5f};
        unsigned int indices[] = {0, 1};

        glEnableClientState(GL_VERTEX_ARRAY);
        glVertexPointer(2, GL_FLOAT, 0, vertices);
        glDrawElements(GL_LINES, 2, GL_UNSIGNED_INT, indices);
    }
};


    // Ensure we can capture the escape key being pressed below
glfwEnable( GLFW_STICKY_KEYS );

// Dark blue background
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);

GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);

// Create and compile our GLSL program from the shaders
GLuint programID = LoadShaders( "SimpleVertexShader.vertexshader", "SimpleFragmentShader.fragmentshader" );


static const GLfloat g_vertex_buffer_data[] = { 
    -0.8f, -1.0f,0.0f,
    0.8f,  -1.0f, 0.0f,
    -0.8f,   1.0f, 0.0f,
    -0.8f, 1.0f, 0.0f,
    0.8f, 1.0f, 0.0f,
    0.8, -1.0f, 0.0f,
};

GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);

do{

    // Clear the screen
    glClear( GL_COLOR_BUFFER_BIT );

    // Use our shader
    glUseProgram(programID);

    // 1rst attribute buffer : vertices
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
    glVertexAttribPointer(
        0,                  // attribute 0. No particular reason for 0, but must match the layout in the shader.
        3,                  // size
        GL_FLOAT,           // type
        GL_FALSE,           // normalized?
        0,                  // stride
        (void*)0            // array buffer offset
    );

    glDrawArrays(GL_TRIANGLES, 0, 6); 

    glDisableVertexAttribArray(0);
    lines::draw(vertexbuffer);
    // Swap buffers
    glfwSwapBuffers();

} // Check if the ESC key was pressed or the window was closed
while( glfwGetKey( GLFW_KEY_ESC ) != GLFW_PRESS &&
       glfwGetWindowParam( GLFW_OPENED ) );

要绘制图元,请为OpenGL提供一个顶点列表以及连接它们的模式(例如,形成线,三角形等)。 最简单的方法是立即模式( glBegin / glVertex3f / glEnd )。 立即模式相当慢,并且通过“顶点数组”一次传递所有顶点(而不是顶点数组对象(VAO),它们是不同的)要快得多,在那里它们像g_vertex_buffer_data一样一维地按顺序排列。 顶点数组是当您将指向主内存中数组的指针传递给glVertexPointer 这样速度更快,但是每次绘制时都会将整个阵列发送到GPU。 顶点缓冲区对象(VBO)允许您将数组发送和存储在GPU内存中。 使用VBO,仅需要发送一次绘图调用,并且数据已经在GPU上,因此无需传输,并且速度更快。 VAO对glVertexPointer参数进行了分组,以使绑定更快,并且glDraw*Indirect允许使用GPU内存中已有的参数进行绘制,但我将其留待以后使用。

大多数教程都是从硬编码的顶点开始的,但是对于最终应用程序来说,这当然是不切实际的。 您想存储许多任意几何形状的位。 类似于您的lines网格物体类很常见。 关键是网格具有顶点列表。 您可以添加索引数组以重新引用现有顶点以形成图元,从而节省内存并计算重复顶点。

但是,现在我将从立即模式渲染开始-可以减少出错的地方。

首先,

struct vec3f {
    float x, y, z;
    vec3f(float nx, float ny, float nz) : x(nx), y(ny), z(nz) {}
};

class Mesh {
    std::vector<vec3f> vertices;
public:
    void add(float x, float y, float z)
    {
        vertices.push_back(vec3f(x, y, z));
    }
    void draw()
    {
        glBegin(GL_LINE_STRIP);
        for (size_t i = 0; i < vertices.size(); ++i)
            glVertex3f(vertices[i].x, vertices[i].y, vertices[i].z);
        glEnd();
    }
};

并使用它,

Mesh square;
...
//Lots of add() and push_back is slow. Much faster to use
//dynamic allocation yourself and copy data in bigger blocks,
//but this will do for an example.
square.add(-1,-1,0);
square.add(-1,1,0);
square.add(1,1,0);
square.add(1,-1,0);
square.add(-1,-1,0); //these could also be read from a file
...
line.draw();

这个想法使您可以使用全局std::list<Mesh> lines; 例如。 您可以在初始化时,从文件或在运行时向其添加行。 然后,您的绘图代码只需在每个元素上调用draw。 稍后,您可以将此想法扩展为也支持三角形(例如,使GL_LINE_STRIP成为primitive成员)。 稍后,您可以添加索引,法线(这里您将要使用gl*Pointer函数的stride参数查找交织的顶点/法线数据),颜色/材质等。

关于您使用VBO的问题。 glGenBuffers将为您提供一个唯一的句柄来引用您的glGenBuffers只是一个整数。 每当您修改或使用该VBO时,都需要将其绑定。

glBufferData(GL_ARRAY_BUFFER...对当前绑定的GL_ARRAY_BUFFER进行实际的初始化/调整大小(如果尚未设置),并且如果data参数为非NULL,则传输数据。

glVertexAttribPointer会假定您正在向主存储器传递上述数组“ vertex arrays”,除非您使用glBindBuffer(GL_ARRAY_BUFFER, vbo) ,在这种情况下,最后一个参数将成为该VBO的偏移量。 调用glVertexAttribPointer

所以,

1. glGenBuffers
2. glBufferData (while the buffer is bound)

初始化已完成。 继续绘图...

3. glVertexAttribPointer (while the buffer is bound)

然后

4. glDrawArrays

要么

4. glDrawElements (while an element array buffer is bound, containing the order in which to draw the vertices)

因此,要扩展网格物体类,您至少需要一个GLuint vertexBuffer; 也许添加一个函数upload()来生成一个句柄并缓冲当前数据。 然后,假设您不再需要主存储器中的顶点数据,则可以调用vertices.clear() (实际上,对于std :: vector使用this )。 然后更改绘图函数以绑定vbo,调用glVertexPointer ,unbind和glDrawArrays (来自numVertices成员,因为vertices.size()现在可能为零)。

这里是一些相关的帖子:

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM