QT中使用OpenGL的方法——以绘制三角形为例

本文详细介绍了如何在Qt环境中使用QOpenGLWidget类进行OpenGL图形渲染,包括创建自定义的QtOpenGLWidget类,重写initializeGL、paintGL和resizeGL方法,以及将原生OpenGL代码迁移至Qt的过程。通过一个绘制三角形的例子,展示了Qt中OpenGL的使用方法,使得代码更加简洁且易于维护。
摘要由CSDN通过智能技术生成

前言

传统上学习OpenGL的代码需要先配置好GLFWGLAD
GLFW允许用户创建OpenGL上下文,定义窗口参数以及处理用户输入。
由于OpenGL驱动版本众多,它大多数函数的位置都无法在编译时确定下来,需要用到GLAD在运行时辅助我们查询。
而Qt作为一个GUI框架,在提供窗口的同时又对OpenGL进行了很好的封装,免去了自己配置GLFW和GLAD环境的麻烦。
本文的第三节以经典的绘制三角形为例,描述了如何将原生OpenGL绘制三角形代码迁移到Qt中运行起来。
第一节和第二节是对第三节中环境迁移的背景补充。
简单的说,将OpenGL代码适配的Qt上的方法为:

  1. GLFW和GLAD相关的代码删掉,因为创建窗口依靠Qt提供的QOpenGLWidget,调用OpenGL函数依靠QOpenGLFunctions_x_x_x。
  2. 渲染循环部分的代码放到paintGL()中,改变窗口大小时重绘的代码放到resizeGL()中,其它代码放到initializeGL()中即可。

1 QOpenGLWidget类的使用

QOpenGLWidget用于显示OpenGL代码绘制的图形。使用时需要:

  1. 创建一个新类(本例名为QtOpenGLWidget )并继承自QOpenGLWidgetQOpenGLFunctions_3_3_Core。QOpenGLFunctions_x_x_x中可选择OpenGL的版本等信息,本例选择的是OpenGL3.3核心模式。
  2. 重载三个重要的虚函数initializeGLpaintGLresizeGL
protected:
	void initializeGL() override; //负责初始化
	void paintGL() override;//负责执行绘画,该函数会被自动的反复调用
	void resizeGL(int width, int height) override;//窗口尺寸改变时调用

2 在创建好的Qt空窗口中调用上一步自定义的类

本例首先通过Qt的向导默认创建了一个继承自QMainWindow的名为Tranangle的空窗口类。然后在其构造函数中调用和设置用于显示OpenGL图形的自定义类QtOpenGLWidget

Tranangle::Tranangle(QWidget *parent)
	: QMainWindow(parent)
{
	this->resize(619, 418);//设置程序窗口的大小
	
	//在头文件中声明QtOpenGLWidget *glWidget;
	glWidget = new QtOpenGLWidget(this);//实例化用于显示图形的自定义类
	
	setCentralWidget(glWidget);//将图形显示界面的大小铺满程序窗口
}

配置好以上的代码,构造空窗口Tranangle的时候,会进而自动调用QtOpenGLWidget来完成图案绘制与显示。

3 将原生OpenGL代码迁移至Qt

本节以图片的方式详细的描述了如何将原生OpenGL绘制三角形的代码移植到Qt中完成三角形的绘制。
第一部分
第二部分
第三部分
第四部分
第五部分
第六部分

4 源码

main.cpp

#include "tranangle.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Tranangle w;
    w.show();
    return a.exec();
}

tranangle.h

#pragma once

#include <QtWidgets/QMainWindow>
#include "qtOpenGLWidget.h"

class Tranangle : public QMainWindow
{
    Q_OBJECT

public:
    Tranangle(QWidget *parent = Q_NULLPTR);

private:
	QtOpenGLWidget *glWidget;
};

tranangle.cpp

#include "tranangle.h"

Tranangle::Tranangle(QWidget *parent)
	: QMainWindow(parent)
{
	this->resize(619, 418);
	glWidget = new QtOpenGLWidget(this);
	setCentralWidget(glWidget);
}

qtOpenGLWidget.h

#pragma once

#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <QDebug>

class QtOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Core
{
	Q_OBJECT

public:
	QtOpenGLWidget(QWidget *parent = 0);
	~QtOpenGLWidget();

protected:
	void initializeGL() override;
	void paintGL() override;
	void resizeGL(int width, int height) override;
};

qtOpenGLWidget.cpp

