1

我正在尝试使用 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);

?

4

3 回答 3

2

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

2/。使用顶点缓冲对象。自 GL 1.5 起可用。

由于无论如何您都需要 VBO 来获取核心配置文件(即现代 GL),因此您至少可以先掌握这一点。

于 2012-12-14T22:54:54.137 回答
1

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

于 2012-12-14T23:21:54.363 回答
1

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

如果您想要四边形,请确保您查看的是GL 2.1 时代的文档,而不是新的东西

于 2012-12-14T23:28:29.433 回答