2021SC@SDUSC

目录

IMesh.h与Mesh.h

1.CreateBuffers

2.ComputeBoundingSphere

3.其他函数


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

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;
}

【Overload游戏引擎】源码分析之五:OvRendering函数库(三)相关推荐

  1. 虚幻引擎源码分析(5)

    虚幻引擎源码分析(5)

  2. 从源码分析Android的Glide库的图片加载流程及特点

    转载:http://m.aspku.com/view-141093.html 这篇文章主要介绍了从源码分析Android的Glide库的图片加载流程及特点,Glide库是Android下一款人气很高的 ...

  3. 【Apollo源码分析】系列的第三部分【prediction】_slamcode的博客 -CSDN博客

    [Apollo源码分析]系列的第三部分[prediction]_slamcode的博客 -CSDN博客

  4. jQuery源码分析之$.grep()函数四问

    问题1:jQuery.grep源码是什么? //grep函数,第三个参数表示是否根据fn的结果取反! grep: function( elems, callback, invert ) { var c ...

  5. SequoiaDB 系列之五 :源码分析之main函数

    好久好久没有写博客了,因为一直要做各种事,工作上的,生活上的,这一下就是半年. 时光如梭. 这两天回头看了看写的博客,感觉都是贻笑大方. 但是还是想坚持把SequoiaDB系列写完. 初步的打算已经确 ...

  6. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  7. Linux内核 eBPF基础:ftrace源码分析:过滤函数和开启追踪

    Linux内核 eBPF基础 ftrace基础:过滤函数和开启追踪 荣涛 2021年5月12日 本文相关注释代码:https://github.com/Rtoax/linux-5.10.13 上篇文章 ...

  8. EOSIO源码分析 - EOSIO合约开发库

    EOSIO合约开发库 通过简单的源码分析,可以很清楚的看到EOSIO合约开发库在目录libraries下,各个库的功能如下: 注意:由于篇幅问题,只介绍最主要的,常用的 CDT: 总目录|----li ...

  9. jQuery源码分析之$.inArray()函数

    测试代码1: //indexOf原生方法:indexOf(特定的元素,开始下标); //同时indexOf的第二个参数可以是负数,表示从倒数第几个开始,记住,此时不是看下标,而是看倒数第几个! var ...

  10. sqrt函数实现(涉及3D游戏引擎源码)

    转载自:http://blog.csdn.net/stormbjm/article/details/8191737 我们平时经常会有一些数据运算的操作,需要调用sqrt,exp,abs等函数,那么时候 ...

最新文章

  1. [原创].NET 分布式架构开发实战五 Framework改进篇
  2. zwpython_零起点Python大数据与量化交易
  3. Powerdesigner数据库建模工具教程
  4. 批量快速一键修改IP,掩码,网关,以及dns代码
  5. 数学差、物理差、英语又烂的放牛娃,后来竟成了清华校长,还做出了诺奖级的研究成果!...
  6. C#根据网址生成静态页面
  7. php 安装zip,php zip拓展安装
  8. ios 内联函数 inline ---分解LFLiveKit
  9. HDOJ--1596--find the safest road
  10. 多元回归理论及R语言实现
  11. 手机连接电脑DCIM目录下文件夹和图片显示不全
  12. 布署LAMP环境(分离部署)
  13. FL Studio20.9安装汉化版水果下载教程
  14. vuejs2.0 数组操作 提示Cannot read property 'push' of undefined
  15. Cannot find module 'xxx' 错误的解决方案
  16. nginx正向代理的配置及实现
  17. 明朝时期中外的火器对比
  18. 用计算机写作文主题,用计算机写作文》——学习智能ABC输入法
  19. 推荐一些旅途的电影,歌曲和文章
  20. 许昌一高2021年高考成绩查询,2021年许昌最好的高中排名,许昌重点高中升学率排名...

热门文章

  1. 3种解法 - 两水壶拼水问题
  2. 开源与安全的“冰与火之歌”
  3. 这些4K手机、电脑壁纸网站,你一定要知道
  4. OCR图片文字识别,人工手动图片标注软件安装过程
  5. PHP实现微信公众平台开发---提升篇(网页授权接口)
  6. windows2003系统在启动登录界面的时候蓝屏报错:STOP:c0000218 {Registry File Failure}
  7. 如何为自己的网站添加关键字
  8. Genio 500核心板,MT8385安卓核心板定制方案
  9. java手机号归属地查询
  10. Android 打开网络上pdf文件