APP下载

基于OpenGL的三维模型读取与动态观察

2018-02-05张肇同

科技视界 2017年34期

张肇同

【摘 要】在机器人仿真软件开发、三维视景建模等领域,通常需要读取三维建模,这些模型大都由专业的三维建模软件生成,具有特定的文件格式。本文基于OpenGL,对此过程中的模型导入与动态观察部分进行研究。在VS2017环境下,通过OpenGL与Assimp实现三维模型数据文件的可视化,使人们可以获取到模型特定数据,并可直观地看到模型,为其余工作奠定基础。

【关键词】OpenGL;Assimp;模型可视化;动态观察

0 引言

目前,许多优秀的三维建模软件如CATIA、UG、Pro/E等,可以方便地建立各种复杂物体模型,但除了软件所给出的功能外,很难对模型进行控制和操作[1]。OpenGL则更容易实现模型的变换、纹理、交互操作等,但是却没有提供CATIA、UG等建模软件中用于建立复杂三维模型的高级命令,只提供了基本的集合图元(如点、线、多边形)的绘制命令[2]。因此,若能将三维建模软件输出的模型文件,在OpenGL中进行“加工”,可以更好地解決实际问题。

1 模型读取与绘制方法

考虑到各平台文件格式不同,为了增强通用性,我们选择通过Assimp库辅助模型读取工作,这样可读入十余种不同格式的主流模型文件,增强了通用性,方便了后续工作。

1.1 Assimp概述

Assimp(Open Asset Import Library)是开源图形库,它会将所有的模型数据加载至Assimp的通用数据结构中[3]。当Assimp加载完模型之后,我们就能够从Assimp的数据结构中提取我们所需的所有数据了。由于Assimp的数据结构保持不变,不论导入的是什么种类的文件格式,它都能够将模型数据从这些不同文件格式中抽象出来,用同一种方式访问所需数据。

当使用Assimp导入一个模型的时候,它通常会将整个模型加载进一个场景对象,它会包含导入的模型中的所有数据。Assimp会将场景载入为一系列的节点,每个节点包含了场景对象中所储存数据的索引,每个节点都可以由任意数量的子节点。

一个网格对象本身包含了渲染所需要的所有相关数据,如顶点、法向量、纹理坐标、面和材质等。一个网格包含了多个面,一个面包含了组成图元的顶点索引。由于顶点数据和顶点索引是分开的,使用一个索引缓冲来渲染是非常方便的。

1.2 场景绘制方式

现在,我们可以根据场景的结构,读取场景对象中的数据并绘制模型。为了更加系统的进行场景绘制,我们构建了Model类与Mesh类,分别对应于模型结构与网格结构:

class Model{

public:

Model(char* path){ };

void Draw(Shader shader);

private:

vectormeshes;

void loadModel( string path);

void processNode(aiNode* node, const aiScene* scene);

Mesh processMesh( aiMesh* mesh, const aiScene* scene);

};

class Mesh{

public:

vectorvertices;

vectorindices;

GLuint VAO;

Mesh(vectorvertices, vectorindices, vector textures);

void Draw(Shader shader);

private:

GLuint VBO, EBO;

void setupMesh();

};

1.2.1 模型读取

首先,读取给定路径的模型文件并加载到Scene对象。除了加载文件之外,我们还可以设定一些选项强制性对导入的数据做一些额外的计算或操作。

1.2.2 处理模型节点

我们首先检查每个节点的网格索引,并索引场景的mMeshes数组来获取对应的网格。返回的网格将会传递到processMesh函数中,它会返回一个Mesh类对象,我们可以将他存储在meshes数组中。当所有网格都被处理后,我们会遍历节点的所有子节点,并对子节点中的网格传递到processMesh函数中,不断递归下去直到节点中不再存在子节点为止。

1.2.3 处理模型网格

网格传递到processMesh函数后,开始对网格进行处理。处理网格的过程主要分为两步:获取所有的定点数据;获取他们的顶点索引。处理后的数据将会存储在两个vector当中,我们会使用他们构建一个Mesh类对象,作为processMesh函数的返回值。

为了获取顶点数据,我们首先定义一个Vertex结构:

struct Vertex

{

glm::vec3 Position;

glm::vec3 Normal;

};

我们将在每个迭代之后将它加到vectorvertices数组中。我们会遍历网格中的所有顶点(使用mesh->mNumVertices来获取),并获得每个顶点的位置、法向量等。

Assimp的接口定义了每个网格都有一个面(Face)数组,一个面包含了多个索引,他们定义了在每个图元中我们应该绘制哪个顶点,并以什么顺序绘制。因此,我们遍历了所有的面(使用mesh->mNumFaces来获取),并存储了面的索引到vectorindices中,完成面包含索引的读取。由此,我们遍历了所有节点中的网格,读取了绘制模型所需要的数据。

1.2.4 绘制网格

现在,我们有一大列用于渲染的网格数据。将这些数据按照OpenGL渲染的标准步骤,配置正确的缓冲,并通过顶点属性指针定义顶点着色器的布局等,这些设置都集中在mesh类的成员函数setupMesh()中。

初始化Model类对象,并调用其成员函数Draw(Shader shader),此函数将遍历类对象的meshes数组,并调用Mesh类的成员函数Draw(Shader shader),根据顶点数组对象所绑定缓冲中的数据,绘制模型。

2 实验结果

根据前文所述内容,在Visual Studio2017平台实现了对模型文件的读取、显示与三维漫游功能。为了验证系统显示三维模型的实际效果,选用了CATIA中STL格式的模型文件,下面为得到的三维模型。

3 结语

对模型文件的读取与显示,是对模型一切后续操作的前提和基础。本文通过对OpenGL与模型文件的研究,以Visual Studio2017作为开发平台,利用Assimp库读取模型文件数据,并通过OpenGL显示出了模型,今后,可将这种方法应用于机器人仿真软件开发、三维视景建模等领域。

【参考文献】

[1]张代聪.基于OpenGL的交互式PLC虚拟仿真系统[D].山东大学,2012.

[2]Richard S.Wright, Jr.OpenGL超级宝典[M].北京:人民邮电出版社,2012.

[3]肖健,魏雄,王仁波.基于 OpenGL 的大型建筑三维场景模拟的实现与意义[J].电子质量,2016(11):88-92.