嵌入式Linux(SOC带GPU树莓派)无窗口系统下搭建 OpenGL ES + Qt 开发环境,并绘制旋转金字塔

树莓派无窗口系统下搭建 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 渲染。

  1. 确认系统支持 EGLFS

    复制代码
    ls /usr/lib/arm-linux-gnueabihf/qt5/plugins/platforms/libqeglfs.so

    如果存在 libqeglfs.so,表示系统支持 EGLFS。

  2. 设置环境变量启用 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
  1. 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();
    }
  2. 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
  3. 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();  // 触发重绘
    }
  4. 创建项目文件并编译运行

    复制代码
    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/*

完成后,你的金字塔应用程序将在树莓派的无窗口系统中运行并水平旋转!

相关推荐
有一个好名字41 分钟前
MyBatis-Plus 三种数据库操作方式详解 + 常用方法大全
数据库·mybatis
-Xie-1 小时前
Redis(八)——多线程与单线程
java·数据库·redis
wanhengidc1 小时前
云手机的软件核心是什么
运维·服务器·web安全·游戏·智能手机
国服第二切图仔1 小时前
Qt-for-鸿蒙PC-多线程绘制开源鸿蒙开发实践
qt·开源·鸿蒙pc
G探险者1 小时前
为什么 VARCHAR(1000) 存不了 1000 个汉字? —— 详解主流数据库“字段长度”的底层差异
数据库·后端·mysql
芬加达2 小时前
jvm八股
运维·服务器·jvm
小兔薯了2 小时前
11. Linux firewall 防火墙管理
linux·运维·服务器
Linux技术芯2 小时前
浅谈SCSI寻址机制与工作阶段深度解析?
linux
Albert Tan2 小时前
Oracle EBS R12.2.14 清理FND_LOBS并释放磁盘空间
数据库·oracle
国服第二切图仔2 小时前
Qt-for-鸿蒙PC-CheckBox开源鸿蒙开发实践
qt·开源·鸿蒙pc