如何在OpenGL中优化显示大量四边形?

时间:2012-12-14 22:29:41

标签: qt opengl

我试图以有效的方式使用OpenGL和C ++显示在XY规则网格上定义的数学表面f(x,y):

struct XYRegularSurface {
    double x0, y0;
    double dx, dy;
    int    nx, ny;
    XYRegularSurface(int nx_, int ny_) : nx(nx_), ny(ny_) {
       z = new float[nx*ny];
    }
    ~XYRegularSurface() {
       delete [] z;
    }
    float& operator()(int ix, int iy) {
       return z[ix*ny + iy];
    }

    float x(int ix, int iy) {
       return x0 + ix*dx;
    }
    float y(int ix, int iy) {
       return y0 + iy*dy;
    }
    float zmin(); 
    float zmax(); 
    float* z; 
 };

到目前为止,这是我的OpenGL绘图代码:

void color(QColor & col) {
    float r = col.red()/255.0f;
    float g = col.green()/255.0f;
    float b = col.blue()/255.0f;
    glColor3f(r,g,b);
}

void paintGL_XYRegularSurface(XYRegularSurface &surface, float zmin, float zmax) {
    float x, y, z;

    QColor col;
    glBegin(GL_QUADS);
    for(int ix = 0; ix < surface.nx - 1; ix++) {
        for(int iy = 0; iy < surface.ny - 1; iy++) {
            x = surface.x(ix,iy);
            y = surface.y(ix,iy);
            z = surface(ix,iy);
            col = rainbow(zmin, zmax, z);color(col);
            glVertex3f(x, y, z);

            x = surface.x(ix + 1, iy);
            y = surface.y(ix + 1, iy);
            z = surface(ix + 1,iy);
            col = rainbow(zmin, zmax, z);color(col);
            glVertex3f(x, y, z);

            x = surface.x(ix + 1, iy + 1);
            y = surface.y(ix + 1, iy + 1);
            z = surface(ix + 1,iy + 1);
            col = rainbow(zmin, zmax, z);color(col);
            glVertex3f(x, y, z);

            x = surface.x(ix, iy + 1);
            y = surface.y(ix, iy + 1);
            z = surface(ix,iy + 1);
            col = rainbow(zmin, zmax, z);color(col);
            glVertex3f(x, y, z);

        }
    }
    glEnd();
}

问题是这很慢,nx = ny = 1000且fps~ = 1。 如何优化它以加快速度?

编辑:根据你的建议(谢谢!)关于VBO 我补充说:

float* XYRegularSurface::xyz() {
    float* data = new float[3*nx*ny];
    long i = 0;
    for(int ix = 0; ix < nx; ix++) {
        for(int iy = 0; iy < ny; iy++) {
            data[i++] = x(ix,iy);
            data[i++] = y(ix,iy);
            data[i] = z[i]; i++;
        }
    }
    return data;
}

我想我理解如何创建VBO,将其初始化为xyz()并一次性将其发送到GPU,但是如何在绘制时使用VBO。我知道这可以在顶点着色器或glDrawElements中完成吗?我认为后者更容易?如果是这样的话:我没有在glDrawElements的文档中看到任何QUAD模式!?

EDIT2: 因此,我可以循环遍历所有nx * ny四边形并通过以下方式绘制:

GL_UNSIGNED_INT indices[4];
// ... set indices
glDrawElements(GL_QUADS, 1, GL_UNSIGNED_INT, indices);

3 个答案:

答案 0 :(得分:2)

1 /。使用display lists来缓存GL命令 - 避免重新计算顶点和昂贵的每顶点调用开销。如果数据已更新,则需要查看客户端顶点数组(不要与VAO混淆)。现在忽略这个选项......

2 /。使用vertex buffer objects。从GL 1.5开始提供。

既然你需要core profile的VBO(即现代GL),你至少可以先掌握它。

答案 1 :(得分:1)

嗯,你问了一个相当开放的问题。我建议使用现代(3.0+)OpenGL来处理所有事情。几乎任何新的OpenGL功能的关键是提供更快的方式来做事。像其他人建议的那样,使用数组(顶点)缓冲区对象和顶点数组对象。也使用元素数组(索引)缓冲区对象。大多数GPU都有一个'转换后缓存',它存储最后几个转换顶点,但这只能在调用glDraw * Elements系列函数时使用。我还建议你在VBO中存储一个平面网格,其中每个顶点y = 0。从顶点着色器中的高度图纹理中对y进行采样。如果这样做,只要曲面发生变化,您只需更新高度贴图纹理,这比更新VBO更容易。使用浮点或整数纹理格式之一作为高度图,因此您不必限制您的值介于0和1之间。

答案 2 :(得分:1)

  

如果是这样的话:我没有在glDrawElements的文档中看到任何QUAD模式!?

如果你想要四边形,请确保你正在查看GL 2.1-era docs,而不是new stuff