在Qt中使用OpenGL(六)

本文介绍如何在Qt中使用OpenGL构建3D模型,重点是模型基类的设计和色子模型的实现。通过创建基类,定义顶点信息、纹理和3D变换,再实现色子模型的构造、缓存初始化和绘制,最后展示如何在3D窗口中同时绘制多个旋转的色子模型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

在Qt中使用OpenGL(一)
在Qt中使用OpenGL(二)
在Qt中使用OpenGL(三)
在Qt中使用OpenGL(四)
在Qt中使用OpenGL(五)
在前面的文章中,我们终于实现了自由查看3D世界的功能,现在无论我们之后要创建什么样的3D世界,我们都有能力自由的在其中探索了。
那么,接下来就是需要大家努力思考的问题了:我们要如何构建一个3D世界?
难不成,我们需要手动的为所有我们想要画出来的东西,编写顶点信息和纹理坐标?哪怕我们要画出来1000头牛也要手动进行?
很显然这是不可能的。

模型的基类

一般情况下,构建一个3D世界我们会使用模型这个概念。
一个模型我们就可以理解为一个物体。
比如,一个茶壶,一个人,一个桌子,一张凳子,它们都可以是一个模型。
那么,我们只要指定这些模型的位置和旋转角度,乃至大小,是不是一个简单的3D世界我们就构建出来了?
那么,根据我们之前对于OpenGL的了解,想要画出一个东西出来,我们至少需要两个东西:顶点和纹理。
其中,顶点应该包含位置坐标和纹理坐标,而纹理则是一张图,不,是至少一张图。
之前我们也说过,在OpenGL的世界中,纹理坐标是基于当前激活的纹理来计算的。这也就意味着,我们只需要在绘制前激活不同的纹理,我们就可以在绘制的时候使用不同的纹理来绘制我们的模型。
简单来说,就是茶壶和桌子可以使用不同的纹理。
我们只需要在绘制茶壶的时候激活茶壶纹理,绘制桌子的时候激活桌子纹理就行了。乃至我们可以在绘制茶壶嘴的时候激活一张贴图,绘制茶壶盖的时候激活另一张贴图都是没什么问题的。
好了,那么让我们来总结一下,一个模型中至少应该有哪些东西。

  1. 顶点信息(包括位置坐标和纹理坐标)
  2. 纹理(可以有多个纹理)
  3. 最终在3D世界中的变换(也就是Shader中需要的模型矩阵,可以用来让模型缩放,旋转,平移)

当然,实际情况的模型是会包含更多的内容的,考虑到目前有些东西我们还没有掌握,所以这里就用我们已知的知识来总结。
除了这些数据上的东西,对于要绘制一个模型,我很显然还需要VAO,VBO和Shader。并且,是每一个模型,都需要一个独立的VAO,VBO与Shader。因为我们目前就是这么做的,那么当我们需要画多个物体的时候,重复多次我们之前的行为是一个很正常的操作。
那么,此时你的脑海中是不是就出现了一个类的基本架构了呢?

struct Vertex
{
   
	QVector3D pos;
	QVector2D texture;
};

class Model : public QOpenGLExtraFunctions
{
   
public:
	Model();
	~Model();
public:
	void setScale(float val) {
    m_scale = val; }
	void setRotate(const QVector3D &rotate) {
    m_rotate = rotate; }
	void setPos(const QVector3D &pos) {
    m_pos = pos; }
public:
	void setVertices(const QVector<Vertex> &vertices) {
    m_vertices = vertices; }
	void setTexture(QOpenGLTexture *texture, int index = -1);
	void setShaderProgram(QOpenGLShaderProgram *program) {
    m_program = program; }
public:
	QMatrix4x4 model();
public:
	virtual void init();
	virtual void update();
	virtual void paint(const QMatrix4x4 &projection, const QMatrix4x4 &view);
protected:
	QVector3D m_pos{
    0,0,0 };
	QVector3D m_rotate{
    0,0,0 };
	float m_scale = 1;
	QVector<Vertex> m_vertices;
	QMap<int, QOpenGLTexture *> m_textures;
	QOpenGLVertexArrayObject m_vao;
	QOpenGLBuffer m_vbo;
	QOpenGLShaderProgram *m_program = nullptr;
};

我们的模型继承QOpenGLExtraFunctions是为了方便使用OpenGL的函数。
成员函数与变量都至少是protected是因为我们实际上目前无法知道一个模型绘制的细节,所以我们首先制定好一个模型的核心内容,形成一个基类,然后将实现的细节部分交给继承的类来做。
很容易理解的原因就是,我们没有办法确定,我们在初始化与绘制的时候,具体要使用什么样的Shader,怎么绑定数据,也不知道具体要怎么去绘制三角形,是画两个三角形形成一个矩形然后重复呢?还是只画一个三角形然后重复呢?
所以,我们先只顶下一个框架。
此时我们可以做的事情不多,也就是如何保存纹理以及如何生成模型矩阵。

void Model::setTexture(QOpenGLTexture *texture, int index)
{
   
	if (index == -1)
	{
   
		if (m_textures.isEmpty())
		{
   
			index = 0;
		}
		else
		{
   
			index = m_textures.keys().last() + 1;
		}
	}
	m_textures.insert(index, texture);
}

QMatrix4x4 Model::model()
{
   
	QMatrix4x4 _mat;
	_mat.setToIdentity();
	_mat.translate(m_pos);
	_mat.rotate(m_rotate.x(), 1, 0, 0);
	_mat.rotate(m_rotate.y(), 0, 1, 
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值