#include "qtOpenGLWidget.h"

const char *vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n" "void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";

const char *fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" "}\n\0";

unsigned int shaderProgram, VAO, VBO;

QtOpenGLWidget::QtOpenGLWidget(QWidget *parent)
	: QOpenGLWidget(parent)
{
}

QtOpenGLWidget::~QtOpenGLWidget()
{
	glDeleteVertexArrays(1, &VAO);
	glDeleteBuffers(1, &VBO);
	glDeleteProgram(shaderProgram);
}

void QtOpenGLWidget::initializeGL()
{
	initializeOpenGLFunctions();//初始化

	//顶点着色器
	unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	glCompileShader(vertexShader);

	//判断顶点着色器是否编译成功
	int success;
	char infoLog[512];
	glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
		qDebug() << "ERROR::SHADER" << infoLog;
	}

	//片段着色器
	unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
	glCompileShader(fragmentShader);

	//判断片段着色器是否编译成功
	glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
		qDebug() << "ERROR::FRAGEMENT" << infoLog;
	}

	//链接阶段
	shaderProgram = glCreateProgram();
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentShader);
	glLinkProgram(shaderProgram);

	//判断是否链接成功
	glGetShaderiv(shaderProgram, GL_LINK_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(shaderProgram, 512, NULL, infoLog);
		qDebug() << "ERROR::SHADERPROGRAM" << infoLog;
	}
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);

	//建立顶点数据
	float vertices[] = {
	-0.5f, -0.5f, 0.0f,
	0.5f, -0.5f, 0.0f,
	0.0f, 0.5f, 0.0f
	};

	//配置顶点属性	
	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);

	//绑定VAO
	glBindVertexArray(VAO);

	//绑定并设置VBO
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	//配置顶点属性
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);

	glBindBuffer(GL_ARRAY_BUFFER, 0);

	glBindVertexArray(0);
}

void QtOpenGLWidget::resizeGL(int width, int height)
{

}

void QtOpenGLWidget::paintGL()
{
	//着色
	glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT);

	//绘制第一个三角形
	glUseProgram(shaderProgram);
	glBindVertexArray(VAO);
	glDrawArrays(GL_TRIANGLES, 0, 3);
}

结尾

Qt以面向对象的方式另外提供了更友好的编码风格和方式,大大提高了代码的可读性。QT中使用OpenGL的方法(二)会介绍如何以这种方式完成Qt中OpenGL的编码。

可以使用以下代码来在 Qt 使用 OpenGL 绘制三角形: ```cpp #include <QtGui/QOpenGLFunctions> #include <QtGui/QOpenGLShaderProgram> #include <QtGui/QOpenGLVertexArrayObject> #include <QtGui/QOpenGLBuffer> class MyOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions { public: MyOpenGLWidget(QWidget *parent = nullptr) : QOpenGLWidget(parent) {} protected: void initializeGL() override { initializeOpenGLFunctions(); // 创建着色器程序 m_program = new QOpenGLShaderProgram(this); m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, R"( #version 330 core layout (location = 0) in vec3 aPos; void main() { gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); } )"); m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, R"( #version 330 core out vec4 FragColor; void main() { FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); } )"); m_program->link(); // 创建顶点数组对象和顶点缓冲对象 m_vao = new QOpenGLVertexArrayObject(this); m_vao->create(); m_vao->bind(); m_vbo = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer); m_vbo->create(); m_vbo->bind(); float vertices[] = { -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, 0.0f, 0.5f, 0.0f }; m_vbo->allocate(vertices, sizeof(vertices)); // 设置顶点属性指针 m_program->bind(); m_program->enableAttributeArray(0); m_program->setAttributeBuffer(0, GL_FLOAT, 0, 3, 0); // 解绑 m_vao->release(); m_vbo->release(); m_program->release(); } void paintGL() override { glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); m_program->bind(); m_vao->bind(); glDrawArrays(GL_TRIANGLES, 0, 3); m_vao->release(); m_program->release(); } private: QOpenGLShaderProgram *m_program; QOpenGLVertexArrayObject *m_vao; QOpenGLBuffer *m_vbo; }; ``` 这段代码使用 QtOpenGL 模块来创建一个继承自 QOpenGLWidget 的自定义 OpenGL 窗口,然后在 initializeGL() 函数初始化着色器程序、顶点数组对象和顶点缓冲对象,最后在 paintGL() 函数绘制三角形
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值