IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> 【Overload游戏引擎】源码分析之五:OvRendering函数库(三) -> 正文阅读

[游戏开发]【Overload游戏引擎】源码分析之五:OvRendering函数库(三)

2021SC@SDUSC

回顾一下前几篇文章,我们讲到了有关图形学三维空间的变换与各种数据存储对象的信息,接下来就是关于三维空间中物体的网格表示。

IMesh.h与Mesh.h

与网格相关的类有两个其中IMesh是一个基类,定义了4个纯虚函数用于子类继承。

namespace OvRendering::Resources
{
	/**
	* Interface for any mesh
	*/
	class IMesh
	{
	public:
		virtual void Bind() = 0;
		virtual void Unbind() = 0;
		virtual uint32_t GetVertexCount() = 0;
		virtual uint32_t GetIndexCount() = 0;
	};
}

而重点则是以下这个Mesh类,它对IMesh进行公有继承,用于实现网格的相关操作。

class Mesh : public IMesh
	{
	public:
		Mesh(const std::vector<Geometry::Vertex>& p_vertices, const std::vector<uint32_t>& p_indices, uint32_t p_materialIndex);
		virtual void Bind() override;
		virtual void Unbind() override;
		virtual uint32_t GetVertexCount() override;
		virtual uint32_t GetIndexCount() override;
		uint32_t GetMaterialIndex() const;
		const OvRendering::Geometry::BoundingSphere& GetBoundingSphere() const;

	private:
		void CreateBuffers(const std::vector<Geometry::Vertex>& p_vertices, const std::vector<uint32_t>& p_indices);
		void ComputeBoundingSphere(const std::vector<Geometry::Vertex>& p_vertices);

	private:
		const uint32_t m_vertexCount;
		const uint32_t m_indicesCount;
		const uint32_t m_materialIndex;

		Buffers::VertexArray							m_vertexArray;
		std::unique_ptr<Buffers::VertexBuffer<float>>	m_vertexBuffer;
		std::unique_ptr<Buffers::IndexBuffer>			m_indexBuffer;

		Geometry::BoundingSphere m_boundingSphere;
	};

Mesh类中包含了以下几个成员变量:

m_vertexCount:网格中的顶点个数;

m_indicesCount:顶点索引个数;

m_materialIndex:材质索引个数;?

m_vertexArray:顶点数组对象;

m_vertexBuffer:顶点缓冲对象;

m_indexBuffer:索引缓冲对象;

m_boundingSphere:当前网格的碰撞球对象。

这里我们看到一个新的数据类型unique_ptr,它是 C++ 11 提供的用于防止内存泄漏的智能指针中的一种实现,独享被管理对象指针所有权的智能指针。unique_ptr对象包装一个原始指针,并负责其生命周期。当该对象被销毁时,会在其析构函数中删除关联的原始指针。
unique_ptr具有->和*运算符重载符,因此它可以像普通指针一样使用。

总的来说就是比起从前的new指针,unique_ptr对象更为安全,这里作了解就好。

这些数据类型在前文都有提及,此处就不再赘述,紧接着我们来看Mesh类的两个重要的私有函数:

1.CreateBuffers

首先我们来看CreateBuffers函数,它的作用在于为传入的网格顶点数据创建一个缓冲。我们看一看到,CreateBuffers函数的两个参数分别是一个顶点向量(相当于一个2维矩阵),以及一个索引向量。

在函数开头,创建了一个浮点向量用于存储顶点数据,然后是一个无符号整型向量用于存储索引数据。

