我正在为 OpenGL 构建一个图形 API,它基于基本的调用绘制图形样式。基本上,不是将数据存储到 GPU 中,并使用它的句柄调用它,而是提供信息以绘制每次更新应该绘制的内容。我知道它很慢,但它很简单,并且适用于非性能关键应用程序。无论如何,是否有任何现代等价于 glBegin/glEnd?它不必调用每个顶点,而是一种我可以在每次更新时发送数据而不将顶点存储在 gpu 中的方法?
2 回答
你几乎回答了你自己的问题。
是否有任何现代等价于 glBegin/glEnd?它不必调用每个顶点,而是一种我可以在每次更新时发送数据而不将顶点存储在 gpu 中的方法?
基本上不,现代方法是将VAO与VBO(和 IBO)一起使用。
如果您要更改 VBO 中的数据,请记住您可以更改glBufferDatamode
中的参数。
GL_STREAM_DRAW - 数据存储内容将被修改一次,最多使用几次。
GL_STATIC_DRAW - 数据存储内容将被修改一次并多次使用。
GL_DYNAMIC_DRAW - 数据存储内容将被反复修改并多次使用。
然后代替使用GL_STATIC_DRAW
,然后使用与使用GL_DYNAMIC_DRAW
相比,使用它会大大提高 FPS GL_STATIC_DRAW
,但这取决于数据量以及更改它的频率。但是尽量限制它,比如如果你实际上不需要,不要更新缓冲区中的数据。
您可以在OpenGL Wiki上阅读有关不同缓冲区的更多信息。
寻找您想要实现的 VAO / VBO 用法。
下面的 C/C++ 代码是一个简单的示例。
输入变量模式是GL_POINTS/TRIANGLES/QUADS/...
(如glBegin()
)
这也是 GLSL 和核心配置文件传递属性的唯一选项(glVertex/glNormal/...
现在在核心中是未知的一段时间)
//------------------------------------------------------------------------------
//--- Open GL VAO example (GLSL) -----------------------------------------------
//------------------------------------------------------------------------------
#ifndef _OpenGL_VAO_example_h
#define _OpenGL_VAO_example_h
//------------------------------------------------------------------------------
GLuint vbo[4]={-1,-1,-1,-1};
GLuint vao[4]={-1,-1,-1,-1};
const float vao_pos[]=
{
// x y z
0.75f, 0.75f, 0.0f,
0.75f,-0.75f, 0.0f,
-0.75f,-0.75f, 0.0f,
};
const float vao_col[]=
{
// r g b
1.0f,0.0f,0.0f,
0.0f,1.0f,0.0f,
0.0f,0.0f,1.0f,
};
//---------------------------------------------------------------------------
void vao_init()
{
glGenVertexArrays(4,vao);
glGenBuffers(4,vbo);
glBindVertexArray(vao[0]);
glBindBuffer(GL_ARRAY_BUFFER,vbo[0]);
glBufferData(GL_ARRAY_BUFFER,sizeof(vao_pos),vao_pos,GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,0);
glBindBuffer(GL_ARRAY_BUFFER,vbo[1]);
glBufferData(GL_ARRAY_BUFFER,sizeof(vao_col),vao_col,GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,0,0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER,0);
}
//---------------------------------------------------------------------------
void vao_exit()
{
glDeleteVertexArrays(4,vao);
glDeleteBuffers(4,vbo);
}
//---------------------------------------------------------------------------
void vao_draw(GLuint mode)
{
void *p=NULL;
glBindVertexArray(vao[0]);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glDrawArrays(mode,0,3);
glBindVertexArray(0);
}
//------------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------------
//--- end. ---------------------------------------------------------------------
//------------------------------------------------------------------------------
如果您不想使用 GLSL,则必须将代码稍微更改为以下内容:
//tetraeder
#define V_SIZ 12
#define I_SIZ 6
GLfloat tet_verts[V_SIZ] = { \
-0.5f, -1.0f, -0.86f, \
-0.5f, -1.0f, 0.86f, \
1.0f, -1.0f, 0.0f, \
0.0f, 1.0f, 0.0f};
GLushort tet_index = {3, 0, 1, 2, 3, 0};
void init_buffers() {
glGenBuffersARB(1, &vertex_buf);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertex_buf);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, V_SIZ*sizeof(GLfloat), tet_verts, GL_STATIC_DRAW_ARB); //upload data
glGenBuffersARB(1, &index_buf);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, index_buf);
glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, I_SIZ*sizeof(GLushort), tet_index, GL_STATIC_DRAW_ARB); //upload data
return;
}
void draw_buffers() {
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertex_buf);
glVertexPointer(3, GL_FLOAT, 0, 0); //3 is xyz, last 0 ("pointer") is offset in vertex-array
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, index_buf);
glEnableClientState(GL_VERTEX_ARRAY);
//use indexing
glDrawElements(GL_TRIANGLE_STRIP, I_SIZ, GL_UNSIGNED_SHORT, 0); //last 0 is offset in element-array
return;
}
void deinit_buffers() {
glDeleteBuffersARB(1, &vertex_buf);
glDeleteBuffersARB(1, &index_buf);
return;
}
PS。我建议不要在我使用的所有卡上使用索引它通常要慢得多,但当然这会占用更多内存。此外,在驱动程序上实现的索引也不是很好,有时会出现错误(即使在 nVidia 上,当然也可以在 ATI 上,如果满足正确的情况)
如果您还想要着色器,请参阅我的: