2021SC@SDUSC
目录
Model
1.构造与析构
2.GetBoundingSphere和ComputeBoundingSphere
在前几节的内容中提到了ModelLoaeder类,本节就正式来讲Model类的内容。
与Shader与Texture一样,Model同样在最开始将自身的loader作为友元类,同时我们可以看到所谓的模型(model)就是一系列网格的结合。
namespace Loaders { class ModelLoader; }
/**
* A model is a combinaison of meshes
*/
class Model
{
friend class Loaders::ModelLoader;
public:
/**
* Returns the meshes
*/
const std::vector& GetMeshes() const;
/**
* Returns the material names
*/
const std::vector& GetMaterialNames() const;
/**
* Returns the bounding sphere of the model
*/
const OvRendering::Geometry::BoundingSphere& GetBoundingSphere() const;
private:
Model(const std::string& p_path);
~Model();
void ComputeBoundingSphere();
public:
const std::string path;
private:
std::vector m_meshes;
std::vector m_materialNames;
Geometry::BoundingSphere m_boundingSphere;
};
一个模型对象需要包括以下几个重要信息:网格(meshes)、材质(material),以及碰撞球(boundingsphere),除此之外作为一个工具类,它还需要模型的存储路径path。
为了存储模型网格,我们需要一个类型为mesh指针的向量,同时还需要一个类型为字符串的向量存储材质的名称。
OvRendering::Resources::Model::Model(const std::string & p_path) : path(p_path)
{
}
OvRendering::Resources::Model::~Model()
{
for (auto mesh : m_meshes)
delete mesh;
}
model的构造函数很简单,只需要将模型存储路径赋值给自身的path变量;而析构函数的主要作用就是销毁每一个网格指针,这里用变量mesh遍历网格向量,取出每一个网格对象的指针后delete删除。
const OvRendering::Geometry::BoundingSphere& OvRendering::Resources::Model::GetBoundingSphere() const
{
return m_boundingSphere;
}
获取碰撞球对象的函数返回了自身的碰撞球对象,而要获得这个对象需要调用自身的私有函数ComputeBoundingSphere(),接下来我们就来看看它的详细内容。
void OvRendering::Resources::Model::ComputeBoundingSphere()
{
if (m_meshes.size() == 1)
{
m_boundingSphere = m_meshes[0]->GetBoundingSphere();
}
最开始需要判断网格的数量,因为可能出现由一个单独网格构成的模型,若网格向量的大小为1,则m_boundingSphere 直接赋值为第一个网格的碰撞球对象。
若是其他情况,我们需要进行更复杂的处理,首先为自身的m_boundingSphere赋初值,中心点position等于零向量,半径radius为0。
else
{
m_boundingSphere.position = OvMaths::FVector3::Zero;
m_boundingSphere.radius = 0.0f;
之后判断网格向量的是否为空,向量空时不做处理;反之开始计算。这里的步骤与计算mesh网格的碰撞盒时类似,首先将std限制的浮点数最大值与最小值分别赋值给最小顶点坐标与最大顶点坐标,注意这里是将最小赋给最大,最大赋给最小。
if (!m_meshes.empty())
{
float minX = std::numeric_limits::max();
float minY = std::numeric_limits::max();
float minZ = std::numeric_limits::max();
float maxX = std::numeric_limits::min();
float maxY = std::numeric_limits::min();
float maxZ = std::numeric_limits::min();
之后遍历所有网格,先获取当前网格的碰撞盒信息,然后将碰撞盒中心坐标与半径相减,并与上述最小坐标做比较去最小值,用最后的结果更新最小坐标;最大坐标的更新也是类似,但需要将相减改为相加,比较时取最大值。
for (const auto& mesh : m_meshes)
{
const auto& boundingSphere = mesh->GetBoundingSphere();
minX = std::min(minX, boundingSphere.position.x - boundingSphere.radius);
minY = std::min(minY, boundingSphere.position.y - boundingSphere.radius);
minZ = std::min(minZ, boundingSphere.position.z - boundingSphere.radius);
maxX = std::max(maxX, boundingSphere.position.x + boundingSphere.radius);
maxY = std::max(maxY, boundingSphere.position.y + boundingSphere.radius);
maxZ = std::max(maxZ, boundingSphere.position.z + boundingSphere.radius);
}
m_boundingSphere.position = OvMaths::FVector3{ minX + maxX, minY + maxY, minZ + maxZ } / 2.0f;
m_boundingSphere.radius = OvMaths::FVector3::Distance(m_boundingSphere.position, { minX, minY, minZ });
}
}
}
在遍历了所有网格之后,min会成为距离坐标原点最近的碰撞球表面顶点,max会成为距离坐标原点远的碰撞球表面顶点。得到这些信息,我们构建一个包含所有网格的碰撞球,他的中心点坐标等于(max+min)/2,半径大小等于中心点与最小坐标的距离(也可以是最大坐标)。
本节内容较少,主要是对之前的补充,模型加载的更多内容已在前文【Overload游戏引擎】源码分析之八:OvRendering函数库(六)的ModelLoader中讲过,详细内容可以翻阅。