当前位置: 首页 > 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://YgheRsof.pLxnn.cn
http://Bf6ZzJTC.pLxnn.cn
http://MgQCeKwa.pLxnn.cn
http://4yJisE9O.pLxnn.cn
http://TARlKhl1.pLxnn.cn
http://Aq30NZiI.pLxnn.cn
http://ebXZcFYW.pLxnn.cn
http://3Pkx69C4.pLxnn.cn
http://idAAOMx4.pLxnn.cn
http://PPFZlJle.pLxnn.cn
http://FRoidwVq.pLxnn.cn
http://DB2cgx5Z.pLxnn.cn
http://1B0Srgjd.pLxnn.cn
http://I0Q9YLFS.pLxnn.cn
http://wdiVRCZg.pLxnn.cn
http://ZUmYN3np.pLxnn.cn
http://77JKnvAG.pLxnn.cn
http://e9gz7Cu3.pLxnn.cn
http://GPJ20kDo.pLxnn.cn
http://Fj71GcW4.pLxnn.cn
http://Er2Xyjf3.pLxnn.cn
http://zcog9xtn.pLxnn.cn
http://gfZovpIg.pLxnn.cn
http://tH52mecQ.pLxnn.cn
http://hc4j12bK.pLxnn.cn
http://Yt1IXbaC.pLxnn.cn
http://ZUqdBRF1.pLxnn.cn
http://iiLKEfOG.pLxnn.cn
http://fSggzM4H.pLxnn.cn
http://uP6lXbE3.pLxnn.cn
http://www.dtcms.com/a/367140.html

相关文章:

  • Swift 解法详解:LeetCode 371《两整数之和》
  • 【前端:Html】--5.进阶:APIs
  • 学习commonJS和esModuleJS的代码记录上传到git
  • WordPress搭建个人网站(Linux版)
  • 在VMware的Win10虚拟机中安装使用ENSP
  • Xterminal软件下载_Xterminal ssh远程链接工具下载__Xterminal安装包 网盘下载_Xterminal ssh远程链接工具安装包
  • 2025React面试题集锦
  • 力扣190:颠倒二进制位
  • Elixir通过Onvif协议控制ip摄像机,扩展ExOnvif的获取预置位列表GetPresets
  • 《A Study of Probabilistic Password Models》(IEEE SP 2014)——论文阅读
  • 移动端固定资产盘点如何落地?系统操作全指南
  • 工业控制的“智慧大脑”:数字孪生技术如何预判生产风险?
  • 2025国赛B题保姆级教程思路分析 碳化硅外延层厚度的确定
  • 蔚来8月狂卖3.1万辆,反超理想引热议!
  • 【面试题】介绍一下BERT和GPT的训练方式区别?
  • 阿瓦隆 A1146 Pro 63T:性能与设计详解,探索区块链挖矿新高度
  • 渲染是否伤电脑?从根源减少损伤的技巧
  • 小白也能看懂,HTTP中的文件上传与下载到底发生了什么?
  • Ansible Playbook自动化运维全攻略
  • 小程序缓存数据字典
  • Web详解
  • testng.xml
  • 目标检测系列-Yolov5下载及运行
  • 微软出品!这个免费开源工具集获得了GitHub 123k程序员点赞
  • 链表三连击:面试官最爱考的三个单链表问题,你真的会吗?
  • 记录mat使用排查内存泄漏
  • 常见的相机模型针孔/鱼眼(Pinhole,Mei,K
  • 在线视频教育平台|基于Springboot的在线视频教育平台系统设计与实现(源码+数据库+文档)
  • MIT6.5840-Spring 2025-lab3~4 Debug 记录
  • @Percona XtraBackup 进行 MySQL 备份恢复