2012-11-21 89 views
3

我见过一个类似的帖子关于这个问题here,但是,我的问题有点不同。OpenGL渲染大量的动态2D圈

我有一个二维情节,将由不同大小的圆圈组成。目前,我的渲染方案使用显示列表来存储预绘制的圆,可以由用户使用glScalef/glTranslatef主动调整大小并进行翻译。但是,由于我渲染了数千个圈子,所以调整大小和绘制变得非常缓慢。每个圆可以有不同的半径和颜色,所以这些东西必须在循环内完成。

当用户改变说圆圈的大小时,我可以尝试改善圆圈渲染的速度会有什么?我已经看过VBO,就像上面的链接说的那样,但是对于这种类型的应用程序,我的对象不断变化的大小,我会得到多少性能提升,这并不明确。

+2

你应该看看现代的OpenGL。在现代OpenGL中,“glScale”/“glTranslate”和家族不再存在。与您使用的旧版本相比,性能提升可能非常明显。如果您可以使用OpenGL 3.1或更高版本,请执行。 [看看这个页面](http://duriansoftware.com/joe/An-intro-to-modern-OpenGL.-Chapter-1:-The-Graphics-Pipeline.html)介绍现代OpenGL。 – Cornstalks

+0

“成千上万的圈子”有多少个圈子? 10000? “非常缓慢”的速度有多慢? >每帧100ms? – genpfault

回答

1

因为我渲染数千圈的,调整大小和绘图变得极其缓慢

只需顶点数组,这是获取有关每帧为60ms上的英特尔高清显卡3000 10000圈子:

// g++ -O3 circles.cpp -o circles -lglut -lGL 
#include <GL/glut.h> 
#include <vector> 
#include <iostream> 
#include <cmath> 
using namespace std; 

// returns a GL_TRIANGLE_FAN-able buffer containing a unit circle 
vector<float> glCircle(unsigned int subdivs = 20) 
{ 
    vector<float> buf; 

    buf.push_back(0); 
    buf.push_back(0); 
    for(unsigned int i = 0; i <= subdivs; ++i) 
    { 
     float angle = i * ((2.0f * 3.14159f)/subdivs); 
     buf.push_back(cos(angle)); 
     buf.push_back(sin(angle)); 
    } 

    return buf; 
} 

struct Circle 
{ 
    Circle() 
    { 
     x = (rand() % 200) - 100; 
     y = (rand() % 200) - 100; 
     scale = (rand() % 10) + 4; 
     r = rand() % 255; 
     g = rand() % 255; 
     b = rand() % 255; 
     a = 1; 
    } 

    float x, y; 
    float scale; 
    unsigned char r, g, b, a; 
}; 

vector<Circle> circles; 
vector<float> circleGeom; 
void init() 
{ 
    srand(0); 
    for(size_t i = 0; i < 10000; ++i) 
     circles.push_back(Circle()); 
    circleGeom = glCircle(100); 
} 

void display() 
{ 
    int beg = glutGet(GLUT_ELAPSED_TIME); 

    glClear(GL_COLOR_BUFFER_BIT); 

    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    double w = glutGet(GLUT_WINDOW_WIDTH); 
    double h = glutGet(GLUT_WINDOW_HEIGHT); 
    double ar = w/h; 
    glOrtho(-100 * ar, 100 * ar, -100, 100, -1, 1); 

    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 

    glEnableClientState(GL_VERTEX_ARRAY); 
    glVertexPointer(2, GL_FLOAT, 0, &circleGeom[0]); 

    for(size_t i = 0; i < circles.size(); ++i) 
    { 
     Circle& c = circles[i]; 
     c.scale = (rand() % 10) + 4; 

     glPushMatrix(); 
     glTranslatef(c.x, c.y, 0); 
     glScalef(c.scale, c.scale, 0); 
     glColor3ub(c.r, c.g, c.b); 
     glDrawArrays(GL_TRIANGLE_FAN, 0, circleGeom.size()/2); 
     glPopMatrix(); 
    } 

    glDisableClientState(GL_VERTEX_ARRAY); 

    glutSwapBuffers(); 

    int end = glutGet(GLUT_ELAPSED_TIME); 
    double elapsed = (double)(end - beg); 
    cout << elapsed << "ms" << endl; 
} 

void timer(int extra) 
{ 
    glutPostRedisplay(); 
    glutTimerFunc(16, timer, 0); 
} 

int main(int argc, char **argv) 
{ 
    glutInit(&argc, argv); 
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); 
    glutInitWindowSize(600, 600); 
    glutCreateWindow("Circles"); 

    init(); 

    glutDisplayFunc(display); 
    glutTimerFunc(0, timer, 0); 
    glutMainLoop(); 
    return 0; 
} 
0

ARB_instanced_arrays基于实例的实例可能是最干净的。

您将有一个带M个顶点的圆圈,您将绘制N次,将您的每个圆弧的x/y位置,半径和颜色存储为顶点属性,并适当地使用glVertexAttribDivisor()

如果你想要半径自适应LOD,就会变得更加棘手。你可能不得不为此挖掘几何着色器。

0

第二次使用带有glDrawElementsInstanced或glDrawArraysInstanced的实例化数组作为干净的解决方案,可以很好地传递给其他类型的几何体。

如果你想要/需要坚持使用OpenGL 2(例如,必须在iThing上运行),并且你只需要圆形,也可以考虑点精灵。每个圆的起点是顶点的顶点值。将半径存储为纹理坐标的S值,表面法线的X值,无论如何。启用混合,GL_PROGRAM_POINT_SIZE,可能点平滑;并写一个顶点着色器,它将gl_PointSize设置为你想要的半径。即时圈子。