当前位置: 首页 > news >正文

macOS下基于Qt/C++的OpenGL开发环境的搭建

系统配置

  • MacBook Pro 2015 Intel macOS 12
  • Xcode 14

Qt开发环境搭建

Qt Creator的下载与安装

在Qt官网的下载页面上下载,即Download Qt Online Installer for macOS。下载完成就得到一个文件名类似于qt-online-installer-macOS-x64-x.y.z.dmg的安装包。

在这里插入图片描述
下一步

在这里插入图片描述
选中自定义安装下一步

在这里插入图片描述
点击右上角显示下拉框,并选中Archive

在这里插入图片描述
在这里插入图片描述
按上方图示选中对应组件,下一步

在这里插入图片描述
安装。这里需要花费较长的一段时间。

新建Qt Widget项目

打开已经安装完成的Qt Creator IDE

在这里插入图片描述

点击右上角Create Project…

在这里插入图片描述

选中Application(Qt)–>Qt Widgets Application

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

按上方图示,Base class选择QWidget,不选中Generate form

在这里插入图片描述

持续下一步

在这里插入图片描述

点击左下角绿色三角形,即运行按钮

在这里插入图片描述

生成了一个空白窗体。好,现在关闭这个空白窗体。至此,macOS下基于Qt/c++的开发环境搭建完成。

OpenGL开发环境搭建

基本配置

打开并编辑first_project.pro,添加如下代码:

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 5): QT += opengl openglwidgets

保存。
打开并编辑widget.h,变更代码为如下所示:

#ifndef WIDGET_H
#define WIDGET_H#include <QOpenGLWidget>
#include <QWidget>class Widget : public QOpenGLWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();
};
#endif // WIDGET_H

保存。
打开并编辑widget.cpp,变更代码为如下所示:

#include "widget.h"Widget::Widget(QWidget *parent): QOpenGLWidget(parent)
{}Widget::~Widget() {}

保存。运行一下。

在这里插入图片描述

生成了一个空白窗体,效果比上一次的空白窗体更黑,因为现在它是一个OpenGL的运行环境了。好,现在关闭这个空白窗体。

OpenGL版本选择

根据使用 OpenCL 和 OpenGL 图形处理程序的 Mac 电脑这篇Apple官方文章可知,我的MacBook Pro支持OpenGL 4.1。既然如此,那么我就选择OpenGL 4.1作为我的OpenGL学习版本。具体如何操作呢?
回顾一下刚才那个更黑的空白窗体,它已经是一个OpenGL的运行环境了。既然如此,这个OpenGL运行环境运行的是哪一个OpenGL版本呢?是OpenGL 4.1吗?不知道。怎么办呢?
打开并编辑main.cpp,变更代码为如下所示:

#include "widget.h"#include <QApplication>
#include <QOpenGLContext>
#include <QSurfaceFormat>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();QOpenGLContext *cxt = w.context();QSurfaceFormat fmt{ cxt->format() };qDebug("%d.%d", fmt.majorVersion(), fmt.minorVersion());return a.exec();
}

保存。运行一下。还是刚才那个更黑的空白窗体。好,现在关闭这个空白窗体。

在这里插入图片描述

点击一下Qt Creator IDE最下方的Application Output

在这里插入图片描述

现在看来,当前使用的是OpenGL 2.1版本。
现在尝鲜,运行第1条OpenGL 2.1的命令,即const GLubyte *glGetString( GLenum name);
打开并编辑widget.h,变更代码为如下所示:

#ifndef WIDGET_H
#define WIDGET_H#include <QOpenGLFunctions_2_1>
#include <QOpenGLWidget>
#include <QWidget>class Widget : public QOpenGLWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();protected:virtual void initializeGL() override;virtual void paintGL() override;private:QOpenGLFunctions_2_1 *glf;
};
#endif // WIDGET_H

保存。
打开并编辑widget.cpp,变更代码为如下所示:

#include "widget.h"#include <QOpenGLContext>
#include <QOpenGLVersionFunctionsFactory>Widget::Widget(QWidget *parent): QOpenGLWidget(parent)
{}Widget::~Widget() {}void Widget::initializeGL()
{QOpenGLContext *cxt = context();glf = QOpenGLVersionFunctionsFactory::get<QOpenGLFunctions_2_1>(cxt);
}void Widget::paintGL()
{const GLubyte *version = glf->glGetString(GL_VERSION);QString versionStr;for (size_t i = 0; version[i] != 0; ++i){versionStr.append(QChar(version[i]));}qDebug() << versionStr;
}

保存。运行一下。

在这里插入图片描述

好,现在关闭这个空白窗体。
如何将当前的OpenGL运行环境从OpenGL 2.1切换到OpenGL 4.1?
打开并编辑main.cpp,变更代码为如下所示:

