I need to achieve real-time performance (60fps) with my stereoscopic 3D application in c++ for video rendering, using OpenGL Quad Buffer. The application runs on Xubuntu Lts 14.04.
My hardware setup is composed by two Gopro cameras, a nvidia quadro k4000 card and a 120Hz display.
I'm experiencing image latency when watching the displayed stereo video.
There is no important delay when displaying only from one camera, in a mono setup, while not using the quad buffer functionality.
When measuring the times of execution of the display function from OpenGL it takes less than 10 mseconds to execute on most cycles, but there are spikes of more than 60ms that are probably the origin of such latency.
I've tested both with and without setting the sync to vblank option on the graphic's card, and the difference is very little, resulting in the same delayed image on the screen.
The code bellow is part of a more complex application so I hope the parts I provide at least shed a light on what I am trying to accomplish.
EDIT 1: This is the initialization code, outside the display function.
createTexture(&textureID, width, height);
createPBO(&pbo, width, height);
// map OpenGL buffer object for writing from CUDA
cudaGLMapBufferObject((void **)(Img, pbo);
// Unmap Buffers
cudaGLUnmapBufferObject(pbo);
// Paths for the stereo shaders' files
const std::string vertex_file_path = "VertexShader_stereo.vertexshader";
const std::string fragment_file_path = "FragmentShader_stereo.fragmentshader";
GLfloat vertices [] = {
// Position (2 elements) Texcoords (2 elements)
-1.0f, 1.0f, 0.0f, 0.0f, // Top-left
1.0f, 1.0f, 1.0f, 0.0f, // Top-right
1.0f, -1.0f, 1.0f, 1.0f, // Bottom-right
-1.0f, -1.0f, 0.0f, 1.0f // Bottom-left
};
GLushort elements [] = {
0, 1, 2, // indices of the first triangle
2, 3, 0 // indices of the second triangle
};
// Create a pixel buffer object for the right view
createPBO(&pbo_Right, width, height);
// map OpenGL buffer object for writing from CUDA
cudaGLMapBufferObject((void **)Img_Right, pbo_Right);
// Unmap Buffers
cudaGLUnmapBufferObject(pbo_Right);
// Create a vector buffer object
createVBO(&vbo, vertices, sizeof(vertices));
// Create a element buffer object
createEBO(&ebo, elements, sizeof(elements));
// Create shader program from the shaders
shaderProgram = LoadShader(vertex_file_path, fragment_file_path);
posAttrib = glGetAttribLocation(shaderProgram, "position");
texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
}
Edit 2: The createPBO function goes like this:
createPBO(GLuint* pbo_, unsigned int w, unsigned int h) {
// set up vertex data parameter
int num_texels = w * h;
int num_values = num_texels * 4;
int size_tex_data = sizeof(GLubyte) * num_values;
// Generate a buffer ID called a PBO (Pixel Buffer Object)
glGenBuffers(1, pbo_);
// Make this the current UNPACK buffer (OpenGL is state-based)
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, *pbo_);
// Allocate data for the buffer. 4-channel 8-bit image
glBufferData(GL_PIXEL_UNPACK_BUFFER, size_tex_data, NULL, GL_DYNAMIC_COPY);
cudaGLRegisterBufferObject(*pbo_);
}
Bellow is the part of my display function related to the OpenGL environment. I am using several glFinish() calls as an experiment, since it seems to be enhancing the execution times.
// Make this the current array buffer
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// Make this the current element array buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
// Activate shader program
glUseProgram(shaderProgram);
// Specify the layout of the vertex data
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, // index of of attribute in array
2, // size
GL_FLOAT, // type
GL_FALSE, // normalized
4 * sizeof(GLfloat), // stride
0); // offset in the array
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, // index of of attribute in array
2, // size
GL_FLOAT, // type
GL_FALSE, // normalized
4* sizeof(GLfloat), // stride
(void*)(2 * sizeof(GLfloat))); // offset in the array
glFinish();
// Specifies the target to which the buffer object is bound. GL_PIXEL_UNPACK_BUFFER affects the glTexSubImage2D command.
glBindBuffer( GL_PIXEL_UNPACK_BUFFER, pbo);
// Draw Left Back Buffer
glDrawBuffer(GL_BACK_LEFT);
// Specifies the target (GL_TEXTURE_2D) to which the texture is bound
glBindTexture(GL_TEXTURE_2D, textureID);
// Note: NULL indicates the data resides in device memory
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
// Draw a rectangle from the 2 triangles using 6 indices
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
// Specifies the target to which the buffer object is bound. GL_PIXEL_UNPACK_BUFFER affects the glTexSubImage2D command.
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_Right);
// Draw Right Back Buffer
glDrawBuffer(GL_BACK_RIGHT);
// Note: NULL indicates the data resides in device memory
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
// Draw a rectangle from the 2 triangles using 6 indices
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
glFinish();
// Disable and unbind objects
glDisableVertexAttribArray(posAttrib);
glDisableVertexAttribArray(texAttrib);
glUseProgram(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// Swap buffers
glutSwapBuffers();
glutPostRedisplay();
It is possible to make some optimizations? or is this a known problem in stereoscopic 3D?
Related
I am trying to render two different vertex collections on top of one another. Right now, my main loop renders one correctly when it's by itself, and the other correctly when it's by itself, but when I call both of my draw functions, I see a blank window. Why might this be happening?
The first draw call uses one shader, while the second draw call uses a different one. I don't clear the screen in between.
If it makes the code more clear, my shader programs are stored as class variables, as are the texture IDs after they're loaded elsehwere in my program.
This is my main loop:
while (true)
{
// Clear the colorbuffer
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawModel1(); // This works when drawModel2() is commented out
drawModel2(); // This works when drawModel1() is commented out
// Unbind buffer
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Swap the screen buffers
glfwSwapBuffers(_window);
}
My drawModel1() function renders points:
void drawModel1()
{
// Use the image shader
_img_shader.use();
// Feed the position data to the shader
glBindBuffer(GL_ARRAY_BUFFER, _img_pos_VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// Feed the color data to the shader
glBindBuffer(GL_ARRAY_BUFFER, _img_color_VBO);
glVertexAttribPointer(1, 3, GL_UNSIGNED_BYTE, GL_TRUE, 3 * sizeof(GLubyte), (GLvoid*)0);
glEnableVertexAttribArray(1);
// Set the projection matrix in the vertex shader
GLuint projM = glGetUniformLocation(_img_shader.program(), "proj");
glm::mat4 proj = _ndc * _persMat;
glUniformMatrix4fv(projM, 1, GL_TRUE, glm::value_ptr(proj));
// Set the view matrix in the vertex shader
GLuint viewM = glGetUniformLocation(_img_shader.program(), "view");
glUniformMatrix4fv(viewM, 1, GL_TRUE, glm::value_ptr(_viewMat));
// Draw the points
glBindVertexArray(_img_VAO);
glDrawArrays(GL_POINTS, 0, _numImageVertices);
// Disable attributes
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
And my drawModel2() function renders indexed triangles:
void drawModel2()
{
_model_shader.use();
// Load the mesh texture
GLuint texID = _loaded_textures.at(mesh.tex_file());
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texID);
glUniform1i(glGetUniformLocation(_model_shader.program(), "texture_img"), 0);
// Set the proj matrix in the vertex shader
GLuint nvpmM = glGetUniformLocation(_model_shader.program(), "npvm");
glm::mat4 npvm = _ndc * _persMat * _viewMat * mat;
glUniformMatrix4fv(nvpmM, 1, GL_FALSE, glm::value_ptr(npvm));
// Feed the position data to the shader
glBindBuffer(GL_ARRAY_BUFFER, mesh.pos_VBO());
GLuint pos_att = glGetAttribLocation(_model_shader.program(), "position");
glEnableVertexAttribArray(pos_att);
glVertexAttribPointer(pos_att, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
// Feed the texture coordinate data to the shader
glBindBuffer(GL_ARRAY_BUFFER, mesh.tex_VBO());
GLuint tex_coord_att = glGetAttribLocation(_model_shader.program(), "texCoords");
glEnableVertexAttribArray(tex_coord_att);
glVertexAttribPointer(tex_coord_att, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid*)0);
// Draw mesh
glBindVertexArray(mesh.VAO());
glDrawElements(GL_TRIANGLES, mesh.numIndices(), GL_UNSIGNED_SHORT, (void*)0);
// Disable attributes
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
// Release resources
glBindTexture(GL_TEXTURE_2D, 0);
}
You need to bind your vertex arrays at the start of your function, not right before the draw call itself. The Vertex Array is responsible for maintaining the state associated with a given object[-type] and any calls made that will setup state (like glVertexAttribPointer or glEnableVertexAttribArray) will be maintained on that Vertex Array. What you were essentially doing with your old code is that you were setting up state for your object, then switching to an entirely different VAO, then drawing, which meant model1 was using model2's bindings and setup, and vice-versa. Unless they have identical rules and setups, it's extremely unlikely that they'll both draw.
Incidentally, because VAO's store state, the only things that need to be in your draw calls are the draw call itself, and any data that changed that frame. So you'll want to consider spending some time refactoring your code, as it looks like most of those settings (like buffer binding) don't change on a frame-by-frame basis.
I am trying to write a fluid simulator that requires solving iteratively some differential equations (Lattice-Boltzmann Method). I want it to be a real-time graphical visualisation using OpenGL. I ran into a problem. I use a shader to perform relevant calculations on GPU. What I what is to pass the texture describing the state of the system at time t into the shader, shader performs the calculation and returns the state of the system at time t+dt, I render the texture on a quad and then pass the texture back into the shader. However, I found that I can not read and write to the same texture at the same time. But I am sure I have seen implementations of such calculations on GPU. How do they work around it? I think I saw a few discussion on a different way of working around the fact that OpenGL can read and write the same texture, but I could not quite understand them and adapt them to my case. To render to texture I use: glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexture, 0);
Here is my rendering routine:
do{
//count frames
frame_counter++;
// Render to our framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
glViewport(0,0,windowWidth,windowHeight); // Render on the whole framebuffer, complete from the lower left corner to the upper right
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Use our shader
glUseProgram(programID);
// Bind our texture in Texture Unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, renderTexture);
glUniform1i(TextureID, 0);
printf("Inv Width: %f", (float)1.0/windowWidth);
//Pass inverse widths (put outside of the cycle in future)
glUniform1f(invWidthID, (float)1.0/windowWidth);
glUniform1f(invHeightID, (float)1.0/windowHeight);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, quad_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
);
// Draw the triangles !
glDrawArrays(GL_TRIANGLES, 0, 6); // 2*3 indices starting at 0 -> 2 triangles
glDisableVertexAttribArray(0);
// Render to the screen
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Render on the whole framebuffer, complete from the lower left corner to the upper right
glViewport(0,0,windowWidth,windowHeight);
// Clear the screen
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Use our shader
glUseProgram(quad_programID);
// Bind our texture in Texture Unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, renderedTexture);
// Set our "renderedTexture" sampler to user Texture Unit 0
glUniform1i(texID, 0);
glUniform1f(timeID, (float)(glfwGetTime()*10.0f) );
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, quad_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
);
// Draw the triangles !
glDrawArrays(GL_TRIANGLES, 0, 6); // 2*3 indices starting at 0 -> 2 triangles
glDisableVertexAttribArray(0);
glReadBuffer(GL_BACK);
glBindTexture(GL_TEXTURE_2D, sourceTexture);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, windowWidth, windowHeight, 0);
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
}
What happens now, is that when I render to the framebuffer, I the texture I get as an input is empty, I think. But when I render the same texture on screen, it renders succesfully what I excpect.
Okay, I think I've managed to figure something out. Instead of rendering to a framebuffer what I can do is to use glCopyTexImage2D to copy whatever got rendered on the screen to a texture. Now, however, I have another issue: I can't understand if glCopyTexImage2D will work with a frame buffer. It works with onscreen rendering, but I am failing to get it to work when I am rendering to a framebuffer. Not sure if this is even possible in the first place. Made a separate question on this:
Does glCopyTexImage2D work when rendering offscreen?
I'm trying to implement a batch-rendering system using OpenGL, but the triangle I'm trying to render doesn't show up.
In the constructor of my Renderer-class, I'm initializing the VBO and VAO and also load my shader program (this does work, so the error can't be found here). The VBO is supposed to be capable of holding the maximum amount of vertices I'll permit which is defined in the header to be 30000. The VAO contains the information about how the data that I'll store in that buffer is laid out - in this case I use a struct called VertexData which only contains a 3D-vector ('vertex'), but will also contain stuff like colors etc. later on. So I create the buffer with the size I already stated, don't fill in any content yet and provide the layout using 'glVertexAttribPointer'. The '_vertexCount', as the name implies, counts the amount of vertices currently stored inside that buffer for drawing purposes.
The constructor of my Renderer-class (note that every private member variable defined in the header file starts with an _ ):
Renderer::Renderer(std::string vertexShaderPath, std::string fragmentShaderPath) {
_shaderProgram = ShaderLoader::createProgram(vertexShaderPath, fragmentShaderPath);
glGenBuffers(1, &_vbo);
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glEnableVertexAttribArray(0);
glBufferData(GL_ARRAY_BUFFER, RENDERER_MAX_VERTICES * sizeof(VertexData), NULL, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*) 0);
glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
_vertexCount = 0;
}
Once the initization is done, to render anything, the 'begin' procedure has to be called during the main-loop. This gets the current buffer with write permissions to fill in the vertices that should be rendered in the current frame:
void Renderer::begin() {
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
_buffer = (VertexData*) glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
}
After beginning, the 'submit' procedure can be called to add vertices and their corrosponding data to the buffer. I add the data to the location in memory the buffer currently points to, then advance the buffer and increase the vertexcount:
void Renderer::submit(VertexData* data) {
_buffer = data;
_buffer++;
_vertexCount++;
}
Finally, once all vertices are pushed to the buffer, the 'end' procedure will unmap the buffer to enable the actual rendering of the vertices, bind the VAO, use the shader program, render the provided vertices as triangles, unbind the VAO and reset the vertex count:
void Renderer::end() {
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(_vao);
glUseProgram(_shaderProgram);
glDrawArrays(GL_TRIANGLES, 0, _vertexCount);
glBindVertexArray(0);
_vertexCount = 0;
}
In the main loop I'm beginning the rendering, submitting three vertices to render a simple triangle and ending the rendering process. This is the most important part of that file:
Renderer renderer("../sdr/basicVertex.glsl", "../sdr/basicFragment.glsl");
Renderer::VertexData one;
one.vertex = glm::vec3(-1.0f, 1.0f, 0.0f);
Renderer::VertexData two;
two.vertex = glm::vec3( 1.0f, 1.0f, 0.0f);
Renderer::VertexData three;
three.vertex = glm::vec3( 0.0f,-1.0f, 0.0f);
...
while (running) {
...
renderer.begin();
renderer.submit(&one);
renderer.submit(&two);
renderer.submit(&three);
renderer.end();
SDL_GL_SwapWindow(mainWindow);
}
This may not be the most efficient way of doing this and I'm open for criticism, but my biggest problem is that nothing appears at all. The problem has to lie within those code snippets, but I can't find it - I'm a newbie when it comes to OpenGL, so help is greatly appreciated. If full source code is required, I'll post it using pastebin, but I'm about 99% sure that I did something wrong in those code snippets.
Thank you very much!
You have the vertex attribute disabled when you make the draw call. This part of the setup code looks fine:
glBindVertexArray(_vao);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glEnableVertexAttribArray(0);
glBufferData(GL_ARRAY_BUFFER, RENDERER_MAX_VERTICES * sizeof(VertexData), NULL, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*) 0);
At this point, the attribute is set up and enabled. But this is followed by:
glDisableVertexAttribArray(0);
Now the attribute is disabled, and there's nothing else in the posted code that enables it again. So when you make the draw call, you don't have a vertex attribute that is actually enabled.
You can simply remove the glDisableVertexAttribArray() call to fix this.
Another problem in your code is the submit() method:
void Renderer::submit(VertexData* data) {
_buffer = data;
_buffer++;
_vertexCount++;
}
Both _buffer and data are pointers to a VertexData structure. So the assignment:
_buffer = data;
is a pointer assignment. Instead of copying the data into the buffer, it modifies the buffer pointer. This should be:
*_buffer = *data;
This will copy the vertex data into the buffer, and leave the buffer pointer unchanged until you explicitly increment it in the next statement.
I have an OpenGL 1.1 ES 2D sprite engine that's based on one GL_TRIANGLE_FAN per sprite. The main rendering code that gets called per-sprite, per-frame is as follows:
void drawTexture(BitmapImage* aImage, short* vertices, float* texCoords,
ColorMap &colorMap, TInt xDest, TInt yDest, TInt aAlpha)
{
glPushMatrix();
glLoadIdentity();
glBindTexture(GL_TEXTURE_2D, textureId);
glVertexPointer(3, GL_SHORT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glColorPointer(RGBA_BYTES, GL_UNSIGNED_BYTE, 0, colorMap.GetMap());
TFloat scaleX, scaleY;
aImage->getScale(scaleX, scaleY);
glTranslatef((float)xDest, (float)yDest, 0.0f);
glScalef(scaleX, scaleY, 1.0f);
glRotatef(aImage->getRotAngle(), 0.0f, 0.0f, 1.0f);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glPopMatrix();
}
I've been told that switching to Vertex Buffer Objects (VBOs) will significantly increase the performance of rendering, so I'd like to do that. My research thus far has lead me to several examples showing how to set up individual vertex, color, and texture offset buffers, but good examples of how to interleave this data have been more elusive.
For example, I'm pretty sure this is how I'd set up to render with my vertex data in a VBO:
glGenBuffers(1, &batchBufferHandle);
glBindBuffer(GL_ARRAY_BUFFER, batchBufferHandle);
glBufferData(GL_ARRAY_BUFFER, dataSize, data, GL_STATIC_DRAW);
glVertextPointer(3, GL_SHORT, 0, 0);
glDrawElements(..., 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteBuffers(1, &batchBufferHandle);
Apparently I'd generate and bind similar buffers for texture coordinates and vertex color data, though I'm not 100% clear on how setting those up would differ.
My understanding is that the speed boost would come from rendering a bunch of these triangle fans in one "draw call", but what is a "draw call" in this context? DrawElements() gets called multiple times using this methodology, so that can't be it...?
Whatever the case, it would mean that I'd have to generate a VBO (or three) that contain all the data in series for a bunch of sprites. That can be difficult enough on its own given the legacy code I'm dealing with, but I also need to translate, scale, and rotate each individual sprite. Where does that data go in the VBO(s)?
My conclusion thus far is using VBOs is only helpful in the case of a SINGLE, but complex object. It would appear what I want to do is not possible -- provide OpenGL with a list of sprites to render (including all vertex, color, texture map, scale, rotation, and translation information for each).
Is my assessment correct or is there a way to do this (using OpenGL ES 1.1)?
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?
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 the OpenGL Wiki.
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