织梦CMS - 轻松建站从此开始!

罗索

OpenGL读取3DS模型(Qt版)

落鹤生 发布于 2012-06-07 09:49 点击:次 
对于3DS格式,相比OBJ的话,其多了光照、贴图、材质等信息,但如果是工业标准,并且对于贴图和材质没有特别的要求的话,使用代码给每个不同物体写上一个单一颜色就好了。这样速度很快,速度是很重要的因素啊。
TAG:

OpenGL一个重要应用就是能够读取外部的3D模型文件,比如OBJ,MD2,MD3,3DS等。在我之前的日志里已经写过一篇关于OpenGL读取Obj格式的类,详情可以看“Qt下学习OpenGL之OBJ模型”。而这次我要介绍的是3DS文件的读取。

接下来要贴出的代码已经在Qt4下成功运行,不过里面需要依赖一个CBMPLoader的类,这个可以从《OpenGL游戏编程》这本书里看到,也可以在我博客里找到对应的代码。

最后,还补充一下个人的看法。对于3DS格式,相比OBJ的话,其多了光照、贴图、材质等信息,但如果是工业标准,并且对于贴图和材质没有特别的要求的话,使用代码给每个不同物体写上一个单一颜色就好了。这样速度很快,速度是很重要的因素啊。

好了,贴代码了。
3DSLoader.h内容:

  1. #ifndef __3DSLOADER_H__ 
  2. #define __3DSLOADER_H__ 
  3.  
  4. #include "Stdafx.h" 
  5. #include "Vector.h" 
  6. #include "CBMPLoader.h" 
  7.  
  8. /* 下面是定义一些块的ID号 */ 
  9.  
  10. /*  基本块(Primary Chunk),位于文件的开始 */ 
  11. #define PRIMARY       0x4D4D 
  12.  
  13. /*  主块(Main Chunks) */ 
  14. #define OBJECTINFO    0x3D3D        /* 网格对象的版本号 */ 
  15. #define VERSION       0x0002        /* .3ds文件的版本 */ 
  16. #define EDITKEYFRAME  0xB000        /* 所有关键帧信息的头部 */ 
  17.  
  18. /*  对象的次级定义 */ 
  19. #define MATERIAL      0xAFFF        /* 纹理信息 */ 
  20. #define OBJECT        0x4000        /* 对象的面、顶点等信息 */ 
  21.  
  22. /*  材质的次级定义 */ 
  23. #define MATNAME       0xA000        /* 材质名称 */ 
  24. #define MATDIFFUSE    0xA020        /* 对象/材质的颜色 */ 
  25. #define MATMAP        0xA200        /* 新材质的头部 */ 
  26. #define MATMAPFILE    0xA300        /* 保存纹理的文件名 */ 
  27. #define OBJ_MESH      0x4100            /* 新的网格对象 */ 
  28.  
  29. /* 网格对象的次级定义 */ 
  30. #define OBJ_VERTICES  0x4110        /* 对象顶点 */ 
  31. #define OBJ_FACES     0x4120        /* 对象的面 */ 
  32. #define OBJ_MATERIAL  0x4130        /* 对象的材质 */ 
  33. #define OBJ_UV        0x4140        /* 对象的UV纹理坐标 */ 
  34.  
  35. /* 面的结构定义 */ 
  36. struct tFace 
  37.         int vertIndex[3];       /* 顶点索引 */ 
  38.         int coordIndex[3];      /* 纹理坐标索引 */ 
  39. }; 
  40.  
  41. /* 材质信息结构体 */ 
  42. struct tMatInfo 
  43.         char  strName[255];     /* 纹理名称 */ 
  44.         char  strFile[255];     /* 纹理文件名称 */ 
  45.         unsigned char  color[3];    /* 对象的RGB颜色 */ 
  46.         int   texureId;         /* 纹理ID */ 
  47.         float uTile;            /* u 重复 */ 
  48.         float vTile;            /* v 重复 */ 
  49.         float uOffset;          /* u 纹理偏移 */ 
  50.         float vOffset;          /* v 纹理偏移 */ 
  51. } ; 
  52.  
  53. /* 对象信息结构体 */ 
  54. struct t3DObject 
  55.         int  numOfVerts;        /* 模型中顶点的数目 */ 
  56.         int  numOfFaces;        /* 模型中面的数目 */ 
  57.         int  numTexVertex;      /* 模型中纹理坐标的数目 */ 
  58.         int  materialID;        /* 纹理ID */ 
  59.         bool bHasTexture;       /* 是否具有纹理映射 */ 
  60.         char strName[255];      /* 对象的名称 */ 
  61.         Vector3  *pVerts;       /* 对象的顶点 */ 
  62.         Vector3  *pNormals;     /* 对象的法向量 */ 
  63.         Vector2  *pTexVerts;        /* 纹理UV坐标 */ 
  64.         tFace *pFaces;          /* 对象的面信息 */ 
  65. }; 
  66.  
  67. /* 模型信息结构体 */ 
  68. struct t3DModel 
  69. {   int numOfObjects;       /* 模型中对象的数目 */ 
  70.         int numOfMaterials;     /* 模型中材质的数目 */ 
  71.         QVectorpMaterials;  /* 材质链表信息 */ 
  72.         QVector pObject;    /* 模型中对象链表信息 */ 
  73. }; 
  74.  
  75. /* 块信息的结构 */ 
  76. struct tChunk 
  77.         unsigned short int ID;       /* 块的ID */ 
  78.         unsigned int length;         /* 块的长度 */ 
  79.         unsigned int bytesRead;      /* 需要读的块数据的字节数 */ 
  80. }; 
  81.  
  82. #define MAX_TEXTURES  100 
  83.  
  84. /* 3DS文件载入类 */ 
  85. class C3DSLoader 
  86. public
  87.         /* 构造函数 */ 
  88.         C3DSLoader(); 
  89.         virtual ~C3DSLoader(); 
  90.         void Draw();//显示3ds模型 
  91.         void Init(char *filename); 
  92.  
  93. private
  94.         /* 读一个字符串 */ 
  95.         int  GetString(char *); 
  96.  
  97.         /* 装载3ds文件到模型结构中 */ 
  98.         bool Import3DS(t3DModel *pModel, char *strFileName); 
  99.  
  100.         /*  从文件中创建纹理 */ 
  101.         void LoadTexture(char* filename, GLuint textureArray[], GLuint textureID); 
  102.  
  103.         /* 读取一个块 */ 
  104.         void ReadChunk(tChunk *); 
  105.  
  106.         /* 读取下一个块 */ 
  107.         void ReadNextChunk(t3DModel *pModel, tChunk *); 
  108.  
  109.         /* 读取下一个对象 */ 
  110.         void ReadNextObjChunk(t3DModel *pModel,t3DObject *pObject,tChunk *); 
  111.  
  112.         /* 读取下一个材质块 */ 
  113.         void ReadNextMatChunk(t3DModel *pModel, tChunk *); 
  114.  
  115.         /* 读取对象颜色的RGB值 */ 
  116.         void ReadColor(tMatInfo *pMaterial, tChunk *pChunk); 
  117.  
  118.         /* 读取对象的顶点信息 */ 
  119.         void ReadVertices(t3DObject *pObject, tChunk *); 
  120.  
  121.         /* 读取对象的面信息 */ 
  122.         void ReadVertexIndices(t3DObject *pObject,tChunk *); 
  123.  
  124.         /* 读取对象的纹理坐标 */ 
  125.         void ReadUVCoordinates(t3DObject *pObject,tChunk *); 
  126.  
  127.         /* 读取赋予对象的材质 */ 
  128.         void ReadObjMat(t3DModel *pModel,t3DObject *pObject,tChunk *pPreChunk); 
  129.  
  130.         /* 计算对象顶点的法向量 */ 
  131.         void ComputeNormals(t3DModel *pModel); 
  132.  
  133.         /* 释放内存,关闭文件 */ 
  134.         void CleanUp(); 
  135.  
  136.         FILE         *m_FilePointer;              /*< 文件指针 */ 
  137.         tChunk       *m_CurrentChunk;             /*< 读取过程中当前块 */ 
  138.         tChunk       *m_TempChunk;                /*< 临时块 */ 
  139.         GLuint       m_textures[MAX_TEXTURES];    /*< 纹理 */ 
  140.         t3DModel     m_3DModel;                   /*< 模型 */ 
  141.         CBMPLoader   m_BMPTexture;                /* 载入位图 */ 
  142.  
  143. }; 
  144.  
  145. #endif 

