文章来源:http://www.zwqxin.com/archives/opengl/3ds-cload3ds-view-2.html
CLoad3DS类是Sourceforge中的一个开源项目,作用在于帮助开发者学会简单的对3DS文件的载入(OpenGL)程序。虽然有更成熟更强大的3dslib库,但是平时写写Demo中,对模型载入的要求一般比较低,这时候只把CLoad3DS类包含到程序就够了。——ZwqXin.com 本文承接上篇文章:一个读取3DS文件的类CLoad3DS浅析Ⅰ 。
本文来源于 ZwqXin (http://www.zwqxin.com/),
上文提到,PRocessNextChunk(&Model3DS, m_CurrentChunk)这个函数做了模型载入部分最重要的东西。
// 下面的函数读出3ds文件的主要部分//注意传入的后一个参数是刚被ReadChunk过的m_CurrentChunk,也就是说它从0x4D4D块(树干)后开始继续处理,并把0x4D4D块作为pPreviousChunk(前一个块)//处理树结构的常用手法就是递归void CLoad3DS::ProcessNextChunk(t3DModel *pModel, tChunk *pPreviousChunk){ .......... m_CurrentChunk = new tChunk; // 为新的块分配空间 //因为父块的length是子块length总和,而又由0x4D4D块开始,故这个while会遍历整个3DS文件数据 //然后我们在“case OBJECTINFO”中找到了递归,因为OBJECTINFO(0x3D3D,3D editor chunk)就是父块0x4D4D的最直接子块,这次递归中的ProcessNextChunk函数中,while中的pPreviousChunk是递归前(上一层)的m_CurrentChunk,因此switch中寻觅的将是上一层所进入的这个OBJECTINFO块下的子块(找到MATERIAL或OBJECT来处理直至该OBJECTINFO的递归完结,回来继续0x4D4D下的寻觅)。 //总觉得说着说着自己也蒙蒙的(这就是递归!),事实上EDITKEYFRAME跟OBJECTINFO是同级的,不过我们本来就没用到EDITKEYFRAME这种块,故遇到它只是略过(单纯用它所“拥有”的length来增加0x4D4D的bytesRead)//总之呢,你打开某杀毒软件从“我的电脑”开始杀一次毒,观察一下查杀顺序能加深理解恩 while (pPreviousChunk->bytesRead < pPreviousChunk->length) { ReadChunk(m_CurrentChunk);// 读入下一个块 switch (m_CurrentChunk->ID) { case VERSION: ... // 文件版本号 break; case OBJECTINFO: .... // 网格对象信息(3D editor chunk) ProcessNextChunk(pModel, m_CurrentChunk);//!!! break; case MATERIAL: .... // 材质信息 break; case OBJECT: .... // 对象的名称 break; case EDITKEYFRAME: ..... break; default: // 跳过所有忽略的块的内容的读入,增加需要读入的字节数 m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer); break; } // 增加从最后块读入的字节数 pPreviousChunk->bytesRead += m_CurrentChunk->bytesRead; } // 释放当前块的内存空间 delete m_CurrentChunk; m_CurrentChunk = pPreviousChunk;}case语句中的处理函数随chunk的ID(种类)不同而不同,但这些处理函数多少也是递归函数。分配存储空间后,从文件读入后存入相应的数据结构中,并增加该chunk的bytesRead。最需要注意的是,一般由3DS MAX导出的3ds文件的模型坐标跟OPENGL中不同,在读入顶点时要处理(swap)一下。
// 读下一个块 void ProcessNextChunk(t3DModel *pModel, tChunk *); // 读下一个对象块 void ProcessNextObjectChunk(t3DModel *pModel, t3DObject *pObject, tChunk *); // 读下一个材质块 void ProcessNextMaterialChunk(t3DModel *pModel, tChunk *); // 读对象颜色的RGB值 void ReadColorChunk(tMaterialInfo *pMaterial, tChunk *pChunk); // 读对象的顶点 void ReadVertices(t3DObject *pObject, tChunk *); // 读对象的面信息 void ReadVertexIndices(t3DObject *pObject, tChunk *); // 读对象的纹理坐标 void ReadUVCoordinates(t3DObject *pObject, tChunk *); // 读赋予对象的材质名称 void ReadObjectMaterial(t3DModel *pModel, t3DObject *pObject, tChunk *pPreviousChunk);另外还有读入字符串,各种向量等通用计算函数等等,就不介绍了。在ImportModel的第4步中,要计算顶点法向量(把以该点为顶点的各个面的法向量取均值),貌似3DS文件中没有保存法向量信息的chunk吧。因此这里导入的模型要重新(粗略地)计算面和顶点法向量。最后是DrawModel绘制模型(集齐了顶点,纹理或材质[难道有了纹理就不能用材质吗,汗一个],顶点法向量,用三角面片方式按索引绘制),并在RenderModel中调用并作移转缩等处理。总结一下:CLoad3DS类最核心的就是递归思想,以及它与3DS文件树型结构的对应。 CLoad3DS类下载:点此。
本文来源于 ZwqXin (http://www.zwqxin.com/),
新闻热点
疑难解答