Qt5 OpenGL教程系列0:创建一个窗口

1 篇文章 1 订阅
本文是Qt5 OpenGL教程的第一部分,主要介绍如何使用QOpenGLWindow类创建一个窗口。内容包括理解QOpenGLWindow和QOpenGLFunctions的作用,创建窗口的步骤,以及在main.cpp中初始化和显示窗口。通过学习,你可以了解到如何在不依赖QtWidgets的情况下创建一个简单的OpenGL程序。
摘要由CSDN通过智能技术生成

关于Qt5 OpenGL教程系列

本系列教程假定你

  1. 有Qt框架的基础知识。至少了解信号与槽,知道如何创建简单的程序。如果你对文章的内容有任何不明白、需要我阐明的地方,请评论留言。
  2. 对OpenGL有基础的了解。

需要明确的是本系列教程不是OpenGL教程或者Qt教程,而是这两种技术结合使用的教程

QOpenGLWindow

我们将使用Qt5 新增的QOpenGLWindow类。

QOpenGLWindow是只从QtGui 继承而来的新类。这一点非常重要,因为这使得我们不依赖QtWidgets模块就能提供OpenGL的抽象层。这不像之前QGL的情况,因为QGL和 Qt Widgets过于耦合。

对于QOpenGLWindow我们只需要关注一下几个函数:

  • initializeGL()
  • resizeGL(int widthint height)
  • paintGL()
    由函数名称你便可猜出,这几个函数是我们可以操作我们的OpenGL逻辑。其实这就是所有我们所需要去创建简单的OpenGL程序的步骤 —— 这中间很多复杂的配置OpenGL的操作都已经被Qt框架所完成了。

QOpenGLFunctions

为了方便我们可以继承QOpenGLWindow的同时选择性的继承QOpenGLFunctions。在新版的Qt中,GLEW已经不需要了,QOpenGLFunctions就能使得我们可以使用 OpenGL的函数了

你不需要继承QOpenGLFunctions来访问相关函数,但如果你非要,你可以通过QOpenGLContext来获取可用的函数.可以通过如下局部变量的方式来获取:

QOpenGLFunctions functions(QOpenGLContext::currentContext());
functions.glFunctionHere();
// or...
QOpenGLFunctions *functions = QOpenGLContext::currentContext()->functions();
functions->glFunctionHere();

这里所默认访问的是OpenGL ES 2.0 的API,这是处于兼容性考虑的,如此我们可以轻松的将产品移植到嵌入式平台(比如Android).我们接下来的用力都会使用这样的函数上下文(context).我们仍然可以要求使用指定的函数上下文(context)(比如QOpenGLFunctions_4_3_Core)

这样我们可以只访问我们所需要支持的上下文.我们目前没有访问OpenGL ES 2.0 API之外的需求,所以接下去都按照默认的来进行.

创建一个Window

有了以上的基础,我们来创建我们的OpenGL窗口.得益于Qt,跨平台的OpenGL最难的部分Qt已经帮我们处理了,

1. 新建一个项目

我们创建一个新的Qt项目,没什么特殊的,可以选择控制台程序然后添加我们所需要的东西.
新建项目对话框
我们所需要做的是在我们的项目中添加Qt Gui模块,我们只需要在<项目名>.pro中添加两行代码

原先的文件看起来像是这样子的:

# ...
QT	+= core
QT	-= gui
# ...

我们要引入Qt5Gui模块,只需要改变成下面这样

# ...
QT	-= core gui
# ...

这样,我们的项目就可以使用QOpenGL*的类了,因为我们已经包含了Qt5Gui模块

2. 创建窗口类

接下来我们将要创建一个使用OpenGL 类作为基类的窗口类,按Ctrl+N,然后File->New File or Project … 选择C++模版下的C++
在这里插入图片描述
在这里插入图片描述
最后,我们把接口(window.h)改成类似如下:

#ifndef WINDOW_H
#define WINDOW_H

#include <QOpenGLWindow>
#include <QOpenGLFunctions>

class Window : public QOpenGLWindow,
               protected QOpenGLFunctions
{
  Q_OBJECT

// OpenGL Events
public:
  ~Window();

  void initializeGL();
  void resizeGL(int width, int height);
  void paintGL();
  void teardownGL();

private:
  // Private Helpers
  void printContextInformation();
};

#endif // WINDOW_H

这里面没有什么新的东西,我们只是将前面所讲的内容具体化成了一个类。这个窗口类继承了由QOpenGLWindow和我QOpenGLFunctions提供的功能,这使得我们可以使用OpenGL的功能,并且拥有了OpenGL可以在上面绘制的表面(surface)。

