讀取自定義模型文件,繪製模型

利用OpenGL進行模型表現

轉自http://blog.csdn.net/zhangci226/article/details/5060634

 

這篇文章介紹一下用OpenGL來表現模型對象。比如用3DMAX等工具做好一個模型後,我們希望能夠在自己的程序中使用它。一般使用這些工具的導出功能導出特定的文件,然後讀取其中我們感興趣的部分,再把這些感興趣的數據在我們的程序中組織好就可以了。利用OpenGL來表現靜態模型是很簡單的。

 

這裏爲了簡單起見,模型對象文件爲txt文本,只包含了模型的頂點個數,面個數,頂點座標,索引信息。當然在一些複雜的模型文件中,還包括法線,貼圖座標等等信息。重要的問題是,如果組織這些信息。

 

 

219483
435667
3.031209 1.875606 1.422974
3.030240 1.863352 1.404835
3.030240 1.863352 1.404835
3.021032 1.846390 1.404004
3.021032 1.846390 1.404004
3.050020 1.888645 1.389481
3.040140 1.883706 1.400404

.

.

.

2869 2977 2973
2973 2974 2869
2979 2978 2975
2980 2979 2976
2976 2979 2975
2982 3104 3101
3096 2983 2982
3094 2984 3096
2984 2983 3096
3094 2972 2984
2979 2873 2978
2979 2980 2988

.

.

.

 

如上面的信息一樣,第一行數據爲該模型的頂點個數,第二行數據爲該模型的三角形面個數。後面的數據分別人頂點座標和每一個面的頂點索引信息。很自然的,首先可以想到要在程序中表現該模型,需要vertex的數據類型,於是可以定義這樣的結構體,可以包含頂點的座標和法線信息。

  1. struct Vertex  
  2. {  
  3.     double P[3];  
  4.     double N[3];  
  5. };  

這裏的頂點結構包含了頂點座標P和法線N。

 

然後就是面的數據類型

  1. struct Face  
  2. {  
  3.     int Idx[3];  
  4. };  

一個面由3個頂點構成,只要有了頂點的索引就可以了。

 

最後就是模型的數據類型了

  1. struct Model  
  2. {  
  3.     int vNum;  
  4.     int fNum;  
  5.     Vertex *VertList;  
  6.     Face *FaceList;  
  7. };  

 

這個數據類型包含了模型頂點數vNum,面數fNum,指向頂點列表的指針VertList和指向面列表的指針FaceList。

然後這樣只要用Model來定義一個模型就可以了

 

Model MyModel;

 

