QT+OpenGL实现Coordinate Systems,绘制立方体

将learningopengl入门篇的Coordinate Systems代码在QT框架下实现,绘制一些带纹理贴图的动态立方体


一、环境

操作系统:Windows 11
IDE:Microsoft Visual Studio Community 2022 (64 位)
QT:5.12.12

二、代码实现

learningopengl Hello Triangle章节教程:

https://learnopengl-cn.github.io/01%20Getting%20started/08%20Coordinate%20Systems/

我们要做的是这节教程最后的绘制10个立方体,相应的GLFW框架下的代码:

https://learnopengl.com/code_viewer_gh.php?code=src/1.getting_started/6.3.coordinate_systems_multiple/coordinate_systems_multiple.cpp

对照GLFW框架下代码进行以下修改

glm

和二维渲染不同,在三维空间下显示、渲染涉及到物体的平移、旋转和相机的计算,需要大量的矩阵运算,OpenGL内没有实现矩阵运算的方法,常用的第三方库是GLM,教程中的代码使用的也是这个库

我使用的版本是glm0.9.9.8,下载链接:

https://github.com/g-truc/glm/tags

GLM是一个header only库,只需要包括了相应的头文件就可以使用它提供的类和函数。不需要进行额外的编译,只要设置工程的头文件包含目录即可。
在这里插入图片描述

着色器类 shader.h

教程中实现了一个自己的着色器类

https://learnopengl.com/code_viewer_gh.php?code=includes/learnopengl/shader.h

这部分代码直接拿过来用,需要进行一些修改

glad->QOpenGLFunctions
对头文件进行替换

//#include <glad/glad.h>
#include <QOpenGLFunctions>

QT框架下Shader类需要继承QOpenGLFunctions类,才能初始化和使用OpenGL的方法

class Shader : protected QOpenGLFunctions
{
	...
	...
	...
}

初始化OpenGL函数指针,在构造函数最前面调用initializeOpenGLFunctions

	Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath = nullptr)
	{
		this->initializeOpenGLFunctions();
		
		...
		...
		...
	}

删除所有utility uniform functions相关方法的const修饰,这个应该是编译器差异的问题

在这里插入图片描述

着色器

教程中着色器代码写在了两个文件中

https://learnopengl.com/code_viewer_gh.php?code=src/1.getting_started/6.3.coordinate_systems_multiple/6.3.coordinate_systems.vs
https://learnopengl.com/code_viewer_gh.php?code=src/1.getting_started/6.3.coordinate_systems_multiple/6.3.coordinate_systems.fs

直接创建两个相同的文件,并确保程序运行时能找到这两个文件

纹理贴图

教程中用到了木箱和笑脸的两个贴图

https://learnopengl-cn.github.io/img/01/06/container.jpg
https://learnopengl-cn.github.io/img/01/06/awesomeface.png

将他们下载下来放在resources\textures\目录下,下面程序调用时是从这个目录读取

stb_image.h

读取纹理贴图时用到了这个单头像图像加载库stb_image.h

https://github.com/nothings/stb/blob/master/stb_image.h

使用这个库需要两个文件stb_image.hstb_image.cppstb_image.h直接下载,stb_image.cpp只需要两行代码

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

QOpenGL控件

新建一个QOpenGL控件类CoordinateSystemsMultipleWidget,继承QOpenGLWidget类,并重载initializeGLresizeGLpaintGL三个方法,包含glm的头文件和stb_image.h,代码如下

#include "CoordinateSystemsMultipleWidget.h"
#include "stb_image.h"

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <qDebug>


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

CoordinateSystemsMultipleWidget::~CoordinateSystemsMultipleWidget()
{

}

void CoordinateSystemsMultipleWidget::initializeGL()
{
	this->initializeOpenGLFunctions();    //为当前上下文初始化提供OpenGL函数解析
}

void CoordinateSystemsMultipleWidget::resizeGL(int w, int h)
{
	glViewport(0.0f, 0.0f, w, h);    //调整视口
}

void CoordinateSystemsMultipleWidget::paintGL()
{
}

初始化

复制将教程中main函数中while (!glfwWindowShouldClose(window))之前的初始化代码,找到上一步新建的CoordinateSystemsMultipleWidget控件类的initializeGL()方法,在initializeOpenGLFunctions后粘贴。