不过其中仍然还是有两个新增的东西:

  • teardownGL()
    • 我们需要一个函数来做一些清理工作。如果QOpenGLWIndow::makeCUrrent()是首先被调用的,那么我们可以在析构函数中做清理工作。但这里我想要一个独立的函数来做清理工作来保持我们的接口清晰明确。
  • printContextInformation()
    • 这个辅助程序将打印我们获取到的有关OpenGL上下文的信息,为了方便调试

接下来我们进行函数实现(在window.cpp中):

#include "window.h"
#include <QDebug>
#include <QString>

Window::~Window()
{
  makeCurrent();
  teardownGL();
}

/*******************************************************************************
 * OpenGL Events
 ******************************************************************************/

void Window::initializeGL()
{
  // Initialize OpenGL Backend
  initializeOpenGLFunctions();
  printContextInformation();

  // Set global information
  glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}

void Window::resizeGL(int width, int height)
{
  // Currently we are not handling width/height changes
  (void)width;
  (void)height;
}

void Window::paintGL()
{
  // Clear
  glClear(GL_COLOR_BUFFER_BIT);
}

void Window::teardownGL()
{
  // Currently we have no data to teardown
}

/*******************************************************************************
 * Private Helpers
 ******************************************************************************/

void Window::printContextInformation()
{
  QString glType;
  QString glVersion;
  QString glProfile;

  // Get Version Information
  glType = (context()->isOpenGLES()) ? "OpenGL ES" : "OpenGL";
  glVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));

  // Get Profile Information
#define CASE(c) case QSurfaceFormat::c: glProfile = #c; break
  switch (format().profile())
  {
    CASE(NoProfile);
    CASE(CoreProfile);
    CASE(CompatibilityProfile);
  }
#undef CASE

  // qPrintable() will print our QString w/o quotes around it.
  qDebug() << qPrintable(glType) << qPrintable(glVersion) << "(" << qPrintable(glProfile) << ")";
}

这是一个非常简单的操作,里面只有一两个值得关注的地方

  • initializeGL()

    • QOpenGLFunctions::initializeOpenGLFunctions() ,会使用当前的OpenGL上下文进行初始化操作
    • Window::printContextInfomation()是我们自己的函数,这会在控制台上打印一些版本信息。
    • glClearColor() 函数继承自QOpenGLFunctions。看名字你就应该知道,这清理了颜色。
  • resizeGL()

    • 现在,由于我们还没有做任何复杂的图形,我们在这里面暂时不需要做任何操作,你之后会看到这个函数非常有用
  • paintGL()

    • 仍然是个非常基础的函数,我们只是使用了我们在initializeGL()中设置的颜色来清理了背景色。
  • teardownGL()

    • 很明显现在不需要做什么,我们还没有分配任何GPU资源.
  • printContextInformation()

    • 依据我们如何创建我们的OpenGL上下文,我们可以访问到不同版本与功能的OpenGL.在控制台打印版本信息有时很有用
    • 唯一有技巧性的是QStrings如果直接传给QDebug打印,将会以引号包围着打印.我们这里使用了qPrintable(),这是一个简单的Qt内置的转换成char*的函数,打印时不会被引号包围.

3. 编辑main.cpp来创建窗口

这儿还有一个前面没有提及的Qt5类,QGuiApplication.这个跟OpenGL没有什么特别的关系.默认的是使用QCoreApplication,我们把它谎称QGuiApplication.并且在exec()前我们将创建并现实一个窗口.

#include <QGuiApplication>
#include "window.h"

int main(int argc, char *argv[])
{
  QGuiApplication app(argc, argv);

  // Set OpenGL Version information
  // Note: This format must be set before show() is called.
  QSurfaceFormat format;
  format.setRenderableType(QSurfaceFormat::OpenGL);
  format.setProfile(QSurfaceFormat::CoreProfile);
  format.setVersion(3,3);

  // Set the window up
  Window window;
  window.setFormat(format);
  window.resize(QSize(800, 600));
  window.show();

  return app.exec();
}

代码里本身就很好理解.我们用QSurfaceFormat来制定我们所需要的OpenGL版本.提供一个QSurfaceFormat并不是必须的.

此刻呢,你应该保存、编译、执行,按理(如果你的显卡支持OpenGL 3.3以上的话)你应该会在控制台看到
OpenGL x.x ( CoreProfile )
并且你还会看到一个全黑的窗口
在这里插入图片描述
试着将CoreProfile变成CompatibilityProfile、改变版本,看看输出会有什么不同.

总结

以上是本次教程的所有,今天我们学到了如下内容:

  • Qt5Gui和Qt5OpenGL类有所不同,对于新的程序,请使用机遇Qt5Gui的OpenGL类
  • 通过上面的教程我们可以不以来Qt5Widgets类来创建一个OpenGL的窗口.
  • 更好,更现代的OpenGL支持在Qt5中的Qt5Gui模块中提供
  • 在你的机器上获得一个800x600的简单操作

代码可以在Gitee上下载

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值