Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draw many of the same object quickly in OpenGL

Tags:

c++

opengl

So I'm working on a game and I need to draw a lot of the same object. Same shape, same size, same color, just different locations.

Right now my setup is like this.

I have some class Renderer where object that want to draw on the screen can call static void addVertex(float x, float y, float z); which will store the vertex into an std::vector. When everyone is done drawing static void draw(); in Renderer is called where everything is stuffed into a VBO and drawn onto the screen.

draw looks like this:

void Renderer::draw() {
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, _quadID);
    glBufferSubDataARB(GL_QUADS, 0, _vertexBuffer.dataSize(), _vertexBuffer.toArray());

    glColorPointer(4, GL_FLOAT, 0, _colorBuffer.toArray());

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
    glVertexPointer(3, GL_FLOAT, 0, _vertexBuffer.toArray());

    glDrawArrays(GL_QUADS, 0, (_vertexBuffer.size() / 3));
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);

    glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);

    _vertexBuffer.clear();
    _colorBuffer.clear();
}

Where _vertexBuffer and _colorBuffer are of a class template <class T> Buffer which is more or less a managed std::vector<T> for my purposes.

With this setup I can get about 300 things on screen before I start slowing down. Right now everything is a GL_QUAD. Bear in mind I'm a little new to OpenGL, if the above is embarrassing I'm sorry.

How can I improve this to account for like polygons?

like image 824
SpaceFace Avatar asked Feb 19 '12 19:02

SpaceFace


2 Answers

On ~modern hardware, instancing is the way to go.

The idea is that you send the geometry to your GPU once (one draw call), specifying how many instances you want to draw (primCount parameter).

Then in the vertex shader you can use the intrinsic input variable gl_InstanceID to learn which instance is being rendered and then use the appropriate transformation for it. This approach implies that you should have the transformations for all your instances available in the vertex shader, for example in an Uniform Buffer Object.

Edit: The glVertexAttribDivisor function is very useful together with instancing; it basically allows to have some per-vertex attributes together with some per-instance attributes.

like image 172
Kos Avatar answered Nov 10 '22 09:11

Kos


There's beautiful thing in OpenGL, called Display list. NeHe production has tutorial on them which should provide all necessary info and examples. But basically:

GLuint displayList; // This should be class attribute
displayList = glGenLists(1);    
glNewList(displayList,GL_COMPILE);
Renderer::draw();
glEndList();

And in real draw method just:

glCallList( displayList);

Don't forget to actualize precompiled display list each time you add/remove something.

like image 44
Vyktor Avatar answered Nov 10 '22 10:11

Vyktor