3DSLoader.cpp内容:

  1. #include "Stdafx.h" 
  2. #include "3DSLoader.h" 
  3.  
  4. /* 构造函数 */ 
  5. C3DSLoader::C3DSLoader() 
  6.     m_CurrentChunk = new tChunk;     /* 为当前块分配空间 */ 
  7.     m_TempChunk = new tChunk;        /* 为临时块分配空间 */ 
  8.     m_3DModel.numOfObjects = 0; 
  9.     m_3DModel.numOfMaterials = 0; 
  10.     for(int i=0;i0) 
  11. LoadTexture(m_3DModel.pMaterials[i].strFile,m_textures, i);/* 使用纹理文件名称来装入位图 */ 
  12. m_3DModel.pMaterials[i].texureId = i;/* 设置材质的纹理ID */ 
  13.     } 
  14.  
  15. /* 显示3ds模型 */ 
  16. void C3DSLoader::Draw() 
  17.     /*保存现有颜色属实性 */ 
  18.     glPushAttrib(GL_CURRENT_BIT); 
  19.     glDisable(GL_TEXTURE_2D); 
  20.     //glEnable(GL_LIGHT0); 
  21.  
  22.     /* 遍历模型中所有的对象 */ 
  23.     for(int i = 0; i < m_3DModel.numOfObjects; i++) 
  24.     { 
  25.         /* 如果对象的大小小于0,则退出 */ 
  26.         if(m_3DModel.pObject.size() <= 0)
  27.              break;         /* 获得当前显示的对象 */
  28.          t3DObject *pObject = &m_3DModel.pObject[i];
  29.          /* 判断该对象是否有纹理映射 */
  30.          if(pObject->bHasTexture) 
  31.         { 
  32.             glEnable(GL_TEXTURE_2D);/* 打开纹理映射 */ 
  33.             glBindTexture(GL_TEXTURE_2D, m_textures[pObject->materialID]); 
  34.         } 
  35.         else 
  36.             glDisable(GL_TEXTURE_2D);/* 关闭纹理映射 */ 
  37.  
  38.         glColor3ub(255, 255, 255); 
  39.  
  40.         /* 开始绘制 */ 
  41.  
  42.             glBegin(GL_TRIANGLES); 
  43.  
  44.         /* 遍历所有的面 */ 
  45.         for(int j = 0; j < pObject->numOfFaces; j++) 
  46.         { 
  47.             /* 遍历三角形的所有点 */ 
  48.             for(int tex = 0; tex < 3; tex++)
  49.              {
  50. /* 获得面对每个点的索引 */
  51. int index = pObject->pFaces[j].vertIndex[tex]; 
  52.  
  53. /* 给出法向量 */ 
  54. glNormal3f(pObject->pNormals[index].x,pObject->pNormals[index].y, 
  55. pObject->pNormals[index].z); 
  56.  
  57.                 /* 如果对象具有纹理 */ 
  58.                 if(pObject->bHasTexture) 
  59.                 { 
  60.                     /* 确定是否有UVW纹理坐标 */ 
  61.                     if(pObject->pTexVerts) 
  62. glTexCoord2f(pObject->pTexVerts[index].x,pObject->pTexVerts[index].y); 
  63.                 } 
  64.                 else 
  65.                 { 
  66.                     if(m_3DModel.pMaterials.size() && pObject->materialID>= 0) 
  67.                     { 
  68. unsigned char *pColor = m_3DModel.pMaterials[pObject->materialID].color; 
  69. glColor3ub(pColor[0],pColor[1],pColor[2]); 
  70.                     } 
  71.                 } 
  72. glVertex3f(pObject->pVerts[index].x,pObject->pVerts[index].y,pObject->pVerts[index].z); 
  73.             } 
  74.         } 
  75.         glEnd(); 
  76.         /* 绘制结束 */ 
  77.     } 
  78.  
  79.     //glDisable(GL_LIGHT0); 
  80.     glEnable(GL_TEXTURE_2D); 
  81.  
  82.     /* 恢复前一属性 */ 
  83.     glPopAttrib(); 
  84.  
  85. void C3DSLoader::LoadTexture(char* filename, GLuint textureArray[], GLuint textureID) 
  86.     if(!filename) 
  87.         return
  88.  
  89.     if(!this->m_BMPTexture.LoadBitmap(filename)) 
  90.     { 
  91. QMessageBox::warning(0,QObject::tr("Load Bitmap Error"),QObject::tr("Load Bitmap Error")); 
  92.         return
  93.     } 
  94.  
  95.     glGenTextures(1,&m_textures[textureID]); 
  96.  
  97.     glPixelStorei (GL_UNPACK_ALIGNMENT, 1); 
  98.     glBindTexture(GL_TEXTURE_2D, m_textures[textureID]); 
  99.  
  100.     /* 控制滤波 */ 
  101.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); 
  102.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR); 
  103.  
  104.     /* 创建纹理 */ 
  105.     gluBuild2DMipmaps(GL_TEXTURE_2D, 3, m_BMPTexture.imageWidth,m_BMPTexture.imageHeight
  106. , GL_RGB, GL_UNSIGNED_BYTE, this->m_BMPTexture.image); 
  107.  
  108.  
  109. /* 载入3DS文件到模型结构中 */ 
  110. bool C3DSLoader::Import3DS(t3DModel *pModel,char *strFileName) 
  111.     char strMessage[255] = {0}; 
  112.  
  113.     /* 打开一个3ds文件 */ 
  114.     m_FilePointer = fopen(strFileName, "rb"); 
  115.  
  116.     /* 检查文件指针 */ 
  117.     if(!m_FilePointer) 
  118.     { 
  119.         sprintf(strMessage, "Cann't find the file: %s!", strFileName); 
  120.         QMessageBox::information(NULL, 
  121.                                  "Error"
  122.                                  strMessage, 
  123.                                  QMessageBox::Yes | QMessageBox::No, 
  124.                                  QMessageBox::Yes); 
  125.         return false
  126.     } 
  127.  
  128.     /* 将文件的第一块读出并判断是否是3ds文件 */ 
  129.     ReadChunk(m_CurrentChunk); 
  130.  
  131.     /* 确保是3ds文件 */ 
  132.     if (m_CurrentChunk->ID != PRIMARY) 
  133.     { 
  134.         QMessageBox::information(NULL, 
  135.                                  "Error"
  136.                                  "Cann't Loading the Function"
  137.                                  QMessageBox::Yes | QMessageBox::No, 
  138.                                  QMessageBox::Yes); 
  139.         return false
  140.     } 
  141.  
  142.     /* 递归读出对象数据 */ 
  143.     ReadNextChunk(pModel, m_CurrentChunk); 
  144.  
  145.     /* 计算顶点的法线 */ 
  146.     ComputeNormals(pModel); 
  147.  
  148.     /* 释放内存空间 */ 
  149.     CleanUp(); 
  150.  
  151.     return true
  152.  
  153. /*  读入一个字符串 */ 
  154. int C3DSLoader::GetString(char *pBuffer) 
  155.     int index = 0; 
  156.  
  157.     /* 读入一个字节的数据 */ 
  158.     fread(pBuffer, 1, 1, m_FilePointer); 
  159.  
  160.     /* 直到结束 */ 
  161.     while (*(pBuffer + index++) != 0) 
  162.     { 
  163.         /* 读入一个字符直到NULL */ 
  164.         fread(pBuffer + index, 1, 1, m_FilePointer); 
  165.     } 
  166.  
  167.     /* 返回字符串的长度 */ 
  168.     return strlen(pBuffer) + 1; 
  169.  
  170. /* 读入块的ID号和它的字节长度 */ 
  171. void C3DSLoader::ReadChunk(tChunk *pChunk) 
  172.     /* 读入块的ID号 */ 
  173.     pChunk->bytesRead = fread(&pChunk->ID, 1, 2, m_FilePointer); 
  174.  
  175.     /* 读入块占用的长度 */ 
  176.     pChunk->bytesRead += fread(&pChunk->length, 1, 4, m_FilePointer); 
  177.  
  178.  
  179. /* 读出3ds文件的主要部分 */ 
  180. void C3DSLoader::ReadNextChunk(t3DModel *pModel, tChunk *pPreChunk) 
  181.     t3DObject newObject = {0};                  /* 用来添加到对象链表 */ 
  182.     tMatInfo newTexture = {0};                  /* 用来添加到材质链表 */ 
  183.     unsigned int version = 0;                   /* 保存文件版本 */ 
  184.     int buffer[50000] = {0};                    /* 用来跳过不需要的数据 */ 
  185.     m_CurrentChunk = new tChunk;                /* 为新的块分配空间      */ 
  186.  
  187.     /* 继续读入子块 */ 
  188.     while (pPreChunk->bytesRead < pPreChunk->length) 
  189.     { 
  190.         /* 读入下一个块 */ 
  191.         ReadChunk(m_CurrentChunk); 
  192.  
  193.         /* 判断块的ID号 */ 
  194.         switch (m_CurrentChunk->ID) 
  195.         { 
  196.  
  197.             /* 文件版本号 */ 
  198.         case VERSION: 
  199.  
  200.             /* 读入文件的版本号 */ 
  201.             m_CurrentChunk->bytesRead += fread(&version
  202. , 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer); 
  203.  
  204.             /* 如果文件版本号大于3,给出一个警告信息 */ 
  205.             if (version > 0x03) 
  206.                 QMessageBox::information(NULL, 
  207.                                          "Warning"
  208.                                          "The 3DS File Version is wrong"
  209.                                          QMessageBox::Yes | QMessageBox::No, 
  210.                                          QMessageBox::Yes); 
  211.             break
  212.  
  213.             /* 网格版本信息 */ 
  214.         case OBJECTINFO: 
  215.  
  216.             /* 读入下一个块 */ 
  217.             ReadChunk(m_TempChunk); 
  218.  
  219.             /* 获得网格的版本号 */ 
  220.             m_TempChunk->bytesRead += fread(&version, 1
  221. , m_TempChunk->length - m_TempChunk->bytesRead, m_FilePointer); 
  222.  
  223.             /* 增加读入的字节数 */ 
  224.             m_CurrentChunk->bytesRead += m_TempChunk->bytesRead; 
  225.  
  226.             /* 进入下一个块 */ 
  227.             ReadNextChunk(pModel, m_CurrentChunk); 
  228.             break
  229.  
  230.             /* 材质信息 */ 
  231.         case MATERIAL: 
  232.  
  233.             /* 材质的数目递增 */ 
  234.             pModel->numOfMaterials++; 
  235.  
  236.             /* 在纹理链表中添加一个空白纹理结构 */ 
  237.             pModel->pMaterials.push_back(newTexture); 
  238.  
  239.             /* 进入材质装入函数 */ 
  240.             ReadNextMatChunk(pModel, m_CurrentChunk); 
  241.             break
  242.  
  243.             /* 对象名称 */ 
  244.         case OBJECT: 
  245.  
  246.             /* 对象数递增 */ 
  247.             pModel->numOfObjects++; 
  248.  
  249.             /* 添加一个新的tObject节点到对象链表中 */ 
  250.             pModel->pObject.push_back(newObject); 
  251.  
  252.             /* 初始化对象和它的所有数据成员 */ 
  253.             memset(&(pModel->pObject[pModel->numOfObjects - 1])
  254. , 0, sizeof(t3DObject)); 
  255.  
  256.             /* 获得并保存对象的名称,然后增加读入的字节数 */ 
  257.             m_CurrentChunk->bytesRead
  258.  += GetString(pModel->pObject[pModel->numOfObjects - 1].strName); 
  259.  
  260.             /* 进入其余的对象信息的读入 */ 
  261.             ReadNextObjChunk(pModel
  262. , &(pModel->pObject[pModel->numOfObjects - 1]), m_CurrentChunk); 
  263.             break
  264.  
  265.             /* 关键帧 */ 
  266.         case EDITKEYFRAME: 
  267.  
  268.             /* 跳过关键帧块的读入 */ 
  269.             m_CurrentChunk->bytesRead += fread(buffer, 1
  270. , m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer); 
  271.             break
  272.  
  273.         default
  274.             /*  跳过所有忽略的块的内容的读入 */ 
  275.             m_CurrentChunk->bytesRead += fread(buffer, 1
  276. , m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer); 
  277.             break
  278.         } 
  279.  
  280.         /* 增加从最后块读入的字节数 */ 
  281.         pPreChunk->bytesRead += m_CurrentChunk->bytesRead; 
  282.     } 
  283.  
  284.     /* 释放当前块的内存空间 */ 
  285.     delete m_CurrentChunk; 
  286.     m_CurrentChunk = pPreChunk; 
  287.  
  288. /* 处理所有的文件中对象的信息 */ 
  289. void C3DSLoader::ReadNextObjChunk(t3DModel *pModel
  290. , t3DObject *pObject, tChunk *pPreChunk) 
  291.     /* 用于读入不需要的数据 */ 
  292.     int buffer[50000] = {0}; 
  293.  
  294.     /* 对新的块分配存储空间 */ 
  295.     m_CurrentChunk = new tChunk; 
  296.  
  297.     /* 继续读入块的内容直至本子块结束 */ 
  298.     while (pPreChunk->bytesRead < pPreChunk->length) 
  299.     { 
  300.         /* 读入下一个块 */ 
  301.         ReadChunk(m_CurrentChunk); 
  302.  
  303.         /* 区别读入是哪种块 */ 
  304.         switch (m_CurrentChunk->ID) 
  305.         { 
  306.             /* 正读入的是一个新块 */ 
  307.         case OBJ_MESH: 
  308.             /* 使用递归函数调用,处理该新块 */ 
  309.             ReadNextObjChunk(pModel, pObject, m_CurrentChunk); 
  310.             break
  311.  
  312.             /* 读入是对象顶点 */ 
  313.         case OBJ_VERTICES: 
  314.             ReadVertices(pObject, m_CurrentChunk); 
  315.             break
  316.  
  317.             /* 读入的是对象的面 */ 
  318.         case OBJ_FACES: 
  319.             ReadVertexIndices(pObject, m_CurrentChunk); 
  320.             break
  321.  
  322.             /* 读入的是对象的材质名称 */ 
  323.         case OBJ_MATERIAL: 
  324.             /* 读入对象的材质名称 */ 
  325.             ReadObjMat(pModel, pObject, m_CurrentChunk); 
  326.             break
  327.  
  328.             /* 读入对象的UV纹理坐标 */ 
  329.         case OBJ_UV: 
  330.             /* 读入对象的UV纹理坐标 */ 
  331.             ReadUVCoordinates(pObject, m_CurrentChunk); 
  332.             break
  333.  
  334.         default
  335.             /* 略过不需要读入的块 */ 
  336.             m_CurrentChunk->bytesRead += fread(buffer, 1
  337. , m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer); 
  338.             break
  339.         } 
  340.         /* 添加从最后块中读入的字节数到前面的读入的字节中 */ 
  341.         pPreChunk->bytesRead += m_CurrentChunk->bytesRead; 
  342.     } 
  343.     /* 释放当前块的内存空间,并把当前块设置为前面块 */ 
  344.     delete m_CurrentChunk; 
  345.     m_CurrentChunk = pPreChunk; 
  346.  
  347. /* 处理所有的材质信息 */ 
  348. void C3DSLoader::ReadNextMatChunk(t3DModel *pModel, tChunk *pPreChunk) 
  349.     /* 用于读入不需要的数据 */ 
  350.     int buffer[50000] = {0}; 
  351.  
  352.     /* 给当前块分配存储空间 */ 
  353.     m_CurrentChunk = new tChunk; 
  354.  
  355.     /* 继续读入这些块 */ 
  356.     while (pPreChunk->bytesRead < pPreChunk->length) 
  357.     { 
  358.         /* 读入下一块 */ 
  359.         ReadChunk(m_CurrentChunk); 
  360.         /* 判断读入的是什么块 */ 
  361.         switch (m_CurrentChunk->ID) 
  362.         { 
  363.         case MATNAME:                           /* 材质的名称 */ 
  364.             /* 读入材质的名称 */ 
  365.             m_CurrentChunk->bytesRead
  366.  += fread(pModel->pMaterials[pModel->numOfMaterials - 1].strName, 1
  367. , m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer); 
  368.             break
  369.         case MATDIFFUSE:                        /* 对象的R G B颜色 */ 
  370.             ReadColor(&(pModel->pMaterials[pModel->numOfMaterials - 1]), m_CurrentChunk); 
  371.             break
  372.         case MATMAP:                            /* 纹理信息的头部 */ 
  373.             /* 下一个材质块信息 */ 
  374.             ReadNextMatChunk(pModel, m_CurrentChunk); 
  375.             break
  376.         case MATMAPFILE:                        /* 材质文件的名称 */ 
  377.             /* 读入材质的文件名称 */ 
  378.             m_CurrentChunk->bytesRead
  379.  += fread(pModel->pMaterials[pModel->numOfMaterials - 1].strFile, 1
  380. , m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer); 
  381.             break
  382.         default
  383.             /* 跳过不需要读入的块 */ 
  384.             m_CurrentChunk->bytesRead += fread(buffer, 1
  385. , m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer); 
  386.             break
  387.         } 
  388.         /* 添加从最后块中读入的字节数 */ 
  389.         pPreChunk->bytesRead += m_CurrentChunk->bytesRead; 
  390.     } 
  391.     /* 删除当前块,并将当前块设置为前面的块 */ 
  392.     delete m_CurrentChunk; 
  393.     m_CurrentChunk = pPreChunk; 
  394.  
  395. /* 读入RGB颜色 */ 
  396. void C3DSLoader::ReadColor(tMatInfo *pMaterial, tChunk *pChunk) 
  397.     /* 读入颜色块信息 */ 
  398.     ReadChunk(m_TempChunk); 
  399.     /* 读入RGB颜色 */ 
  400.     m_TempChunk->bytesRead += fread(pMaterial->color, 1
  401. , m_TempChunk->length - m_TempChunk->bytesRead, m_FilePointer); 
  402.     /* 增加读入的字节数 */ 
  403.     pChunk->bytesRead += m_TempChunk->bytesRead; 
  404.  
  405. /* 读入顶点索引 */ 
  406. void C3DSLoader::ReadVertexIndices(t3DObject *pObject, tChunk *pPreChunk) 
  407.     unsigned short index = 0;                   /* 用于读入当前面的索引 */ 
  408.     /* 读入该对象中面的数目 */ 
  409.     pPreChunk->bytesRead += fread(&pObject->numOfFaces, 1, 2, m_FilePointer); 
  410.     /* 分配所有面的存储空间,并初始化结构 */ 
  411.     pObject->pFaces = new tFace [pObject->numOfFaces]; 
  412.     memset(pObject->pFaces, 0, sizeof(tFace) * pObject->numOfFaces); 
  413.     /* 遍历对象中所有的面 */ 
  414.     for(int i = 0; i < pObject->numOfFaces; i++) 
  415.     {   for(int j = 0; j < 4; j++)
  416.          {
  417.              /* 读入当前面的第一个点  */
  418.              pPreChunk->bytesRead += fread(&index, 1, sizeof(index), m_FilePointer); 
  419.             if(j < 3)
  420.              {
  421.                  /* 将索引保存在面的结构中 */
  422.                  pObject->pFaces[i].vertIndex[j] = index; 
  423.             } 
  424.         } 
  425.     } 
  426.  
  427. /* 读入对象的UV坐标 */ 
  428. void C3DSLoader::ReadUVCoordinates(t3DObject *pObject, tChunk *pPreChunk) 
  429.     /* 读入UV坐标的数量 */ 
  430.     pPreChunk->bytesRead += fread(&pObject->numTexVertex, 1, 2, m_FilePointer); 
  431.  
  432.     /* 分配保存UV坐标的内存空间 */ 
  433.     pObject->pTexVerts = new Vector2[pObject->numTexVertex]; 
  434.  
  435.     /* 读入纹理坐标 */ 
  436.     pPreChunk->bytesRead += fread(pObject->pTexVerts, 1
  437. , pPreChunk->length - pPreChunk->bytesRead, m_FilePointer); 
  438.  
  439. /*  读入对象的顶点 */ 
  440. void C3DSLoader::ReadVertices(t3DObject *pObject, tChunk *pPreChunk) 
  441.     /* 读入顶点的数目 */ 
  442.     pPreChunk->bytesRead += fread(&(pObject->numOfVerts), 1, 2, m_FilePointer); 
  443.  
  444.     /* 分配顶点的存储空间,然后初始化结构体 */ 
  445.     pObject->pVerts = new Vector3 [pObject->numOfVerts]; 
  446.     memset(pObject->pVerts, 0, sizeof(Vector3) * pObject->numOfVerts); 
  447.  
  448.     /* 读入顶点序列 */ 
  449.     pPreChunk->bytesRead += fread(pObject->pVerts, 1
  450. , pPreChunk->length - pPreChunk->bytesRead, m_FilePointer); 
  451.  
  452.     /* 遍历所有的顶点将Y轴和Z轴交换,然后将Z轴反向 */ 
  453.     for(int i = 0; i < pObject->numOfVerts; i++) 
  454.     { 
  455.         /* 保存Y轴的值 */ 
  456.         float fTempY = pObject->pVerts[i].y; 
  457.         /* 设置Y轴的值等于Z轴的值 */ 
  458.         pObject->pVerts[i].y = pObject->pVerts[i].z; 
  459.         /* 设置Z轴的值等于-Y轴的值  */ 
  460.         pObject->pVerts[i].z = -fTempY; 
  461.     } 
  462.  
  463. /* 读入对象的材质名称 */ 
  464. void C3DSLoader::ReadObjMat(t3DModel *pModel, t3DObject *pObject, tChunk *pPreChunk) 
  465.     char strMaterial[255] = {0};            /* 用来保存对象的材质名称 */ 
  466.     int buffer[50000] = {0};                /* 用来读入不需要的数据 */ 
  467.  
  468.     /* 读入赋予当前对象的材质名称 */ 
  469.     pPreChunk->bytesRead += GetString(strMaterial); 
  470.  
  471.     /* 遍历所有的纹理 */ 
  472.     for(int i = 0; i < pModel->numOfMaterials; i++) 
  473.     { 
  474.         /* 如果读入的纹理与当前的纹理名称匹配 */ 
  475.         if(strcmp(strMaterial, pModel->pMaterials[i].strName) == 0) 
  476.         { 
  477.             /* 设置材质ID */ 
  478.             pObject->materialID = i; 
  479.  
  480.             /* 判断是否是纹理映射 */ 
  481.             if(strlen(pModel->pMaterials[i].strFile) > 0) { 
  482.  
  483.                 /* 设置对象的纹理映射标志 */ 
  484.                 pObject->bHasTexture = true
  485.             } 
  486.             break
  487.         } 
  488.         else 
  489.         { 
  490.             /* 如果该对象没有材质,则设置ID为-1 */ 
  491.             pObject->materialID = -1; 
  492.         } 
  493.     } 
  494.     pPreChunk->bytesRead += fread(buffer, 1
  495. , pPreChunk->length - pPreChunk->bytesRead, m_FilePointer); 
  496.  
  497. /* 计算对象的法向量 */ 
  498. void C3DSLoader::ComputeNormals(t3DModel *pModel) 
  499.     Vector3 vVector1, vVector2, vNormal, vPoly[3]; 
  500.  
  501.     /* 如果模型中没有对象,则返回 */ 
  502.     if(pModel->numOfObjects <= 0) 
  503.         return
  504.  
  505.     /* 遍历模型中所有的对象 */ 
  506.     for(int index = 0; index < pModel->numOfObjects; index++) 
  507.     { 
  508.         /* 获得当前的对象 */ 
  509.         t3DObject *pObject = &(pModel->pObject[index]); 
  510.  
  511.         /* 分配需要的存储空间 */ 
  512.         Vector3 *pNormals       = new Vector3 [pObject->numOfFaces]; 
  513.         Vector3 *pTempNormals   = new Vector3 [pObject->numOfFaces]; 
  514.         pObject->pNormals       = new Vector3 [pObject->numOfVerts]; 
  515.  
  516.         /* 遍历对象的所有面 */ 
  517.         for(int i=0; i < pObject->numOfFaces; i++) 
  518.         {   vPoly[0] = pObject->pVerts[pObject->pFaces[i].vertIndex[0]]; 
  519.             vPoly[1] = pObject->pVerts[pObject->pFaces[i].vertIndex[1]]; 
  520.             vPoly[2] = pObject->pVerts[pObject->pFaces[i].vertIndex[2]]; 
  521.  
  522.             /* 计算面的法向量 */ 
  523.             vVector1 = vPoly[0] - vPoly[2];             /* 获得多边形的矢量 */ 
  524.             vVector2 = vPoly[2] - vPoly[1];             /* 获得多边形的第二个矢量 */ 
  525.             vNormal  = vVector1.crossProduct(vVector2); /* 计算两个矢量的叉积 */ 
  526.             pTempNormals[i] = vNormal; 
  527.             vNormal  = vNormal.normalize();             /* 规一化叉积 */ 
  528.             pNormals[i] = vNormal;                      /* 将法向量添加到法向量列表中 */ 
  529.         } 
  530.  
  531.         /* 计算顶点法向量 */ 
  532.         Vector3 vSum(0.0,0.0,0.0); 
  533.         Vector3 vZero = vSum; 
  534.         int shared=0; 
  535.  
  536.         /* 遍历所有的顶点 */ 
  537.         for (int i = 0; i < pObject->numOfVerts; i++) 
  538.         {   for (int j = 0; j < pObject->numOfFaces; j++)   /* 遍历所有的三角形面 */ 
  539.             {                                               /* 判断该点是否与其它的面共享 */ 
  540.                 if (pObject->pFaces[j].vertIndex[0] == i || 
  541.                     pObject->pFaces[j].vertIndex[1] == i || 
  542.                     pObject->pFaces[j].vertIndex[2] == i) 
  543.                 { 
  544.                     vSum = vSum + pTempNormals[j]; 
  545.                     shared++; 
  546.                 } 
  547.             } 
  548.             pObject->pNormals[i] = vSum / float(-shared); 
  549.  
  550.             /* 规一化顶点法向 */ 
  551.             pObject->pNormals[i] = pObject->pNormals[i].normalize(); 
  552.             vSum = vZero; 
  553.             shared = 0; 
  554.         } 
  555.         /* 释放存储空间,开始下一个对象 */ 
  556.         delete [] pTempNormals; 
  557.         delete [] pNormals; 
  558.     } 

使用方法:

  1. //使用很简单,声明对象 
  2.   C3DSLoader m_3DS; 
  3. //初始化 
  4. m_3DS.Init("d:\plane.3ds"); 
  5. //绘制模型 
  6. m_3DS.Draw(); 

附上贴图:

 

(民警小刘)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201206/16070.html]
本文出处:liusir 作者:民警小刘 原文
顶一下
(5)
35.7%
踩一下
(9)
64.3%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容