《OGL dev》Etay Meiri Tutorial 22 - Loading models using the Open Asset Import Library 笔记
Open Asset Import Library,简称Assimp,地址:http://www.assimp.org/,是一个开源的C/C++模型加载库,支持的模型格式很多,包含大部分主流格式。并且Assimp是跨平台的。
Assimp通过Assimp::Importer对象的ReadFile方法加载模型,返回一个aiScene对象,代表加载的模型。
ReadFile方法提供多个可选参数,对加载的模型进行处理,支持多选:
- aiProcess_Triangulate,将非三角形的mesh,转换为三角形的mesh。例如一个quad可以转换为两个三角形。
- aiProcess_GenSmoothNormals,如果模型不包含法线,生成顶点法线。
- aiProcess_FlipUVsv,沿Y轴翻转纹理坐标。
- aiProcess_JoinIdenticalVertices - 为每个顶点创建一个副本,在需要时,从多个索引引用它。有助于节省内存。
一个aiScene对象至少包含1个aiMesh对象,可以包含多个。mNumMeshes属性描述aiMesh对象的个数。一个aiMesh对象是一个mesh structure。
aiMesh对象的属性如下:
- mMaterialIndex,材质索引,指aiScene对象包含的材质的索引,aiMesh对象可以共享同一材质。
- mNumVertices,顶点数。
- mVertices,顶点,aiVector3D类型的数组。
- mNormals,法线,aiVector3D类型的数组。
- mTextureCoords,纹理坐标,aiVector3D*类型的二维数组。一个顶点可以包含零或一或多组纹理坐标。使用纹理坐标之前,需要先使用HasTextureCoords()函数进行检查。虽然纹理坐标类型为aiVector3D,但只有x、y分量是有效的,z无效。
- mNumVertices,顶点索引数。
- mFaces,顶点索引,aiFace类型数组。每一个aiFace对象是一个unsigned int数组,数组的长度取决于多边形的顶点数。aiFace对象的mNumIndices属性,描述多边形的顶点数。
一个aiScene可以包含多个aiMaterial对象,mNumMaterials属性描述aiMaterial对象的个数。一个aiMaterial对象是一个材质。
aiMaterial对象除了包含纹理以外,还包含blend和strength函数,blend用于混合颜色,strength指定颜色的强度。但本节教程中不使用。
一个aiMaterial对象可以包含多种类型的纹理,比如diffuse texture、height map、 normal map、displacement map等。之前教程中使用的都是diffuse texture。
一个aiMaterial对象每种类型的纹理也可以包含多个,GetTextureCount()函数可以获取指定类型纹理的数量,如GetTextureCount(aiTextureType_DIFFUSE)
获取diffuse texture的数量。
aiMaterial对象的GetTexture(aiTextureType_DIFFUSE, 0, &Path, NULL, NULL, NULL, NULL, NULL)
函数,获取第一张diffuse texture的名称。
- 第二个参数0表示纹理的索引为0,即第一张。
- 第三个参数&Path是aiString类型对象,用于接收纹理名称,Path.data是char数组。
- 之后五个NULL参数,是blend因子、映射模式、纹理操作等,暂时不需要关心。
代码中之所以在找不到纹理文件时,使用一张单个texel的纯白纹理,是为了解决当纹理文件不存在时,采样结果为黑色,导致看不到模型的问题。也存在其他的解决方法,比如在shader中特殊处理,或使用专用的shader。
depth test,深度测试,也称为Z-test。OpenGL默认不开启深度测试。这种情况下,离摄影机远的三角形可能绘制在近的三角形之上,导致视觉异常。开启深度测试的方法如下:
glEnable(GL_DEPTH_TEST);
,启用深度测试。glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH);
,启用depth buffer,或称为Z buffer。glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
,清空depth buffer。每个渲染帧之前都必须清空depth buffer。- 经测试,不清空depth buffer的结果是什么也看不到,推测depth buffer默认值为0。