Vbo如何绘制原语
Posted
技术标签:
【中文标题】Vbo如何绘制原语【英文标题】:Vbo how to draw primitivies 【发布时间】:2013-10-24 02:16:23 【问题描述】:您好,我正在尝试使用本教程学习 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 ) );
【问题讨论】:
这里混合了顶点数组、VBO 和 VAO。您能否更具体地说明您遇到的问题? 【参考方案1】:要绘制图元,您需要给 OpenGL 一个顶点列表以及连接它们的模式(例如,形成直线、三角形等)。最简单的方法是立即模式 (glBegin
/glVertex3f
/glEnd
)。立即模式非常慢,通过“顶点数组”一次传递所有顶点要快得多(不是顶点数组对象(VAO),它们是不同的),它们按顺序排列在一维数组中,就像你的@ 987654331@。顶点数组是指将指向主内存中数组的指针传递给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
会给你一个唯一的句柄来引用你的 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)假设您不再需要主内存中的顶点数据。然后改变draw函数绑定vbo,调用glVertexPointer
,unbind和glDrawArrays
(从numVertices
成员vertices.size()
现在可能为零)。
这里有一些相关的帖子:
The best way to use VBOs What are some best practices for OpenGL coding (esp. w.r.t. object orientation)? Most basic working vbo example 来自您的教程,tutorial-9-vbo-indexing SimpleVBO.c http://www.opengl.org/wiki/VBO_-_just_examples【讨论】:
以上是关于Vbo如何绘制原语的主要内容,如果未能解决你的问题,请参考以下文章