使用 OpenGL VBO 绘制数千个多边形

Posted

技术标签:

【中文标题】使用 OpenGL VBO 绘制数千个多边形【英文标题】:Drawing thousands of polygons with OpenGL VBO 【发布时间】:2016-09-11 15:00:28 【问题描述】:

我正在尝试创建能够渲染超过 100000 个 2d 原始对象的 OpenGL 应用程序。

AFAIK,使用现代 OpenGL 和 VBO 应该是可能的。

下面是代码(使用 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);

此代码仅每 16 毫秒渲染 100000 个多边形。

而且我对我的代码的性能并不满意。它会大量加载处理器(尽管使用了 VBO)。我可以让它更高效,还是这是最好的性能?

谢谢。

【问题讨论】:

您正在为每个多边形使用一个绘制调用。难怪这很慢,并且会消耗你所有的 GPU 负载。而且您根本没有使用现代 OpenGL - 现代 GL 没有 GL_POLYGON,也没有 glEnableClientStateglVertexPointer 【参考方案1】:

那是你的问题:

// draw my polygons:
for(int i=0; i<100000; i+=5)

    glDrawArrays(GL_POLYGON, i, 5);

您正在为单个 VBO 执行 100000 次绘制调用。这就是对你的 CPU 征税的原因。相比之下,最新的《毁灭战士》平均需要不到 1500 次绘制调用来完成整个场景。

您应该通过调用glDrawArraysglDrawElements 来绘制整个几何图形。顺便说一句:现代 OpenGL 不再支持 GL_POLYGON(唯一支持的原语 GL_POINTS、GL_LINE* 和 GL_TRIANGLE*)。

如果您关心的是开始一个新的原语,with glDrawElements you can specify a special index that restarts。或者(这实际上是首选方法)只是将其绘制为索引三角形。索引是高效缓存的关键,因此如果您想要获得最佳性能,这就是您要走的路。

【讨论】:

谢谢,它确实有帮助,但是我应该如何索引这个 VBO?我已经尝试了一些配置,但它们根本不起作用。 @Soup71:创建一个元素数组缓冲区(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, …)),用索引数组填充它,然后glDrawElements(…, NULL)。您已经有了索引创建代码,您也可以使用 QGLBuffer 及其write 方法来创建索引。请记住,顶点数组对象仅涵盖顶点属性,因此元素索引缓冲区必须单独绑定和维护。

以上是关于使用 OpenGL VBO 绘制数千个多边形的主要内容,如果未能解决你的问题,请参考以下文章

iOS OpenGL ES 2.0 VBO 混淆

VBO:未绘制数组

使用着色器和 VBO 绘制四边形

OpenGL VBO - 数组步幅错误?

用户有啥办法可以通过在 c++ 中使用 opengl 来决定他想要绘制的多边形吗?

未能在 OpenGL/Android 中使用 VBO