QOpenGLFunctions_2_1 与 OpenGL 的区别
核心区别:Qt 封装器 vs. 图形标准
OpenGL 是一种用于渲染 2D 和 3D 向量图形的跨语言、跨平台的应用程序编程接口(API)规范。它本身不是一个可执行文件或库,而是一系列函数的标准定义。你的显卡驱动程序提供了这个标准的具体实现。
QOpenGLFunctions_2_1
是 Qt 框架提供的一个 C++ 类。它的主要目的是帮助你在 Qt 应用中安全、方便地使用 OpenGL 2.1 版本的函数。
你可以把它想象成一个遥控器:
- OpenGL 是你的电视机(功能强大的底层硬件和软件)。
QOpenGLFunctions_2_1
是一个精心设计的遥控器,它让你能够轻松、安全地控制电视机的特定功能(OpenGL 2.1 功能),而无需自己去处理复杂的电源线和内部电路。
详细对比
特 性 | QOpenGLFunctions_2_1 | OpenGL (标准) |
---|---|---|
本质 | 一个 C++ 类 | 一个图形 API 规范 |
所属 | Qt 框架 | Khronos Group(标准制定者) |
作用 | 封装和加载 OpenGL 函数指针 | 定义了一套用于渲染的函数集合 |
版本 | 对应 OpenGL 2.1 和 OpenGL ES 2.0 | 拥有多个版本(如 1.x, 2.1, 3.x, 4.x, 4.6等) |
管线 | 仅支持固定管线(Fixed-Function Pipeline) | 早期版本支持固定管线,现代版本(3.1+)主推可编程管线(Programmable Pipeline) |
使用方式 | 在 QOpenGLWidget 中继承并调用 initializeOpenGLFunctions() 方法后,即可直接使用 gl* 函数,无需手动加载。 | 你需要通过显卡驱动程序提供的特定机制(如 GLAD、GLEW 或 Qt 提供的类)来获取函数指针,才能调用它们。 |
移植性 | 跨平台,由 Qt 负责处理底层差异。 | 规范是跨平台的,但你需要依赖具体平台的工具来访问它。 |
总结
QOpenGLFunctions_2_1
实际上是 Qt 为你提供的一座“桥梁”,它将你编写的 C++ 代码与底层的 OpenGL 标准实现连接起来。
当你使用 QOpenGLFunctions_2_1
时,你调用的 glBegin()
、glVertex3f()
等函数,实际上是这个类在幕后帮你找到了显卡驱动程序中对应的函数地址,并进行了调用。这使得你的代码更加简洁,并且确保了在不同操作系统上的兼容性。
简而言之,你不能“使用”OpenGL,你只能使用一个实现了 OpenGL 规范的库或类。而 QOpenGLFunctions_2_1
就是 Qt 为你提供的最方便、最常用的一个。
简单流程:
1、继承QOpenGLFunctions_2_1(OpenGL 2.1 功能)
2、初始化 initializeGL(),核心initializeOpenGLFunctions(),必须调用初始化所有opengl2.1的指针
3、处理窗口尺寸变化
- 函数会在窗口第一次显示或每次被调整大小时被调用。在这里,你应该设置你的视口(Viewport)和投影矩阵(Projection Matrix),以确保场景能够正确地适配窗口的宽高比。
4、paintGL()
函数是你的主渲染循环。Qt 会在需要更新窗口内容时自动调用它。你所有的绘制逻辑都应该放在这里。
5、画图形,立方体的绘制逻辑
一个立方体由 6 个面组成,每个面都是一个四边形。如果使用
GL_QUADS
,每个面需要 4 个顶点。如果使用GL_TRIANGLES
,每个面需要 6 个顶点(两个三角形)。在QOpenGLFunctions_2_1
的示例中,使用GL_QUADS
是最直观的方式。下面是
drawCube()
函数的实现细节:
- 开始绘制:调用
glBegin(GL_QUADS)
,告诉 OpenGL 接下来我们将要定义四边形。- 定义每个面:
- 为每个面设置一个唯一的颜色 (
glColor3f
)。- 按逆时针或顺时针顺序定义该面的 4 个顶点 (
glVertex3f
)。这个顺序很重要,因为它决定了面的“正面”(Face Culling,如果你启用了这个功能)。
- 结束绘制:调用
glEnd()
,结束四边形的定义。
代码:
myopenglwidget.h
#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions_2_1>
#include <QTimerEvent>
#include <QKeyEvent>
const double M_PI = 3.14159265358979323846;// 继承 QOpenGLWidget 和 QOpenGLFunctions_2_1
// 这样我们既可以使用 Qt 的 OpenGL 窗口,又可以直接调用 OpenGL 2.1 的函数
class MyOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions_2_1
{Q_OBJECTpublic:explicit MyOpenGLWidget(QWidget *parent = nullptr) : QOpenGLWidget(parent) {// 启用计时器以实现动画效果startTimer(16); // 大约 60 FPSm_angle = 0.0f;}protected:// 初始化 OpenGL 状态void initializeGL() override {// 必须调用此函数,它会加载 QOpenGLFunctions_2_1 提供的所有函数指针initializeOpenGLFunctions();// 设置背景色为深蓝色glClearColor(0.2f, 0.2f, 0.4f, 1.0f);// 启用深度测试,以确保正确的 3D 渲染效果glEnable(GL_DEPTH_TEST);}// 处理窗口尺寸变化void resizeGL(int w, int h) override {// 设置视口大小,使其与窗口尺寸匹配glViewport(0, 0, w, h);// 选择投影矩阵glMatrixMode(GL_PROJECTION);// 重置矩阵为单位矩阵glLoadIdentity();// 设置透视投影// fovy: 视野角度, aspect: 宽高比, zNear: 近剪裁平面, zFar: 远剪裁平面// 这里我们使用一个简单的透视投影来模拟3D效果GLdouble aspect = (GLdouble)w / (GLdouble)h;gluPerspective(45.0, aspect, 0.1, 100.0);}// 绘制场景void paintGL() override {// 清空颜色缓冲区和深度缓冲区glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 选择模型视图矩阵glMatrixMode(GL_MODELVIEW);// 重置矩阵glLoadIdentity();// 将模型平移到屏幕中央glTranslatef(0.0f, 0.0f, -5.0f);// 根据角度旋转模型,实现动画效果glRotatef(m_angle, 1.0f, 1.0f, 0.0f);// 使用固定管线绘制一个彩色立方体drawCube();}// 绘制立方体的辅助函数void drawCube() {glBegin(GL_QUADS);// 前面glColor3f(1.0f, 0.0f, 0.0f); // 红色glVertex3f(-1.0f, -1.0f, 1.0f);glVertex3f( 1.0f, -1.0f, 1.0f);glVertex3f( 1.0f, 1.0f, 1.0f);glVertex3f(-1.0f, 1.0f, 1.0f);// 后面glColor3f(0.0f, 1.0f, 0.0f); // 绿色glVertex3f(-1.0f, -1.0f, -1.0f);glVertex3f(-1.0f, 1.0f, -1.0f);glVertex3f( 1.0f, 1.0f, -1.0f);glVertex3f( 1.0f, -1.0f, -1.0f);// 顶部glColor3f(0.0f, 0.0f, 1.0f); // 蓝色glVertex3f(-1.0f, 1.0f, -1.0f);glVertex3f(-1.0f, 1.0f, 1.0f);glVertex3f( 1.0f, 1.0f, 1.0f);glVertex3f( 1.0f, 1.0f, -1.0f);// 底部glColor3f(1.0f, 1.0f, 0.0f); // 黄色glVertex3f(-1.0f, -1.0f, -1.0f);glVertex3f( 1.0f, -1.0f, -1.0f);glVertex3f( 1.0f, -1.0f, 1.0f);glVertex3f(-1.0f, -1.0f, 1.0f);// 右侧glColor3f(1.0f, 0.0f, 1.0f); // 品红glVertex3f( 1.0f, -1.0f, -1.0f);glVertex3f( 1.0f, 1.0f, -1.0f);glVertex3f( 1.0f, 1.0f, 1.0f);glVertex3f( 1.0f, -1.0f, 1.0f);// 左侧glColor3f(0.0f, 1.0f, 1.0f); // 青色glVertex3f(-1.0f, -1.0f, -1.0f);glVertex3f(-1.0f, -1.0f, 1.0f);glVertex3f(-1.0f, 1.0f, 1.0f);glVertex3f(-1.0f, 1.0f, -1.0f);glEnd();}// 计时器事件处理器void timerEvent(QTimerEvent *event) override {// 每次定时器触发时,增加旋转角度m_angle += 1.0f;// 请求重新绘制,这将触发 paintGL()update();}private:float m_angle; // 旋转角度// gluPerspective 的实现,QOpenGLFunctions_2_1 默认不提供// 这里为了示例完整性手动实现一个简单的版本void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar) {GLdouble ymax = zNear * tan(fovy * M_PI / 360.0);GLdouble ymin = -ymax;GLdouble xmax = ymax * aspect;GLdouble xmin = ymin * aspect;glFrustum(xmin, xmax, ymin, ymax, zNear, zFar);}
};
#endif // MYOPENGLWIDGET_H
main.cpp
#include <QApplication>
#include "myopenglwidget.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);MyOpenGLWidget widget;widget.setWindowTitle("QOpenGLFunctions_2_1 示例");widget.setMinimumSize(800, 600);widget.show();return a.exec();
}