【问题标题】:How do I optimize displaying a large number of quads in OpenGL?如何优化在 OpenGL 中显示大量四边形?
【发布时间】:2012-12-14 22:29:41
【问题描述】:

我正在尝试使用 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 模式!?

编辑2: 所以我可以循环遍历所有 nx*ny 四边形并通过以下方式绘制每个四边形:

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

?

【问题讨论】:

  • 不要使用 glBegin 和 glEnd 而是使用顶点缓冲区。网上资料很多,google一下就知道了。顶点缓冲区允许您将顶点数据存储在 GPU 内存中,而不必每帧重新上传。这应该会给您带来巨大的性能提升。
  • 现代 OpenGL 没有GL_QUADSGL_QUAD_STRIP。使用GL_TRIANGLES 模拟它们。
  • 谢谢。用 2 个三角形替换每个四边形应该很容易,但我想重写三角形条会导致更高的 fps,因为我只能调用 glDrawElements nx 次(或只调用一次?)而不是 nx*ny 次?
  • 如果你使用退化三角形,你只需要调用一次,即没有像素被光栅化的三角形。或者您可以使用原始重启。我认为您在三角形上使用三角形条带的想法是正确的,但是对于更复杂的网格,三角形通常更快,因为它们可以更好地利用 PTC。
  • 需要明确的是,如果您只使用三角形而不是条形,您仍然可以通过一次调用 glDrawElements 将它们全部传递。

标签: qt opengl


【解决方案1】:

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

2/.使用vertex buffer objects。自 GL 1.5 起可用。

由于您无论如何都需要core profile 的 VBO(即现代 GL),您至少可以先掌握这一点。

【讨论】:

  • 谢谢!按照您的建议,我首先关注 VBO。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-23
      • 1970-01-01
      • 2011-08-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多