文档管理中心
|

HarmonyOS 6

HarmonyOS 5

在HarmonyOS PC的Qt项目中集成OpenGL

场景介绍

在HarmonyOS PC的Qt项目中集成OpenGL实现图形渲染是Qt应用的高频使用场景之一,如CAD软件中,使用OpenGL进行3D模型的渲染和交互。 本示例基于商业版Qt,使用QOpenGLWidget及相关OpenGL模块,基于OpenGL核心配置与二十面体几何定义,完成了一个带有动态生成木纹纹理、黑色边线框且具备自动旋转动画的3D正二十面体的实时渲染场景。

效果预览

&&KNOWLEDGEIMGURLPREFIX&&/20260124/0399cdaa-c6b9-4e7b-81af-9ae625232d9c.gif

实现思路

一、OpenGL集成。

  1. 替换适配HarmonyOS的图形公共接口:
    • 下载适配HarmonyOS后的libGLv4.so
    • libGLv4.so复制到HarmonyOS SDK的libs目录下(如:sdk/default/openharmony/native/sysroot/usr/lib/aarch64-linux-ohos)替换默认的libGLv4.so
  2. 修改商业版Qt,将OpenGL ES切换为OpenGL:
    • 检查以下内容是否存在于Qt源码中,如果不存在需要将以下patch应用到商业版qtbase源码中:
    收起
    自动换行
    深色代码主题
    复制
    diff --git a/mkspecs/ohos-clang/qmake.conf b/mkspecs/ohos-clang/qmake.conf
    index 8b21b11e3c5..37c9accea2b 100644
    --- a/mkspecs/ohos-clang/qmake.conf
    +++ b/mkspecs/ohos-clang/qmake.conf
    @@ -107,7 +107,9 @@ QMAKE_LINK_SHLIB = $$QMAKE_CXX
    
    QMAKE_LFLAGS += $$OHOS_LINK_FLAGS
    
    -QMAKE_LIBS_OPENGL_ES3 = -lGLESv3
    +# Link against the OHOS OpenGL ES 3 and desktop OpenGL implementations.
    +QMAKE_LIBS_OPENGL_ES3 = -lGLESv3 -lEGL
    +QMAKE_LIBS_OPENGL = -lGLv4
    
    armeabi-v7a.sdk = armeabi-v7a
    armeabi-v7a.target = armeabi-v7a
    diff --git a/src/gui/configure.json b/src/gui/configure.json
    index 8d27273b803..04dcdbb9423 100644
    --- a/src/gui/configure.json
    +++ b/src/gui/configure.json
    @@ -34,7 +34,7 @@
                "mtdev": "boolean",
                "opengl": { "type": "optionalString", "values": [ "no", "yes", "desktop", "es2", "dynamic" ] },
                "opengl-es-2": { "type": "void", "name": "opengl", "value": "es2" },
    -            "opengles3": "boolean",
    +            "opengles3": { "type": "void", "name": "opengl", "value": "es2" },
                "openvg": "boolean",
                "qpa": { "type": "string", "name": "qpa_default_platform" },
                "qpa-platform-guard": "boolean",
    @@ -424,6 +424,7 @@
            },
            "opengl": {
                "label": "Desktop OpenGL",
    +            "condition": "input.opengl == 'desktop'",
                "test": {
                    "head": [
                        "#ifdef __APPLE__",
    @@ -442,13 +443,13 @@
                },
                "headers": [
                    {
    -                    "condition": "!config.darwin",
    +                    "condition": "!config.darwin && input.opengl == 'desktop'",
                        "headers": "GL/gl.h"
                    }
                ],
                "sources": [
    -                { "type": "pkgConfig", "args": "gl", "condition": "!config.darwin" },
    -                { "type": "makeSpec", "spec": "OPENGL" }
    +                { "type": "pkgConfig", "args": "gl", "condition": "!config.darwin && input.opengl == 'desktop'" },
    +                { "type": "makeSpec", "spec": "OPENGL", "condition": "input.opengl == 'desktop'" }
                ]
            },
            "opengl_es2": {
    diff --git a/src/plugins/platforms/ohos/qohosplatformintegration.cpp b/src/plugins/platforms/ohos/qohosplatformintegration.cpp
    index 66ec904e9c7..97784ad2c85 100644
    --- a/src/plugins/platforms/ohos/qohosplatformintegration.cpp
    +++ b/src/plugins/platforms/ohos/qohosplatformintegration.cpp
    @@ -166,8 +166,13 @@ QOhosPlatformIntegration::QOhosPlatformIntegration(const QStringList &paramList)
            if (Q_UNLIKELY(!eglInitialize(m_eglDisplay, &major, &minor)))
                qFatal("Could not initialize egl display");
    
    +#if defined(QT_OPENGL_ES_2)
            if (Q_UNLIKELY(!eglBindAPI(EGL_OPENGL_ES_API)))
                qFatal("Could not bind GL_ES API");
    +#else
    +        if (Q_UNLIKELY(!eglBindAPI(EGL_OPENGL_API)))
    +            qFatal("Could not bind desktop GL API");
    +#endif
        }
    
        m_screenManager = std::make_unique<QOhosScreenManager>();
    diff --git a/src/plugins/platforms/ohos/render/qohosegl.h b/src/plugins/platforms/ohos/render/qohosegl.h
    index 485018e0304..abad0d37f56 100644
    --- a/src/plugins/platforms/ohos/render/qohosegl.h
    +++ b/src/plugins/platforms/ohos/render/qohosegl.h
    @@ -53,7 +53,6 @@
    
    #include "EGL/egl.h"
    #include "EGL/eglplatform.h"
    -#include <GLES3/gl3.h>
    #include <QSharedPointer>
    #include <QtCore/qglobal.h>
    
    • git命令参考如下,其中diff.patch为上一步的内容,本例中放在Qt源码目录tqtc-qt5的同级目录下:
    收起
    自动换行
    深色代码主题
    复制
    cd qtbase
    git apply ../../diff.patch
    
  3. 修改app.json5配置文件:
    • 增加appEnvironments:
    收起
    自动换行
    深色代码主题
    复制
    "appEnvironments": [
        {
            "name":"NEED_OPENGL",
            "value": "1"
        }
    ]
    

二、实现3D正二十面体渲染。

  1. OpenGL环境初始化与窗口设置:
    • 在OpenGLWidget构造函数中配置OpenGL环境,设置为OpenGL 3.3核心模式,并启用24位深度缓冲区:
    收起
    自动换行
    深色代码主题
    复制
    // 设置OpenGL版本和格式
    QSurfaceFormat format;
    format.setVersion(3, 3);
    format.setProfile(QSurfaceFormat::CoreProfile);
    format.setDepthBufferSize(24);
    setFormat(format);
    
    • 创建定时器用于驱动旋转动画,设置更新频率为60FPS:
    收起
    自动换行
    深色代码主题
    复制
    m_timer = new QTimer(this);
    connect(m_timer, &QTimer::timeout, this, &OpenGLWidget::updateRotation);
    m_timer->start(16); // 60FPS
    
  2. 二十面体几何数据生成:
    • 核心几何生成算法位于CreateIcosahedronVertices()函数中。正二十面体由12个顶点和20个等边三角形面组成,基于黄金分割率(φ≈1.618)计算顶点坐标:
    收起
    自动换行
    深色代码主题
    复制
    const float phi = (1.0f + sqrt(5.0f)) / 2.0f; // 黄金比例
    // 正二十面体的12个顶点(归一化到单位球面)
    m_vertices[0] = QVector3D(-1.0f,  phi, 0.0f).normalized();
    m_vertices[1] = QVector3D( 1.0f,  phi, 0.0f).normalized();
    
    • 顶点定义后,按特定顺序连接成20个三角形面,分为顶部、中间带和底部三个区域:
    收起
    自动换行
    深色代码主题
    复制
    // 顶部的5个面
    m_faces[0] = {0, 11, 5};
    m_faces[1] = {0, 5, 1};
    
  3. 纹理坐标映射: 使用球面映射算法将3D顶点坐标转换为2D纹理坐标,实现木纹的曲面包裹效果:
    收起
    自动换行
    深色代码主题
    复制
    QVector2D OpenGLWidget::SphericalMapping(const QVector3D& position)
    {
        float u = 0.5f + atan2(position.z(), position.x()) / (2.0f * M_PI);
        float v = 0.5f - asin(position.y()) / M_PI;
        return QVector2D(u, v);
    }
    
  4. 木纹纹理动态生成: 通过算法程序化生成木纹纹理:
    收起
    自动换行
    深色代码主题
    复制
    // 基础木材颜色
    int baseR = 200, baseG = 160, baseB = 120;    
    // 木纹条纹效果
    float woodGrain = sin(x * 0.02f + sin(y * 0.01f) * 5.0f) * 0.3f + 0.7f;    
    // 年轮效果
    float distance = sqrt((x-128)*(x-128) + (y-128)*(y-128));
    float rings = sin(distance * 0.05f) * 0.15f + 0.85f;
    // 组合计算最终颜色
    float pattern = woodGrain * rings + noise;
    
  5. 顶点缓冲区对象(VBO)与顶点数组对象(VAO)管理: 创建两套渲染管线分别处理纹理和边线:
    • 纹理渲染管线:使用VertexData结构(位置+纹理坐标)
    • 边线渲染管线:使用LineVertexData结构(位置+颜色)
    收起
    自动换行
    深色代码主题
    复制
    // 纹理VAO配置
    m_program->enableAttributeArray(0); // 位置属性
    m_program->setAttributeBuffer(0, GL_FLOAT, offsetof(VertexData, position), 3, sizeof(VertexData));
    m_program->enableAttributeArray(1); // 纹理坐标属性
    m_program->setAttributeBuffer(1, GL_FLOAT, offsetof(VertexData, texCoord), 2, sizeof(VertexData));
    
  6. 边线数据去重处理: 为避免重复绘制共享边,使用QSet<QPair<int, int>>记录已处理的边:
    收起
    自动换行
    深色代码主题
    复制
    QSet<QPair<int, int>> edgeSet;
    // 对每个面的三条边,检查是否已添加
    QPair<int, int> edge1(qMin(v0, v1), qMax(v0, v1));
    if (!edgeSet.contains(edge1)) {
        edgeSet.insert(edge1);
        // 添加这条边的两个顶点
    }
    
  7. 着色器设计: 实现两个独立的着色器程序:
    • 纹理着色器支持纹理采样和动态木纹效果。
    • 边线着色器:固定颜色渲染,无纹理。 纹理着色器片段着色器中添加了动态效果:
    收起
    自动换行
    深色代码主题
    复制
    float woodPattern = sin(fragTexCoord.x * 20.0 + fragTexCoord.y * 10.0 + time * 0.5) * 0.1 + 0.9;
    texColor.rgb *= woodPattern;
    
  8. 渲染循环与变换矩阵: 在paintGL()中设置变换矩阵并执行绘制:
    收起
    自动换行
    深色代码主题
    复制
    // 设置模型视图矩阵
    m_modelView.setToIdentity();
    m_modelView.translate(0.0f, 0.0f, -4.0f); // 视点距离
    m_modelView.rotate(m_rotationAngle, 0.0f, 1.0f, 0.0f); // 绕Y轴旋转
    m_modelView.rotate(30.0f, 1.0f, 0.0f, 0.0f); // 倾斜角度
    
    // 创建透视投影矩阵
    m_projection.perspective(45.0f, aspect, 0.1f, 100.0f);
    
  9. 绘制顺序与混合: 采用先填充后描边的绘制顺序:
    • 启用深度测试,绘制纹理化的二十面体(60个顶点,GL_TRIANGLES)。
    • 绘制边线框(GL_LINES),设置线宽为2.0。
    • 通过定时器更新旋转角度,实现自动旋转动画。

说明

使用该示例需要完成以下操作:

  1. libs\arm64-v8a下的libqohos.so文件替换为本地Qt安装路径\plugins\platforms目录下的libqohos.so

  2. 将商业版Qt安装路径配置到QT_PREFIX中,可以选择下面两个方案中的一个:

    • 修改entry\src\main\cpp\qtModule\CMakeLists.txt中的set(QT_PREFIX "D:\\qtBusiness\\installDir")为编译出的Qt产物目录:
    收起
    自动换行
    深色代码主题
    复制
    # 检查环境变量是否存在
    if(DEFINED ENV{WORKSPACE})
       set(QT_PREFIX $ENV{WORKSPACE}/code/SDK/Qt/QtOpenSDK)
       message(STATUS "get QT_PREFIX PATH: ${QT_PREFIX}")
    else()
       set(QT_PREFIX "D:\\qtBusiness\\installDir")
       message(STATUS "WORKSPACE not defined, using default path: ${QT_PREFIX}")
    endif()
    
    • 或者删除entry\src\main\cpp\qtModule\CMakeLists.txt中的QT_PREFIX定义,并在entry\build-profile.json5中设置QT_PREFIX
    收起
    自动换行
    深色代码主题
    复制
    "buildOption": {
       "externalNativeOptions": {
          "path": "./src/main/cpp/CMakeLists.txt",
          "arguments": "-DQT_PREFIX=D:\\qtBusiness\\installDir",
          "cppFlags": "",
          "abiFilters": ["arm64-v8a"]
       }
    },
    
  3. libQt5OpenGL.solibqohos.solibqohosstyle.so拷贝到entry\libs\arm64-v8a目录下:

&&KNOWLEDGEIMGURLPREFIX&&/20260202/72428144-591c-4b0c-8ffe-b0b1abdfafc6.png

约束与限制

  • 本示例支持API Version 20 Release及以上版本。
  • 本示例支持HarmonyOS 6.0.0 Release SDK及以上版本。
  • 本示例需要使用DevEco Studio 6.0.0 Release及以上版本进行编译运行。

工程目录

收起
自动换行
深色代码主题
复制
├─entry
│  ├─libs/arm64-v8a
│  │  └─libqohos.so                             // 商业版Qt产物so
│  └─src
│      ├─main
│      │  ├─cpp
│      │  │  ├─OpenGLIcosahedron                // OpenGL实现二十面体几何渲染
│      │  │  │ ├─main.cpp                       // Qt的主入口
│      │  │  │ ├─openglwidget.cpp               // OpenGL二十面体几何渲染类实现
│      │  │  │ ├─openglwidget.h                 // OpenGL二十面体几何渲染类头文件
│      │  │  │ └─CMakeLists.txt                 // OpenGL渲染实现CMakeList文件
│      │  │  ├─napi_Init.cpp
│      │  │  └─CMakeLists.txt                   // Qt项目CMakeList文件
│      │  ├─ets                                 // 与商业版Qt模板工程保持一致
│      │  │  ├─common
│      │  │  │  └─QtAppConstants.ets
│      │  │  ├─pages
│      │  │  │  ├─FloatWindowNativeNode.ets
│      │  │  │  ├─MainWindowNativeNode.ets
│      │  │  │  ├─SubWindowNativeNode.ets
│      │  │  │  └─UiExtensionNativeNode.ets
│      │  │  ├─process
│      │  │  │  └─QChildProcess.ets
│      │  │  ├─qability
│      │  │  │  ├─LocalStorageTsModule.ets
│      │  │  │  ├─OhosExportModules.ets
│      │  │  │  ├─QAbility.ets
│      │  │  │  ├─QEmbeddedComponentCreator.ets
│      │  │  │  ├─QEmbeddedComponentCreatorTsModule.ets
│      │  │  │  ├─QEmbeddedUiExtensionAbility.ets
│      │  │  │  └─QtUtils.ets
│      │  │  └─qabilitystage 
│      │  │     └─QAbilityStage.ets
│      │  ├─qt                                             // 与商业版Qt模板工程保持一致
│      │  │  ├─libqohos.d.ts
│      │  │  └─oh-package.json5
│      │  ├─resources                                      // 应用资源目录
│      │  └─module.json5                                   // 模块级核心配置文件
│      ├─build-profile.json5                               // 工程结构/构建/定制化配置信息
│      └─oh-package.json5                                  // 描述全局配置
└─hvigor                                                   // 构建环境配置

参考文档

libGLv4.so 从0到1构建HarmonyOS PC Qt项目

点赞
2
收藏
1
回复
1
分享
举报
浏览281 发布于2026-02-06 09:40未知归属地
全部评论
最多点赞
最新发布
最早发布
1楼回复于2026-02-06 09:40 未知归属地
写回答
新增插入模板功能
一键使用模板,快速填写内容,轻松发帖~
知道了
  • 为了保障您的信息安全,请勿上传您的敏感个人信息(如您的密码等信息)和您的敏感资产信息(如关键源代码、签名私钥、调试安装包、业务日志等信息),且您需自行承担由此产生的信息泄露等安全风险。
  • 如您发布的内容为转载内容,请注明内容来源。

我要提问题

了解社区公约,与您携手共创和谐专业的开发者社区。