1、删除最前面的GLFW初始化的代码和GLAD初始化的代码。

2、替换VAO相关的代码

	unsigned int VAO; // 声明
	glGenVertexArrays(1, &VAO); // 创建
	glBindVertexArray(VAO); // 绑定
	glBindVertexArray(0); // 解绑

分别替换为

    QOpenGLVertexArrayObject VAO; // 声明
    VAO.create(); // 创建
    if(!VAO.isCreated()){
        qDebug()<<"vao is not created.";
    }
    VAO.bind(); // 绑定
    VAO.release(); // 解绑

3、stbi_load使用的FileSystem::getPath获取路径的方法报错,删除他们,直接写入字符串即可

在这里插入图片描述

渲染 render

复制将教程中main函数中while (!glfwWindowShouldClose(window))中渲染部分的代码,粘贴到CoordinateSystemsMultipleWidget控件类的paintGL()方法中

1、删除键盘、鼠标时间响应的代码processInput(window)和最后面glfw相关的两行代码

2、ourShadertexture1texture2变量报错,将initializeGL()中他们的定义的移动到函数外或类内,并修改相应的初始化代码和调用代码

3、将SCR_WIDTHSCR_HEIGHT改为this->width()this->height()

4、修改glBindVertexArray(VAO);VAO.bind();

5、cubePositions报错,将其定义从initializeGL()中移动到函数外。

timer刷新和动态

到目前为止,教程中的代码已经全部在QT框架下实现,编译运行就能看到空间中的立方体,表面覆盖了木箱和笑脸的纹理贴图
在这里插入图片描述
但是显示的内容是静止的,这是因为在代码中每个立方体的位置和姿态都是静止的,并且我们也没有不断的调用paintGL()中的渲染代码。

initializeGL()方法的最后面开启一个定时器,定时调用update()方法,实现界面的不断刷新

void CoordinateSystemsMultipleWidget::initializeGL()
{
	...
	...
	...


	timer = new QTimer();
	timer->setInterval(33);
	connect(timer, SIGNAL(timeout()), this, SLOT(update()));
	timer->start();
}

paintGL()方法中,在model = glm::translate(model, cubePositions[i]);后增加一行代码让模型旋转起来

		model = glm::rotate(model, angle, glm::vec3(0.5f, 1.0f, 0.0f));

最终paintGL()方法的代码为:

void CoordinateSystemsMultipleWidget::paintGL()
{
	// render
	// ------
	glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // also clear the depth buffer now!

	 // bind textures on corresponding texture units
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, texture1);
	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, texture2);

	// activate shader
	ourShader->use();

	// create transformations
	glm::mat4 view = glm::mat4(1.0f); // make sure to initialize matrix to identity matrix first
	glm::mat4 projection = glm::mat4(1.0f);
	projection = glm::perspective(glm::radians(45.0f), (float)this->width() / (float)this->height(), 0.1f, 100.0f);
	view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
	// pass transformation matrices to the shader
	ourShader->setMat4("projection", projection); // note: currently we set the projection matrix each frame, but since the projection matrix rarely changes it's often best practice to set it outside the main loop only once.
	ourShader->setMat4("view", view);

	// render boxes
	VAO.bind();
	static float angle = 0;
	angle += 0.1;
	if (angle >= 360)
		angle -= 360;
	for (unsigned int i = 0; i < 10; i++)
	{
		// calculate the model matrix for each object and pass it to shader before drawing
		glm::mat4 model = glm::mat4(1.0f);
		model = glm::translate(model, cubePositions[i]);
		model = glm::rotate(model, angle, glm::vec3(0.5f, 1.0f, 0.0f));
		float angle = 20.0f * i;
		model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
		ourShader->setMat4("model", model);

		glDrawArrays(GL_TRIANGLES, 0, 36);
	}
}

再次编译运行,界面中的每个立方体都旋转起来了。
在这里插入图片描述


相关链接和参考

https://learnopengl-cn.github.io/01%20Getting%20started/08%20Coordinate%20Systems/
https://learnopengl.com/code_viewer_gh.php?code=src/1.getting_started/6.3.coordinate_systems_multiple/coordinate_systems_multiple.cpp
https://blog.csdn.net/qq_42537915/article/details/104146135

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值