树莓派无窗口系统下搭建 OpenGL ES + Qt 开发环境,并绘制旋转金字塔
1. 安装 OpenGL ES 开发环境
运行以下命令安装所需的 OpenGL ES 开发工具和库:
sudo apt install cmake mesa-utils libegl1-mesa-dev libgles2-mesa-dev libdrm-dev libgbm-dev
2. 安装 Qt 开发环境
安装 Qt 的核心开发库:
sudo apt install -y qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools qtdeclarative5-dev qml-module-qtquick2
3. 配置 Qt 使用 EGL 和 GBM(无窗口模式)
使用 EGLFS(EGL Fullscreen)插件
EGLFS 插件可以在没有窗口管理器的环境下直接使用 OpenGL 渲染。
-
确认系统支持 EGLFS:
ls /usr/lib/arm-linux-gnueabihf/qt5/plugins/platforms/libqeglfs.so
如果存在
libqeglfs.so
,表示系统支持 EGLFS。 -
设置环境变量启用 EGLFS:
export QT_QPA_PLATFORM=eglfs
使用 GBM 后台支持:
export QT_QPA_EGLFS_INTEGRATION=eglfs_kms
或者切换到 Framebuffer(可选):
export QT_QPA_PLATFORM=linuxfb
4. 编写并运行 Qt 项目代码
创建项目目录和文件
mkdir qt-opengl-example
cd qt-opengl-example
-
main.cpp
:#include <QApplication> #include <QMainWindow> #include "openglwidget.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); QMainWindow window; OpenGLWidget *widget = new OpenGLWidget(); window.setCentralWidget(widget); window.setWindowTitle("OpenGL ES Rotating Pyramid"); window.resize(800, 600); window.show(); return app.exec(); }
-
openglwidget.h
:#ifndef OPENGLWIDGET_H #define OPENGLWIDGET_H #include <QOpenGLWidget> #include <QOpenGLFunctions> #include <QTimer> class OpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions { Q_OBJECT public: explicit OpenGLWidget(QWidget *parent = nullptr); ~OpenGLWidget(); protected: void initializeGL() override; void resizeGL(int w, int h) override; void paintGL() override; void timerEvent(QTimerEvent *event) override; private: float rotationAngle; }; #endif // OPENGLWIDGET_H
-
openglwidget.cpp
:#include "openglwidget.h" #include <QOpenGLShaderProgram> #include <QOpenGLBuffer> #include <QOpenGLVertexArrayObject> #include <QMatrix4x4> #include <QtMath> OpenGLWidget::OpenGLWidget(QWidget *parent) : QOpenGLWidget(parent), rotationAngle(0.0f) { setAutoFillBackground(false); // 不自动填充背景,交给OpenGL渲染 startTimer(10);// 启动定时器,每隔0.01秒触发 } OpenGLWidget::~OpenGLWidget() { } void OpenGLWidget::initializeGL() { initializeOpenGLFunctions(); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // 设置清屏颜色 glEnable(GL_DEPTH_TEST); // 启用深度测试 } void OpenGLWidget::resizeGL(int w, int h) { glViewport(0, 0, w, h); } void OpenGLWidget::paintGL() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除颜色和深度缓冲 // 定义金字塔的顶点数据 GLfloat vertices[] = { // 底面 -0.5f, -0.5f, -0.5f, // 顶点1 0.5f, -0.5f, -0.5f, // 顶点2 0.5f, -0.5f, 0.5f, // 顶点3 -0.5f, -0.5f, 0.5f, // 顶点4 // 顶面 0.0f, 0.5f, 0.0f // 顶点5 }; // 定义金字塔的索引 GLuint indices[] = { 0, 1, 4, // 底面与顶面连接的三角形 1, 2, 4, // 底面与顶面连接的三角形 2, 3, 4, // 底面与顶面连接的三角形 3, 0, 4, // 底面与顶面连接的三角形 0, 1, 2, // 底面三角形 2, 3, 0 // 底面三角形 }; // 创建并绑定着色器程序 QOpenGLShaderProgram program; program.addShaderFromSourceCode(QOpenGLShader::Vertex, "#version 300 es\n" "in vec3 position;\n" "uniform mat4 modelViewProjectionMatrix;\n" "void main() {\n" " gl_Position = modelViewProjectionMatrix * vec4(position, 1.0);\n" "}" ); program.addShaderFromSourceCode(QOpenGLShader::Fragment, "#version 300 es\n" "precision mediump float;\n" "out vec4 fragColor;\n" "void main() {\n" " fragColor = vec4(1.0, 0.5, 0.0, 1.0); // 金字塔颜色:橙色\n" "}" ); program.link(); program.bind(); // 创建顶点数组对象和顶点缓冲对象 GLuint vao, vbo, ebo; glGenVertexArrays(1, &vao); glBindVertexArray(vao); glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glGenBuffers(1, &ebo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); GLint posAttrib = program.attributeLocation("position"); program.enableAttributeArray(posAttrib); glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 0, nullptr); // 创建一个模型视图投影矩阵 QMatrix4x4 projection; projection.perspective(45.0f, (float)width() / height(), 0.1f, 100.0f); projection.translate(0.0f, 0.0f, -3.0f); // 将物体向远离观察者的方向移动 QMatrix4x4 modelView; modelView.rotate(rotationAngle, 0.0f, 1.0f, 0.0f); // 水平旋转金字塔 QMatrix4x4 modelViewProjectionMatrix = projection * modelView; // 将 MVP 矩阵传递给着色器 program.setUniformValue("modelViewProjectionMatrix", modelViewProjectionMatrix); // 绘制金字塔 glDrawElements(GL_TRIANGLES, 18, GL_UNSIGNED_INT, nullptr); glBindVertexArray(0); } void OpenGLWidget::timerEvent(QTimerEvent *event) { rotationAngle += 1.0f; // 增加旋转角度 if (rotationAngle >= 360.0f) rotationAngle = 0.0f; update(); // 触发重绘 }
-
创建项目文件并编译运行:
qmake -project echo "QT += core gui widgets opengl" >> qt-opengl-example.pro qmake make ./qt-opengl-example
5. 调试与优化
启用调试日志
export QT_LOGGING_RULES="qt.qpa.*=true"
权限问题
确保当前用户有权限访问 /dev/fb0
和 /dev/dri/*
:
sudo chmod a+rw /dev/fb0
sudo chmod a+rw /dev/dri/*
完成后,你的金字塔应用程序将在树莓派的无窗口系统中运行并水平旋转!