起因

学了点OpenGL的基础知识,想找个GUI框架来显示渲染结果。一开始用GLFW,但那个窗口太简陋了,连个按钮都没有。后来发现Qt自带QOpenGLWidget,可以很方便地把OpenGL嵌入到Qt界面里。于是就试着写了个能旋转的立方体。

基本原理

OpenGL渲染的基本流程:

  1. 定义顶点数据(三角形的三个点)
  2. 把顶点数据传到GPU(VBO)
  3. 告诉GPU怎么解释这些数据(VAO)
  4. 写顶点着色器(处理每个顶点的位置变换)
  5. 写片元着色器(处理每个像素的颜色)
  6. 绘制

听起来简单,但每一步都有坑。

在Qt中使用OpenGL

继承QOpenGLWidget,重写三个虚函数:

class MyGLWidget : public QOpenGLWidget, protected QOpenGLFunctions {
protected:
    void initializeGL() override;      // 初始化OpenGL
    void resizeGL(int w, int h) override; // 窗口大小改变时调用
    void paintGL() override;           // 每帧绘制
};

initializeGL里做初始化:编译着色器、创建VBO/VAO。

resizeGL里设置视口和投影矩阵。

paintGL里做实际的绘制。

着色器代码

顶点着色器(GLSL):

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;

out vec3 ourColor;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main() {
    gl_Position = projection * view * model * vec4(aPos, 1.0);
    ourColor = aColor;
}

片元着色器:

#version 330 core
in vec3 ourColor;
out vec4 FragColor;

void main() {
    FragColor = vec4(ourColor, 1.0);
}

这段代码的意思是:把3D坐标通过model、view、projection三个矩阵变换到屏幕坐标,然后把顶点颜色插值传给片元着色器。

立方体数据

一个立方体有6个面,每个面2个三角形,每个三角形3个顶点。所以总共36个顶点。每个顶点需要位置(xyz)和颜色(rgb)。

float vertices[] = {
    // positions         // colors
    -0.5f, -0.5f, -0.5f,  1.0f, 0.0f, 0.0f,  // 红
     0.5f, -0.5f, -0.5f,  1.0f, 0.0f, 0.0f,
     0.5f,  0.5f, -0.5f,  1.0f, 0.0f, 0.0f,
    // ... 以此类推,36个顶点
};

旋转动画

用QTimer定时刷新,每帧改变model矩阵的旋转角度:

void MyGLWidget::paintGL() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    QMatrix4x4 model;
    model.rotate(angle, 1.0f, 1.0f, 0.5f);  // 绕(1,1,0.5)轴旋转
    
    shaderProgram->bind();
    shaderProgram->setUniformValue("model", model);
    // ... 绘制
}

// 在initializeGL中设置定时器
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, [this]() {
    angle += 2.0f;
    update();  // 触发paintGL
});
timer->start(16);  // 约60fps

踩过的坑

效果

最终效果是一个在深色背景上缓缓旋转的彩色立方体,每个面颜色不同。虽然很简单,但整个流程跑通了:着色器编译、顶点数据、矩阵变换、实时渲染。

学习资源推荐

OpenGL的学习资料其实不多,但有几个质量特别高的:

赵新政的教程在Telegram上可以免费获取,LearnOpenGL也有中文社区翻译版。这两个配合着看效果最好。

下一步打算加个光照模型,让立方体看起来有立体感。然后试试加载3D模型文件。