#include "widget.h"#include <QApplication>
#include <QOpenGLContext>
#include <QSurfaceFormat>int main(int argc, char *argv[])
{QSurfaceFormat default_fmt{ QSurfaceFormat::defaultFormat() };default_fmt.setVersion(4, 1);QSurfaceFormat::setDefaultFormat(default_fmt);QApplication a(argc, argv);Widget w;w.show();QOpenGLContext *cxt = w.context();QSurfaceFormat fmt{ cxt->format() };qDebug("%d.%d", fmt.majorVersion(), fmt.minorVersion());return a.exec();
}

保存。运行一下。好,现在关闭这个空白窗体。发现效果和上一张图片完全一样。为什么没有做到将当前的OpenGL运行环境从OpenGL 2.1切换到OpenGL 4.1?哦!原来widget.cpp文件中的那个工厂得到的就是OpenGL 2.1的函数对象,代码如下所示:

 glf = QOpenGLVersionFunctionsFactory::get<QOpenGLFunctions_2_1>(cxt);

打开并编辑widget.h,变更代码为如下所示:

#ifndef WIDGET_H
#define WIDGET_H#include <QOpenGLFunctions_4_1_Core>
#include <QOpenGLWidget>
#include <QWidget>class Widget : public QOpenGLWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();protected:virtual void initializeGL() override;virtual void paintGL() override;private:QOpenGLFunctions_4_1_Core *glf;
};
#endif // WIDGET_H

保存。
打开并编辑widget.cpp,变更代码为如下所示:

#include "widget.h"#include <QOpenGLContext>
#include <QOpenGLVersionFunctionsFactory>Widget::Widget(QWidget *parent): QOpenGLWidget(parent)
{}Widget::~Widget() {}void Widget::initializeGL()
{QOpenGLContext *cxt = context();glf = QOpenGLVersionFunctionsFactory::get<QOpenGLFunctions_4_1_Core>(cxt);
}void Widget::paintGL()
{const GLubyte *version = glf->glGetString(GL_VERSION);QString versionStr;for (size_t i = 0; version[i] != 0; ++i){versionStr.append(QChar(version[i]));}qDebug() << versionStr;
}

保存。运行一下。

在这里插入图片描述

程序崩溃了!怎么办?调试一下。

在这里插入图片描述

图中右下角指出:函数对象glf是空指针。说明在当前这个OpenGL环境上下文下没有正常地拿到函数对象。怎么办?
OpenGL 2.1切换到OpenGL 4.1相关的所有代码如下所示:
widget.h

QOpenGLFunctions_4_1_Core *glf;

widget.cpp

glf = QOpenGLVersionFunctionsFactory::get<QOpenGLFunctions_4_1_Core>(cxt);

main.cpp

QSurfaceFormat default_fmt{ QSurfaceFormat::defaultFormat() };
default_fmt.setVersion(4, 1);
QSurfaceFormat::setDefaultFormat(default_fmt);

我们先来查看一下已经下载到本地的Qt QSurfaceFormat的源代码。
qsurfaceformat.cpp

explicit QSurfaceFormatPrivate(QSurfaceFormat::FormatOptions _opts = { })// 已省略, profile(QSurfaceFormat::NoProfile), major(2), minor(0)// 已省略 {}

qsurfaceformat.h

// 已省略 
enum OpenGLContextProfile {NoProfile,CoreProfile,CompatibilityProfile};
// 已省略 

是不是端倪已出?打开并编辑main.cpp,变更代码为如下所示:

// 已省略
QSurfaceFormat default_fmt{ QSurfaceFormat::defaultFormat() };
default_fmt.setVersion(4, 1);
default_fmt.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile);
QSurfaceFormat::setDefaultFormat(default_fmt);
// 已省略

保存。运行一下。

在这里插入图片描述

好,现在关闭这个空白窗体。至此,macOS下基于Qt/c++的OpenGL 4.1开发环境搭建完成。

细枝末节

细心的话会发现一个现象:
qsurfaceformat.cpp源代码如下所示:

explicit QSurfaceFormatPrivate(QSurfaceFormat::FormatOptions _opts = { })// 已省略, profile(QSurfaceFormat::NoProfile), major(2), minor(0)// 已省略 {}

其中,major是 2,minor0 。但是前文所述,默认情况下,得到的是major是 2,minor1 。为什么?而且这是我的机器运行的结果,别人的机器呢?
Qt是一个支持跨平台的大型c++类库。那么,它是如何跨进macOS的呢?以OpenGL为例:在Mac平台上,通过objective-c编写基于OpenGL的应用,相关的API会涉及到NSOpenGLContext这个类,即OpenGL运行环境上下文,而Qt就可以通过插件的形式调用到此API 。
我们再来查看一下已经下载到本地的qcocoaglcontext.mm的源代码。

