问题
I'm building a graphics API for OpenGL, which is based off the basic call-to-draw graphics style. Basically, instead of storing the data into the GPU, and call it using it's handle, give the info to draw what it should be drawing each update. I know it's slow, but it's simple and it's for non-performance critical applications. Anyway, is there any modern equivalent to glBegin/glEnd? It doesn't have to a call for every vertex, but a way where I can send the data each update, without storing the vertices in the gpu?
回答1:
You pretty much answered your own question.
is there any modern equivalent to glBegin/glEnd? It doesn't have to a call for every vertex, but a way where I can send the data each update, without storing the vertices in the gpu?
Basically no, the modern way is to use VAOs with VBOs (and IBOs).
If you're going to change the data within the VBO, then remember that you can change the mode
parameter in glBufferData.
GL_STREAM_DRAW - The data store contents will be modified once and used at most a few times.
GL_STATIC_DRAW - The data store contents will be modified once and used many times.
GL_DYNAMIC_DRAW - The data store contents will be modified repeatedly and used many times.
Then instead of using GL_STATIC_DRAW
, then use GL_DYNAMIC_DRAW
this will increase the FPS a lot compared to when using GL_STATIC_DRAW
, though this depends on the amount of data, and how frequent you change it. But try to limit it as much as you can, like don't update the data within the buffers if you don't actually need to.
You can read more about the different buffers on OpenGL's Wiki click here.
回答2:
Look for VAO / VBO usage that is what you want to implement.
In C/C++ code bellow is a simple example.
Input variable mode is GL_POINTS/TRIANGLES/QUADS/...
(as in glBegin()
)
This is also the only option with GLSL and core profile to pass attributes (glVertex/glNormal/...
is unknown in core for some time now)
//------------------------------------------------------------------------------
//--- 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. ---------------------------------------------------------------------
//------------------------------------------------------------------------------
If you do not want to use GLSL than you must change the code a little to something like this instead:
//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. i recommend not to use indexing its usually much slower on all cards i use but of course that takes more memory. Also indexing is not very good implemented on drivers sometimes gets buggy (even on nVidia and of course on ATI too if the correct circumstances are met)
If you want also shaders see my:
- complete GL+GLSL+VAO/VBO C++ example
来源:https://stackoverflow.com/questions/19628935/what-is-the-modern-opengl-equivalent-to-glbegin-glend