3. 使用VAO和VBO绘制矩形

使用VAO和VBO绘制矩形 学习卡片

任务目标

在Qt窗口中通过OpenGL绘制一个四边形。核心实现方式是将四边形拆分为两个三角形进行渲染,并为每个顶点赋予不同的颜色,使四边形表面产生平滑的颜色渐变效果。

环境依赖

本案例基于 Qt 5.12+(含OpenGL模块)与 OpenGL 3.3 Core Profile。在项目文件 .pro 中添加:

QT += openglwidgets
LIBS += -lopengl32 -lglu32   # Windows下需链接OpenGL库

完整实现代码

创建 QuadWidget 类,继承自 QOpenGLWidget 并实现核心渲染逻辑。着色器使用GLSL 330 core语法。

#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>
#include <QVector>

class QuadWidget : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Core
{
    Q_OBJECT
public:
    explicit QuadWidget(QWidget *parent = nullptr) : QOpenGLWidget(parent) {}

protected:
    void initializeGL() override {
        initializeOpenGLFunctions();

        // 1. 顶点数据:两个三角形组成四边形(逆时针顺序)
        // 三角形1: v0-v1-v2, 三角形2: v0-v2-v3
        GLfloat vertices[] = {
            // 位置(x,y)    // 颜色(R,G,B)
            -0.8f, -0.8f,   1.0f, 0.0f, 0.0f,  // v0 左下-红
             0.8f, -0.8f,   0.0f, 1.0f, 0.0f,  // v1 右下-绿
             0.8f,  0.8f,   0.0f, 0.0f, 1.0f,  // v2 右上-蓝
            -0.8f, -0.8f,   1.0f, 0.0f, 0.0f,  // v0 重复(三角形2)
             0.8f,  0.8f,   0.0f, 0.0f, 1.0f,  // v2 重复(三角形2)
            -0.8f,  0.8f,   1.0f, 1.0f, 0.0f   // v3 左上-黄
        };

        // 2. 创建并绑定VBO
        GLuint vbo;
        glGenBuffers(1, &vbo);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

        // 3. 创建并绑定VAO
        glGenVertexArrays(1, &vao);
        glBindVertexArray(vao);

        // 4. 配置顶点属性
        // 位置属性(location=0): 每2个float
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)0);
        glEnableVertexAttribArray(0);
        // 颜色属性(location=1): 每3个float,偏移2个float
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));
        glEnableVertexAttribArray(1);

        // 5. 编译着色器
        program = new QOpenGLShaderProgram(this);
        program->addShaderFromSourceCode(QOpenGLShader::Vertex,
            "#version 330 core\n"
            "layout(location=0) in vec2 aPos;\n"
            "layout(location=1) in vec3 aColor;\n"
            "out vec3 vColor;\n"
            "void main() {\n"
            "    gl_Position = vec4(aPos, 0.0, 1.0);\n"
            "    vColor = aColor;\n"
            "}\n");
        program->addShaderFromSourceCode(QOpenGLShader::Fragment,
            "#version 330 core\n"
            "in vec3 vColor;\n"
            "out vec4 fragColor;\n"
            "void main() {\n"
            "    fragColor = vec4(vColor, 1.0);\n"
            "}\n");
        program->link();
        program->bind();

        glBindVertexArray(0); // 解绑VAO
    }

    void paintGL() override {
        glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        program->bind();
        glBindVertexArray(vao);
        glDrawArrays(GL_TRIANGLES, 0, 6);  // 6个顶点 = 2个三角形
        glBindVertexArray(0);
    }

    void resizeGL(int w, int h) override {
        glViewport(0, 0, w, h);
    }

private:
    GLuint vao;
    QOpenGLShaderProgram *program;
};

运行与验证

主函数入口(main.cpp):

#include <QApplication>
#include "QuadWidget.h"

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QuadWidget w;
    w.resize(600, 600);
    w.show();
    return app.exec();
}

验证步骤:

  1. 在Qt Creator中打开项目,构建并运行。
  2. 观察窗口中央是否出现一个四边形,其四个顶点颜色分别为:左下红色、右下绿色、右上蓝色、左上黄色。
  3. 四边形内部颜色应呈现平滑渐变过渡(非突变分界线),说明两个三角形共享边上的颜色插值正确。
  4. 若四边形中间出现明显对角线色差,说明顶点顺序或颜色配置有误,需检查顶点数据。

通过条件:窗口显示完整四边形,且颜色从红→绿→蓝→黄连续渐变,无撕裂或闪烁。

v0 红 v1 绿 v2 蓝 v3 黄 △1: v0-v1-v2 △2: v0-v2-v3

上图展示了四边形顶点颜色布局与两个三角形的拆分方式。渲染时OpenGL对每个三角形内部进行逐像素颜色插值,由于两个三角形共享对角线(v0-v2),整条对角线上颜色连续,因此四边形整体呈现无缝渐变效果。