void OvRendering::Resources::Mesh::CreateBuffers(const std::vector<Geometry::Vertex>& p_vertices, const std::vector<uint32_t>& p_indices)
{
	std::vector<float> vertexData;

	std::vector<unsigned int> rawIndices;

然后函数开始了一个遍历过程,在这个地方有一个语句for(auto &a:b),这个语句可以利用a容器来遍历b中的内容,同时可以利用a对b的值做出改变。

for (const auto& vertex : p_vertices)
	{
		vertexData.push_back(vertex.position[0]);
		vertexData.push_back(vertex.position[1]);
		vertexData.push_back(vertex.position[2]);

		vertexData.push_back(vertex.texCoords[0]);
		vertexData.push_back(vertex.texCoords[1]);

		vertexData.push_back(vertex.normals[0]);
		vertexData.push_back(vertex.normals[1]);
		vertexData.push_back(vertex.normals[2]);

		vertexData.push_back(vertex.tangent[0]);
		vertexData.push_back(vertex.tangent[1]);
		vertexData.push_back(vertex.tangent[2]);

		vertexData.push_back(vertex.bitangent[0]);
		vertexData.push_back(vertex.bitangent[1]);
		vertexData.push_back(vertex.bitangent[2]);
	}

在以下for循环中,函数利用变量vertex来存储p_vertices的数据,然后将vertex中的位置信息(position)、纹理坐标(texCoords)、法向量(normals)、切向量(tangent)、侧切向量(bitangent)等信息依次压入vertexData中。利用这个过程将多个变量转为一个变量,方便后期读取。

之后,为vertexData创建一个VBO顶点缓冲对下,并利用make_unique函数(一个创建unique_ptr智能指针的函数)创建一个指向该VBO的指针。

同样的也为索引向量创建上述的索引缓冲指针。

    m_vertexBuffer	= std::make_unique<Buffers::VertexBuffer<float>>(vertexData);
	m_indexBuffer	= std::make_unique<Buffers::IndexBuffer>(const_cast<uint32_t*>(p_indices.data()), p_indices.size());

最后,将VBO中的顶点数据与VAO(即变量m_vertexArray)绑定,并配置顶点信息读取格式。

在这里我们简单来看看,VBO的第一组信息是位置坐标position,所以读取信息的指针为0号,顶点数据来源为VBO _mvertexBuffer,OpenGL特定数据类型为GL_Float,每组数据的长度为3个单位数据,步长为一个vertex结构体所占的字节数。

    uint64_t vertexSize = sizeof(Geometry::Vertex);

	m_vertexArray.BindAttribute(0, *m_vertexBuffer, Buffers::EType::FLOAT, 3, vertexSize, 0);
	m_vertexArray.BindAttribute(1, *m_vertexBuffer,	Buffers::EType::FLOAT, 2, vertexSize, sizeof(float) * 3);
	m_vertexArray.BindAttribute(2, *m_vertexBuffer,	Buffers::EType::FLOAT, 3, vertexSize, sizeof(float) * 5);
	m_vertexArray.BindAttribute(3, *m_vertexBuffer,	Buffers::EType::FLOAT, 3, vertexSize, sizeof(float) * 8);
	m_vertexArray.BindAttribute(4, *m_vertexBuffer,	Buffers::EType::FLOAT, 3, vertexSize, sizeof(float) * 11);

后面的以此类推。

2.ComputeBoundingSphere

接下来是ComputeBoundingSphere函数,该函数的作用是对于一组网格顶点数据计算其碰撞球的中心点与半径。

具体的思路很简单,首先,为碰撞球赋一个初值,坐标为原点,半径为0。

void OvRendering::Resources::Mesh::ComputeBoundingSphere(const std::vector<Geometry::Vertex>& p_vertices)
{
	m_boundingSphere.position = OvMaths::FVector3::Zero;
	m_boundingSphere.radius = 0.0f;

然后,将C++标准模板库的float型数据最大值分别赋值给初始最小坐标minX、minY、minZ;同样将最小值赋值给初始最大坐标maxX、maxY、maxZ。

接着利用上文提到的for语句对p_vertices的数据进行遍历,在访问每一个顶点数据时,将最小坐标的3的分量与当前顶点坐标的3个分量进行比较,选择更小的一方更新最小坐标值;同样最大坐标值进行类似处理,只不过是利用更大的值更新变量。

	if (!p_vertices.empty())
	{
		float minX = std::numeric_limits<float>::max();
		float minY = std::numeric_limits<float>::max();
		float minZ = std::numeric_limits<float>::max();

		float maxX = std::numeric_limits<float>::min();
		float maxY = std::numeric_limits<float>::min();
		float maxZ = std::numeric_limits<float>::min();

		for (const auto& vertex : p_vertices)
		{
			minX = std::min(minX, vertex.position[0]);
			minY = std::min(minY, vertex.position[1]);
			minZ = std::min(minZ, vertex.position[2]);

			maxX = std::max(maxX, vertex.position[0]);
			maxY = std::max(maxY, vertex.position[1]);
			maxZ = std::max(maxZ, vertex.position[2]);
		}

完成上述过程后,就会得到一个网格所能接触的最大与最小的坐标值分量。?

最后,将最大值与最小值求平均,得到的3个坐标分量就是当前网格的碰撞球的中心点;同时再度遍历所有顶点,将该顶点到碰撞球中心的距离,与当前碰撞球半径作比较,去最大值更新碰撞球半径。

		m_boundingSphere.position = OvMaths::FVector3{ minX + maxX, minY + maxY, minZ + maxZ } / 2.0f;

		for (const auto& vertex : p_vertices)
		{
			const auto& position = reinterpret_cast<const OvMaths::FVector3&>(vertex.position);
			m_boundingSphere.radius = std::max(m_boundingSphere.radius, OvMaths::FVector3::Distance(m_boundingSphere.position, position));
		}
	}
}

如此,便完成了网格碰撞球的计算。

3.其他函数

剩下的函数与前文提到的一些函数大同小异,都是对一些具体函数进行二次封装,在这里,就不做太多介绍。有一点需要注意的是,其中的一些函数是对IMesh基类中的纯虚函数的重定义,如果Mesh类中没有完成该操作,就会产生错误。

OvRendering::Resources::Mesh::Mesh(const std::vector<Geometry::Vertex>& p_vertices, const std::vector<uint32_t>& p_indices, uint32_t p_materialIndex) :
	m_vertexCount(static_cast<uint32_t>(p_vertices.size())),
	m_indicesCount(static_cast<uint32_t>(p_indices.size())),
	m_materialIndex(p_materialIndex)
{
	CreateBuffers(p_vertices, p_indices);
	ComputeBoundingSphere(p_vertices);
}

void OvRendering::Resources::Mesh::Bind()
{
	m_vertexArray.Bind();
}

void OvRendering::Resources::Mesh::Unbind()
{
	m_vertexArray.Unbind();
}

uint32_t OvRendering::Resources::Mesh::GetVertexCount()
{
	return m_vertexCount;
}

uint32_t OvRendering::Resources::Mesh::GetIndexCount()
{
	return m_indicesCount;
}

uint32_t OvRendering::Resources::Mesh::GetMaterialIndex() const
{
	return m_materialIndex;
}

const OvRendering::Geometry::BoundingSphere& OvRendering::Resources::Mesh::GetBoundingSphere() const
{
	return m_boundingSphere;
}

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-11-09 19:56:40  更:2021-11-09 19:57:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/28 0:28:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码