Soup71 Soup71 - 2 months ago 15
C++ Question

Drawing thousands of polygons with OpenGL VBO

I'm trying to create OpenGL application capable of rendering over 100000 2d primitive objects.

AFAIK, it should be possible using modern OpenGL and VBO.

So here is the code (uses Qt):

#include "paintwidget.h"

PaintWidget::PaintWidget(QGLWidget *parent) : QGLWidget(parent)
{
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(updateTimer()));
timer->start(16);
}

GLuint indices[100000];

void PaintWidget::initializeGL()
{
VBOBuffer= new QGLBuffer(QGLBuffer::VertexBuffer);
VBOBuffer->create();
VBOBuffer->bind();
VBOBuffer->setUsagePattern(QGLBuffer::DynamicDraw);
VBOBuffer->allocate(100000 * 10 * sizeof(double));

// load data into VBO:
for(int i=0; i<100000; i++)
{

GLdouble vertices[] = {100 + (double)i * 100, 100 + (double)i * 100,
100 + (double)i * 100, 200 + (double)i * 100,
200 + (double)i * 100, 200 + (double)i * 100,
300 + (double)i * 100, 150 + (double)i * 100,
200 + (double)i * 100, 100 + (double)i * 100 };

VBOBuffer->write(i * 10 * sizeof(double), vertices, 10 * sizeof(double));
}

// fill indices array:
for(int i=0; i<100000; i+=10)
{
indices[i] = i;
indices[i+1] = i+1;
indices[i+2] = i+1;
indices[i+3] = i+2;
indices[i+4] = i+2;
indices[i+5] = i+3;
indices[i+6] = i+3;
indices[i+7] = i+4;
indices[i+8] = i+4;
indices[i+9] = i;
}
}

void PaintWidget::paintEvent(QPaintEvent*)
{
QPainter paint(this);
paint.beginNativePainting();

glEnable(GL_LINE_SMOOTH);
glEnable(GL_MULTISAMPLE);
glClearColor(0.1, 0.96, 0.1, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_DOUBLE, 0, 0);

// draw my polygons:
for(int i=0; i<100000; i+=5)
{
glDrawArrays(GL_POLYGON, i, 5);
}
glDisableClientState(GL_VERTEX_ARRAY);

paint.endNativePainting();
}

void PaintWidget::updateTimer()
{
paintEvent(nullptr);
}


This code simply renders 100000 polygons every 16ms.

And I'm not really satisfied with the prefomance of my code. It loads processor quite a lot (despite using of VBO). Can I make it more efficient, or this is the best perfomance?

Thanks.

Answer

Well there's your problem:

// draw my polygons:
for(int i=0; i<100000; i+=5)
{
    glDrawArrays(GL_POLYGON, i, 5);
}

You're doing 100000 draw calls for that single VBO. That's what taxing your CPU. For comparison the latest Doom on averages requires less than 1500 draw calls for a whole scene.

You should draw your whole geometry with a single call to glDrawArrays or glDrawElements. BTW: GL_POLYGON is no longer supported by modern OpenGL (the only supported primitive a GL_POINTS, GL_LINE* and GL_TRIANGLE*).

If your concern is about starting a new primitive, with glDrawElements you can specify a special index that restarts. Or (and that's actually the preferred method) just draw it as indexed triangles. Indexing is the key for efficient caching so if you want maximum performance that's the way to go.