// 已省略
m_context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:m_shareContext];
// 已省略
NSOpenGLPixelFormat *QCocoaGLContext::pixelFormatForSurfaceFormat(const QSurfaceFormat &format)
{QVector<NSOpenGLPixelFormatAttribute> attrs;attrs << NSOpenGLPFAOpenGLProfile;if (format.profile() == QSurfaceFormat::CoreProfile) {if (format.version() >= qMakePair(4, 1))attrs << NSOpenGLProfileVersion4_1Core;else if (format.version() >= qMakePair(3, 2))attrs << NSOpenGLProfileVersion3_2Core;elseattrs << NSOpenGLProfileVersionLegacy;} else {attrs << NSOpenGLProfileVersionLegacy;}// 已省略

根据上方代码可知,对于Qt来说,原来所有Mac系的OpenGL都支持OpenGL 4.1 CoreOpenGL 3.2 CoreOpenGL Legacy,根据前文描述的运行结果可知,此处的OpenGL Legacy应该就是指OpenGL 2.1了。不过还是不要忘记前文所示的使用 OpenCL 和 OpenGL 图形处理程序的 Mac 电脑这篇Apple官方文章。
另外一个问题是为什么在main.cpp中,以下部分代码:

QSurfaceFormat default_fmt{ QSurfaceFormat::defaultFormat() };
default_fmt.setVersion(4, 1);
default_fmt.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile);
QSurfaceFormat::setDefaultFormat(default_fmt);

出现在QApplication a(argc, argv);之前?因为在它之后会出现问题。
我们再来查看一下已经下载到本地的Qt QSurfaceFormat的源代码。

// 已省略
void QSurfaceFormat::setDefaultFormat(const QSurfaceFormat &format)
{
#ifndef QT_NO_OPENGLif (qApp) {QOpenGLContext *globalContext = QOpenGLContext::globalShareContext();if (globalContext && globalContext->isValid()) {qWarning("Warning: Setting a new default format with a different version or profile ""after the global shared context is created may cause issues with context ""sharing.");}}
#endif*qt_default_surface_format() = format;
}
// 已省略

这样看似乎还是不够明显。我们再来查看一下已经下载到本地的Qt qguiapplication.h的源代码,如下所示:

// 已省略
#if defined(qApp)
#undef qApp
#endif
#define qApp (static_cast<QGuiApplication *>(QCoreApplication::instance()))
// 已省略

这样就解释了在QApplication a(argc, argv);创建应用对象之前调用QSurfaceFormat::setDefaultFormat(default_fmt);的原因了。

http://www.xdnf.cn/news/1451125.html

相关文章:

  • 2025最新版鸿蒙HarmonyOS开发工具安装使用指南
  • 记录一次 Rclone挂载网盘,Emby播放视频出现连续跳集的原因分析以及解决
  • Spring Boot 拦截器(Interceptor)与过滤器(Filter)有什么区别?
  • 【数据可视化-107】2025年1-7月全国出口总额Top 10省市数据分析:用Python和Pyecharts打造炫酷可视化大屏
  • LeetCode每日一题,2025-9-4
  • 动手学深度学习——线性回归 + 基础优化算法
  • 服务器异常负载排查手册 · 隐蔽进程篇
  • Android AI客户端开发(语音与大模型部署)面试题大全
  • Tomcat 服务器全方位指南:安装、配置、部署与实战优化
  • Sentinel 与 Feign 整合详解:实现服务调用的流量防护
  • Clang 编译器:下载安装指南与实用快捷键全解析
  • C++类和对象(上):从设计图到摩天大楼的构建艺术
  • 蔚来汽车前制动器设计及热性能分析cad+三维图+设计说明书
  • MySQL SM4 UDF 安装与使用
  • 【计算机网络(自顶向下方法 第7版)】第一章 计算机网络概述
  • 《D (R,O) Grasp:跨机械手灵巧抓取的机器人 - 物体交互统一表示》论文解读
  • 实战演练(二):结合路由与状态管理,构建一个小型博客前台
  • Java基础知识点汇总(五)
  • 修订版!Uniapp从Vue3编译到安卓环境踩坑记录
  • 新手向:AI IDE+AI 辅助编程
  • 开源视频剪辑工具推荐
  • 经典资金安全案例分享:支付系统开发的血泪教训
  • Hadoop(七)
  • 数说故事 | 2025年运动相机数据报告,深挖主流品牌运营策略及行业趋势​
  • HarmonyOS路由导航方案演进:HMRouter基于Navigation封装,使用更方便
  • 【软考架构】嵌入式系统及软件
  • Shadcn UI – 开发者首选的高性能、高定制化 React 组件库
  • Flutter之riverpod状态管理详解
  • 第1章 Jenkins概述与架构
  • ⸢ 肆 ⸥ ⤳ 默认安全:安全建设方案 ➭ b.安全资产建设