QtOpenGL之创建窗口Qt5

这个教程是从一个国外的博主搬过来的,我做了一些简单翻译和简化工作,因为我发现目前存在的qtopengl的代码版本太低了,很难上手使用,因此我将在Qt5的基础上,说明下qtopengl的使用,并将文章作为自己的一些笔记,笔者能力有限,可能存在一些疏忽的地方,欢迎大家指证。

在接下来的介绍中,已经默认读者掌握了Qt的 信号和槽的使用,并能简单的构建一些应用程序。注意这里不是opengl或qt的教程,而是这两者技术的结合。

注意如果你对Opengl的知识还是不够了解,请移步这里至了解下基础知识,方便后面教程的理解。

 

QOpenGLWindow

QOpenGLWindow是一个新类,仅继承自基于Qt5Gui的类。 之所以重要,是因为它允许我们提供OpenGL抽象,而无需Qt5Widgets模块。 

我们真正关心的只有QOpenGLWindow的是以下功能:

initializeGL()
resizeGL(int width,int height)
paintGL()

可以想象,这些功能使我们能够执行OpenGL逻辑。 实际上,这就是创建一个简单的OpenGL应用程序所需要的全部。

QOpenGLFunctions 

为方便起见,我们可以选择将QOpenGLFunctions与QOpenGLWindow一起子类化。在现代版本的Qt中,不需要GLEW,并且QOpenGLFunctions是可以使用OpenGL ES 2.0 API的结构。 (我们将简短地进行此操作。)

注:此处的Opengl ES2.0是早期的版本,开放性不及3.3版本,此外3.3以后的版本更新都是在此基础上增加额外功能,因此我们这里使用的都是3.3以上的API接口,如果你是只老鸟就忽略吧

你不需要子类来访问QOpenGLFunctions的功能,如果愿意,可以通过QOpenGLContext获取可用的功能。可以通过以下两种方式之一将其实例化为局部变量:

QOpenGL函数示例C ++

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

之所以默认为OpenGL ES 2.0,是出于兼容性方面的考虑,因此我们可以轻松地将产品移植到嵌入式平台(例如Android和iOS)。我们的示例将使用此函数上下文,但是我们也可以要求特定的函数上下文。 (例如QOpenGLFunctions_4_3_Core)

这是很不错的,因为我们可以将自己限制为仅要支持的上下文。除了OpenGL ES 2.0 API,我们没有其他需要,因此我们将坚持使用QOpenGLFunctions类。

创建一个窗口

有了这些知识,我们将从创建OpenGL窗口开始。 多亏了Qt5,使该应用程序变得微不足道,因为跨平台OpenGL最难的部分已设置好。 (由于需要GLEW,因此特别涉及Windows。)这将为我们其他项目提供一个不错的起点。

1,准备一个新项目(Qt5.4 GuiModule)

首先,我们将创建一个新的Qt项目,没什么特别的-我通常选择Console Application并随需添加所需的内容。

 有一点我们需要注意的是,我们需要在我们的项目文件中添加一些东西,我们要把Qt5Gui的模块添加进去。

原来的项目文件如:

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

添加完Qt5Gui 模块后,我们需要编辑为如下:

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

现在我们可以使用QOpengl相关的类了,因为这是Qt5Gui模块的一部分。

2.创建一个窗口类 

接下来,我们需要用之前了解到的opengl类创建一个窗口类,首先新建一个类文件。

 然后我们编辑我们的windows.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

这里我们继承了两个类,从而以便于我们可以使用一些opengl的功能,但是有两个新内容我们有必要解释一下,

  • teardownGL()
    • 我们需要一个函数来执行清理的工作。如果 OpenGLWindow::makeCurrent()第一次被调用,清理工作会在析构中完成,但是我想要一个特殊的函数使得我们的接口清晰明显。
  • printContextInformation()
    • 此辅助函数将打印有关我们已获取的OpenGL上下文的信息,以用于调试目的。

 接下来我们实现我们的函数(window.cpp)

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

Window::~Window()
{
  makeCurrent();//当基础平台窗口已被破坏时,这样可以确保析构函数中的OpenGL资源清理操作始终有效。
  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)
{
  (void)width;
  (void)height;
}

void Window::paintGL()
{
  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::printContextInformation() 这是我们自己编写的函数, 这会在输出台打印一些版本的信息。
    • glClearColor() 实际上继承于QOpenGLFunctions,这可以简单的设置清除的颜色
  • resizeGL()
    • 由于我们没有做任何复杂的图形,因此在此功能中我们什么也不做。
  • paintGL()
    • 同样,非常基本,我们只是使用在initializeGL()中设置的颜色清除背景色。
  • teardownGL()
    • 什么也不做, 我们还没有在GPU上分配任何资源。
  • printContextInformation()
    • 基于我们如何创建OpenGL上下文,我们可以访问OpenGL的不同版本和功能。 据我们所知,在控制台中打印版本非常有用(作为健全性检查)。

快要完了,但还有一些工作。

3.更新main.cpp来创建函数

实际上,我前面没有提到另一个Qt5类。 QGuiApplication。 它不是特定于OpenGL的,因此我不愿意为它添加详细的说明。 现在,main.cpp中的默认功能包括创建一个QCoreApplication并运行它。

我们将使用QGuiApplication进行更改(因为这就是我们所做的)。 在执行exec()之前,我们将创建并显示一个Window。


#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,但这是检查我们的printContextInformation()函数功能的好方法。

此时,您应该能够保存,构建和运行。 使用当前输入,您将看到获得的响应(如果您的计算机支持OpenGL 3.3)为:

OpenGL 3.3(CoreProfile)

对于我们所做的所有工作,您都应该拥有一个平淡无奇的窗户。

 

尝试将CoreProfile更改为CompatibilityProfile,并在不同的版本号之间进行操作; 检查输出是否有意义。 NoProfile保留用于不包含核心/兼容性上下文请求的版本。

源码链接

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值