0

嗨,我正在尝试使用本教程学习 OpenGl http://www.opengl-tutorial.org/beginners-tutorials/tutorial-2-the-first-triangle/ 我会说本教程不适合初学者。他们展示了很多适用于 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 ) );
4

1 回答 1

3

要绘制图元,您需要给 OpenGL 一个顶点列表和连接它们的模式(例如,形成线、三角形等)。最简单的方法是立即模式 ( glBegin/ glVertex3f/ glEnd)。立即模式非常慢,通过“顶点数组”一次传递所有顶点要快得多(不是顶点数组对象(VAO),它们是不同的),它们按顺序排列在一维数组中,就像你的g_vertex_buffer_data. 顶点数组是当您将指向主内存中数组的指针传递给glVertexPointer. 这更快,但每次绘制时都会将整个数组发送到 GPU。顶点缓冲区对象 (VBO) 允许您发送数组并将其存储在 GPU 内存中。使用 VBO,只需要发送一次绘图调用,并且数据已经在 GPU 上,因此无需传输,而且速度更快。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成员)。稍后您可以添加索引、法线(在这里您需要使用函数stride参数查找交错顶点/法线数据gl*Pointer)、颜色/材质等。

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

glBufferData(GL_ARRAY_BUFFER...执行当前绑定的实际初始化/调整大小GL_ARRAY_BUFFER(如果还没有)并在数据参数为非 NULL 时传输数据。

glVertexAttribPointer将假设您在主内存中为上面提到的“顶点数组”传递一个数组,除非您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、取消绑定和glDrawArrays(来自可能现在为零的numVertices成员)。vertices.size()

以下是一些相关的帖子:

于 2013-10-24T02:55:20.647 回答