1、本节要实现的内容
前边我们了解了组件的概念,接下来我们就要了解一下MeshComponent组件,也就是用于显示网格(模型)的组件。这个组件也非常的常用,在三维的世界里,我们有很多很多的物体,每一个物体都可以拥有三维模型,那我们就可以给物体添加一个MeshComponent组件,即每个GameObject(游戏对象)都可以拥有MeshComponent组件,我们只要告诉这个组件模型的路径文件,就可以自动加载并显示该模型,这样可以极大的方便模型的显示,也便于统一管理。这里我们模型主要为静态(无动作的模型),主要以加载OBJ格式模型为主。
添加树木模型MeshCompoment演示
2、 Mesh Component 的基本概念
Mesh Component 是计算机图形学和游戏开发中用于表示3D模型的基本结构单元。它由顶点、边和面构成,定义了物体的几何形状和外观。Mesh Component 通常包含顶点位置、法线、纹理坐标等数据,用于渲染和物理模拟。
3、Mesh Component 的主要功能
Mesh Component 提供了加载、渲染和修改3D模型的功能。它可以导入外部模型文件(如OBJ),并在运行时动态调整顶点数据。Mesh Component 还支持材质和贴图的绑定,以实现复杂的光照和视觉效果。 该组件通常用于场景搭建:建筑、道路、树木、道具等固定场景物体。
主要是在一个游戏里面,我们需要各种各样的游戏场景,那也就是说,我们每一个游戏物体基本上它是需要有外观的,那么这个外观呢,就是我们的3d模型,我们这里设计一个,网格的组件就是为了方便给game object挂载,但game object挂载了这个游戏组件后,就可以很轻松方便的便捷的从资源文件中加载一个obj文件,当然,我们这里为了方便起见,暂时只支持obj文件的模型加载,当然,如果你自己需要加载嗯,其他类型的文件都是可以的,但是因为我们自己做的这个程序没有那么复杂,因此我们就用简单的obj文件就可以了。当然我们确实没有合适的 obj格式的模型文件,我们可以用blender等三维模型软件将它这种格式转换成obj格式,然后再用用我们的模型加载。
cpp
class MeshComponent:public Component
{
public:
//显示的网格类
Mesh MainMesh;
//控制显示控件的显示标识
bool tagVisible;
public:
//初始化
MeshComponent();
void OnSolid3DPaint(HWND hWnd,HDC hDC,Shader *tempShader);
};
这里头我们看到mesh component其实是一个很简单的类,它自身只包括一个简单的网格match类,我们只要在这个类里头实现网格卖是类的显示即可。由于前面我们的mash网格类已经基本实现,所以这里头这个类里头的代码基本上很少,仅仅是把网格显示出来而已。这个类最大的作用是,它将一个网格添加到了一个组件中,他只是继承了一个组件的作用。也就是后期我们所有的game object物体,如果需要就可以自行添加这个Mesh component组件,如果game object不需要模型的显示,那么我们也无需添加该组件,这样可以最优化的节省节省空间,让类的结构不至于太繁琐。也就是想想显示模型就加这该组件,如果不想显示就不加该组件,灵活性很高。
4、Mesh Component 的实现示例
以下是一个简单的代码示例,展示如何实现Mesh Component,这里就是通过成员变量mainmesh加载网格模型,并在显示函数中将网格显示出来就可以了。但这里要注意一个mesh component,一定要跟我们前面的transform component,一起配合使用,因为我们的网格也就是我们的模型显示是需要有位置的,各个物体的位置不同,它的模型显示位置也不同,因此,我们在显示模型前要获取当前物体的transform component的模型矩阵model matrix,每一个物体都必定有一个transform component。这样我们就可以在世界各个位置显示上不同的模型了。
cpp
MeshComponent::MeshComponent()
{
//当前物体的名称
SetName("MeshComponent");
//当前物体的类型
SetType("MeshComponent");
//随机颜色
switch(rand()%7)
{
case 0:MainMaterial.diffuse=glm::vec4(1.0f,1.0f,1.0f,1.0f);break;
case 1:MainMaterial.diffuse=glm::vec4(1.0f,0.0f,0.0f,1.0f);break;
case 2:MainMaterial.diffuse=glm::vec4(0.0f,1.0f,0.0f,1.0f);break;
case 3:MainMaterial.diffuse=glm::vec4(0.0f,0.0f,1.0f,1.0f);break;
case 4:MainMaterial.diffuse=glm::vec4(1.0f,1.0f,0.0f,1.0f);break;
case 5:MainMaterial.diffuse=glm::vec4(1.0f,0.0f,1.0f,1.0f);break;
case 6:MainMaterial.diffuse=glm::vec4(0.0f,1.0f,1.0f,1.0f);break;
}
//默认设置为启用材质
MainMaterial.tagEnable=1;
}
void MeshComponent::OnSolid3DPaint(HWND hWnd,HDC hDC,Shader *tempShader)
{
//显示基类函数
Component::OnSolid3DPaint(hWnd,hDC,tempShader);
//重置并设置模型矩阵
ModelMatrix=glm::mat4(1.0f);
//获取世界坐标系下父子结构下的模型矩阵
ModelMatrix=ptParent->Transform.GetLocalToWorldMatrix();
//启用光照
light[0].tagEnable=1;
//设置材质,启用颜色
material.tagEnable=MainMaterial.tagEnable;
material.ambient=MainMaterial.ambient;
material.diffuse=MainMaterial.diffuse;
material.specular=MainMaterial.specular;
material.shininess=MainMaterial.shininess;
//启用着色器并进行渲染
tempShader->UseShader();
//显示网格
MainMesh.DrawMesh(hWnd,hDC,tempShader);
}
5、Mesh Component 的使用场景
Mesh Component 广泛应用于游戏开发、虚拟现实和增强现实领域。在游戏中,它用于构建场景和道具的3D模型。在工业设计中,Mesh Component 用于可视化产品原型和模拟物理行为。这里我们初步决定,mesh component一般不用于人物模型的加载,游戏里的人物模型,我们一般会用model类加载(后期会讲到),因为model类里头经常会用到骨骼动画,而一般mesh component是不需要骨骼动画的。
那么我们今后在使用网格时,可以这样处理,首先要强调,必须是game object及其派生类才能拥有组件。其次,网格组件不是GameObject的默认组件,如果使用需要自己添加组件,说下面这个例子中我们有一个Game object的指针,指向一个实例物体。那么我们可以用创建动态组件的方式添加网格(分添加动态组件的函数,我们在此前的章节中讲过),如果添加成功的情况下,就可以用网格的加载函数给这个组件加载网格模型。
cpp
//添加网格组件
MeshComponent *ptComponent=ptGameObject->AddDynamicComponent<MeshComponent>();
//设置网格组件
if(ptComponent!=NULL)
{
//采用曲面加载器进行加载
ptGameObject->GetMeshFromObjFile(&ptComponent->MainMesh,"Model\\MeshCube\\MeshCube.obj");
}
然后我们在加载的时候也可以指定模型的纹理,也就在最后一句模型加载GetMeshFromObjFile函数上,加上纹理图片就可以Model\MeshCube\box.png的路径参数即可。
cpp
//添加网格组件
MeshComponent *ptComponent=ptGameObject->AddDynamicComponent<MeshComponent>();
//设置网格组件
if(ptComponent!=NULL)
{
//采用曲面加载器进行加载
ptGameObject->GetMeshFromObjFile(&ptComponent->MainMesh,"Model\\MeshCube\shCube.obj","Model\\MeshCube\\box.png");
}
5、Mesh Component 的优化技巧
为了提升性能,可以尽量减少Mesh Component的顶点数量和绘制调用。后期我们可以考虑使用LOD(Level of Detail)技术动态调整模型的细节级别,合并多个Mesh Component以减少批处理开销,并利用GPU实例化渲染大量相似物体,这些都是很好的进行优化的技巧。
6、源码下载
这里我们已经将上面视频的源码上传到附件中(就是该篇文章的绑定资源),方便大家下载。呃,这里我们采用visual studio 2010编译器,打开文件夹中的world.sln就可以打开这个工程文件,由于我们这里提前配置好了相关库,因此,下载后无需再次配置点击运行,可直接产生exe文件并运行。我在运行源码中有任何问题可以留言,以便帮你解决运行问题。
源码下载
C++和OpenGL实现3D游戏编程【连载29】------添加MeshComponent组件(显示物体网格模型)附源码