下面來看看如果從文件中讀取信息。可以把讀取文件的部分寫成一個函數,比如叫LoadModel,函數的參數只需要提供文件名就可以了。

 

  1. void LoadModel(char *fname)  
  2. {  
  3.     FILE *fp;  
  4.     fp = fopen(fname, "r");  
  5.   
  6.     fscanf(fp, "%d", &MyModel.vNum);  
  7.     fscanf(fp, "%d", &MyModel.fNum);  
  8.   
  9.     MyModel.VertList = new Vertex [MyModel.vNum];  
  10.     MyModel.FaceList = new Face [MyModel.fNum];  
  11.   
  12.     int vNum = MyModel.vNum;  
  13.     int fNum = MyModel.fNum;  
  14.   
  15.     for (int i = 0; i < vNum; ++i)  
  16.     {  
  17.         double x, y, z;  
  18.         fscanf(fp, "%lf %lf %lf", &x, &y, &z);  
  19.         MyModel.VertList[i].P[0] = x;  
  20.         MyModel.VertList[i].P[1] = y;  
  21.         MyModel.VertList[i].P[2] = z;  
  22.   
  23.         MyModel.VertList[i].N[0] = 0.0;  
  24.         MyModel.VertList[i].N[1] = 0.0;  
  25.         MyModel.VertList[i].N[2] = 0.0;  
  26.   
  27.     }  
  28.   
  29.     for (int i = 0; i < fNum; ++i)  
  30.     {  
  31.         int idx0, idx1, idx2;  
  32.         fscanf(fp, "%d %d %d", &idx0, &idx1, &idx2);  
  33.         MyModel.FaceList[i].Idx[0] = idx0;  
  34.         MyModel.FaceList[i].Idx[1] = idx1;  
  35.         MyModel.FaceList[i].Idx[2] = idx2;  
  36.   
  37.         double x0, y0, z0;  
  38.         double x1, y1, z1;  
  39.         double x2, y2, z2;  
  40.   
  41.         x0 = MyModel.VertList[idx0].P[0];  
  42.         y0 = MyModel.VertList[idx0].P[1];  
  43.         z0 = MyModel.VertList[idx0].P[2];  
  44.   
  45.         x1 = MyModel.VertList[idx1].P[0];  
  46.         y1 = MyModel.VertList[idx1].P[1];  
  47.         z1 = MyModel.VertList[idx1].P[2];  
  48.   
  49.         x2 = MyModel.VertList[idx2].P[0];  
  50.         y2 = MyModel.VertList[idx2].P[1];  
  51.         z2 = MyModel.VertList[idx2].P[2];  
  52.   
  53.         double ax, ay, az;  
  54.         double bx, by, bz;  
  55.         double nx, ny, nz;  
  56.         ax = x1 - x0;  
  57.         ay = y1 - y0;  
  58.         az = z1 - z0;  
  59.   
  60.         bx = x2 - x0;  
  61.         by = y2 - y0;  
  62.         bz = z2 - z0;  
  63.   
  64.         nx = ay * bz - az * by;  
  65.         ny = az * bx - ax * bz;  
  66.         nz = ax * by - ay * bx;  
  67.   
  68.         MyModel.VertList[idx0].N[0] += nx;  
  69.         MyModel.VertList[idx0].N[1] += ny;  
  70.         MyModel.VertList[idx0].N[2] += nz;  
  71.   
  72.         MyModel.VertList[idx1].N[0] += nx;  
  73.         MyModel.VertList[idx1].N[1] += ny;  
  74.         MyModel.VertList[idx1].N[2] += nz;  
  75.   
  76.         MyModel.VertList[idx2].N[0] += nx;  
  77.         MyModel.VertList[idx2].N[1] += ny;  
  78.         MyModel.VertList[idx2].N[2] += nz;  
  79.     }  
  80.   
  81.     for (int i = 0; i < vNum; ++i)  
  82.     {  
  83.         double nx, ny, nz;  
  84.         nx = MyModel.VertList[i].N[0];  
  85.         ny = MyModel.VertList[i].N[1];  
  86.         nz = MyModel.VertList[i].N[2];  
  87.   
  88.         double norm = sqrt(nx * nx + ny * ny + nz * nz);  
  89.   
  90.         MyModel.VertList[i].N[0] /= norm;  
  91.         MyModel.VertList[i].N[1] /= norm;  
  92.         MyModel.VertList[i].N[2] /= norm;  
  93.     }  
  94.   
  95.   
  96. }  

上面的代碼比較長,但是內容很簡單。首先打開文件,然後分別以整型的方式讀取頂點個數和麪個數,保存在結構體變量中。然後爲頂點列表和麪列表動態申請內存空間,在循環中分別讀取每個數據。由於頂點包括法線信息,所以這裏還進行了法線的計算。這裏採用平均法線,即把一個頂點的多個法線加在一起,然後再進行單位化。由於一個頂點可能被用於多個面,所以該頂點的法線就是所有面的面法線的和。然後在程序初始化的時候,我們就可以調用這個函數來進行對模型的初始化。

 

最後就是裏利用OpenGL來渲染模型了。有了上面的所有信息,要渲染模型就很簡單了。我們只用利用畫三角形的方法就可以了。

 

  1. glBegin(GL_TRIANGLES);  
  2.     for (int i = 0; i < MyModel.fNum; ++i)  
  3.     {  
  4.         int idx0, idx1, idx2;  
  5.         idx0 = MyModel.FaceList[i].Idx[0];  
  6.         idx1 = MyModel.FaceList[i].Idx[1];  
  7.         idx2 = MyModel.FaceList[i].Idx[2];  
  8.   
  9.         glNormal3dv(MyModel.VertList[idx0].N);  
  10.         glVertex3dv(MyModel.VertList[idx0].P);  
  11.   
  12.         glNormal3dv(MyModel.VertList[idx1].N);  
  13.         glVertex3dv(MyModel.VertList[idx1].P);  
  14.   
  15.         glNormal3dv(MyModel.VertList[idx2].N);  
  16.         glVertex3dv(MyModel.VertList[idx2].P);  
  17.     }  
  18.     glEnd();  

 

可以看到,渲染部分很簡單,就是在循環中依次訪問面列表中每個面。並且給出每個面每個頂點的法線。

 

 

dragon

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章