【摘录】读取MD2模型文件源码

 

  1  /// MD2.H //
  2  #ifndef _MD2_H 
  3  #define  _MD2_H 
  4   
  5  //  These are the needed defines for the max values when loading .MD2 files 
  6  #define  MD2_MAX_TRIANGLES        4096 
  7  #define  MD2_MAX_VERTICES        2048 
  8  #define  MD2_MAX_TEXCOORDS        2048 
  9  #define  MD2_MAX_FRAMES            512 
 10  #define  MD2_MAX_SKINS            32 
 11  #define  MD2_MAX_FRAMESIZE        (MD2_MAX_VERTICES * 4 + 128) 
 12   
 13  //  This holds the header information that is read in at the beginning of the file 
 14  struct  tMd2Header 
 15  {  
 16      int  magic;                     //  This is used to identify the file 
 17      int  version;                     //  The version number of the file (Must be 8) 
 18      int  skinWidth;                 //  The skin width in pixels 
 19      int  skinHeight;                 //  The skin height in pixels 
 20      int  frameSize;                 //  The size in bytes the frames are 
 21      int  numSkins;                 //  The number of skins associated with the model 
 22      int  numVertices;                 //  The number of vertices (constant for each frame) 
 23      int  numTexCoords;             //  The number of texture coordinates 
 24      int  numTriangles;             //  The number of faces (polygons) 
 25      int  numGlCommands;             //  The number of gl commands 
 26      int  numFrames;                 //  The number of animation frames 
 27      int  offsetSkins;                 //  The offset in the file for the skin data 
 28      int  offsetTexCoords;             //  The offset in the file for the texture data 
 29      int  offsetTriangles;             //  The offset in the file for the face data 
 30      int  offsetFrames;             //  The offset in the file for the frames data 
 31      int  offsetGlCommands;         //  The offset in the file for the gl commands data 
 32      int  offsetEnd;                 //  The end of the file offset 
 33  }; 
 34   
 35   
 36  //  This is used to store the vertices that are read in for the current frame 
 37  struct  tMd2AliasTriangle 
 38 
 39      byte  vertex[ 3 ]; 
 40      byte  lightNormalIndex; 
 41  }; 
 42   
 43  //  This stores the normals and vertices for the frames 
 44  struct  tMd2Triangle 
 45 
 46      float  vertex[ 3 ]; 
 47      float  normal[ 3 ]; 
 48  }; 
 49   
 50  //  This stores the indices into the vertex and texture coordinate arrays 
 51  struct  tMd2Face 
 52 
 53      short  vertexIndices[ 3 ]; 
 54      short  textureIndices[ 3 ]; 
 55  }; 
 56   
 57  //  This stores UV coordinates 
 58  struct  tMd2TexCoord 
 59 
 60      short  u, v; 
 61  }; 
 62   
 63  //  This stores the animation scale, translation and name information for a frame, plus verts 
 64  struct  tMd2AliasFrame 
 65 
 66      float  scale[ 3 ]; 
 67      float  translate[ 3 ]; 
 68      char  name[ 16 ]; 
 69     tMd2AliasTriangle aliasVertices[ 1 ]; 
 70  }; 
 71   
 72  //  This stores the frames vertices after they have been transformed 
 73  struct  tMd2Frame 
 74 
 75      char  strName[ 16 ]; 
 76     tMd2Triangle  * pVertices; 
 77  }; 
 78   
 79  //  This stores a skin name 
 80  typedef  char  tMd2Skin[ 64 ]; 
 81   
 82   
 83  //  This class handles all of the loading code 
 84  class  CLoadMD2 
 85 
 86   
 87  public
 88      CLoadMD2();                                 //  This inits the data members 
 89   
 90       //  This is the function that you call to load the MD2 
 91       bool  ImportMD2(t3DModel  * pModel,  char   * strFileName,  char   * strTexture); 
 92   
 93  private
 94       
 95       //  This reads in the data from the MD2 file and stores it in the member variables 
 96       void  ReadMD2Data(); 
 97   
 98       //  This converts the member variables to our pModel structure 
 99       void  ConvertDataStructures(t3DModel  * pModel); 
100   
101       //  This computes the vertex normals for the object (used for lighting) 
102       void  ComputeNormals(t3DModel  * pModel); 
103   
104       //  This frees memory and closes the file 
105       void  CleanUp(); 
106       
107       //  The file pointer 
108      FILE  * m_FilePointer; 
109   
110       //  Member variables         
111   
112      tMd2Header                m_Header;             //  The header data 
113      tMd2Skin                 * m_pSkins;             //  The skin data 
114      tMd2TexCoord             * m_pTexCoords;         //  The texture coordinates 
115      tMd2Face                 * m_pTriangles;         //  Face index information 
116      tMd2Frame                 * m_pFrames;             //  The frames of animation (vertices) 
117  }; 
118   
119   
120  #endif  
121   
122   
123  /  
124  //  
125  //  * QUICK NOTES *  
126  //   
127  //  This file holds all of the structure and class definitions needed to load 
128  //  a MD2 Quake2 file. 
129  //  
130  //   
131  //  Ben Humphrey (DigiBen) 
132  //  Game Programmer 
133  //  DigiBen@GameTutorials.com 
134  //  Co-Web Host of www.GameTutorials.com 
135  //  
136  //  The Quake2 .Md2 file format is owned by ID Software.  This tutorial is being used  
137  //  as a teaching tool to help understand model loading and animation.  This should 
138  //  not be sold or used under any way for commercial use with out written conset 
139  //  from ID Software. 
140  //  
141  //  Quake and Quake2 are trademarks of id Software. 
142  //  All trademarks used are properties of their respective owners.  
143  //  
144  //   
145   
146   
147   
148    /// MD2.CPP //
149    // *********************************************************************** //    
150  //                                                                         //    
151  //       - "Talk to me like I'm a 3 year old!" Programming Lessons -       //    
152  //                                                                         //    
153  //       $Author:        DigiBen     digiben@gametutorials.com             //    
154  //                                                                         //    
155  //       $Program:       MD2 Loader                                        //    
156  //                                                                         //    
157  //       $Description:   Demonstrates how to load a Quake2 MD2 Model       //    
158  //                                                                         //    
159  //       $Date:          2/6/02                                            //    
160  //                                                                         //    
161  // *********************************************************************** //    
162     
163     
164  #include  " main.h "    
165  #include  " Md2.h "    
166     
167     
168  /   
169  //    
170  //  This file holds the code to load the Quake2 models from a .Md2 format.   
171  //  The .Md2 file is usually stored in a .zip file (don't let the extension   
172  //  fool you, just rename it to .zip), depending on where you get the models   
173  //  from.  The CLoadMD2 class handles the loading, but we draw the model   
174  //  externally on our own in main.cpp.  I created a converter function   
175  //  to convert to our already used model and object structures.  This way   
176  //  eventually we can create a model library that can load any type of   
177  //  model that we support, as well as use inheritance to create a new class   
178  //  for each file format for the small things that each model format needs differently.   
179  //  Like the other loading tutorials, we calculate our own vertex normals.   
180  //  The .Md2 format is REALLY simple to load.  That is why I chose it.  The   
181  //  next tutorial will show how to load and animate Md2 files.  Next, we   
182  //  will move from key frame animation to skeletal animation with the Quake3   
183  //  .Md3 files.  This is also a wonderfuly easy format to load and use.   
184  //    
185  //    
186     
187     
188  /  CLOAD MD2 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
189  /// //   
190  /// //   This constructor initializes the md2 structures   
191  /// //   
192  /  CLOAD MD2 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
193     
194  CLoadMD2::CLoadMD2()   
195  {   
196       //  Here we initialize our structures to 0   
197      memset( & m_Header,  0 sizeof (tMd2Header));   
198     
199       //  Set the pointers to null   
200      m_pSkins = NULL;   
201      m_pTexCoords = NULL;   
202      m_pTriangles = NULL;   
203      m_pFrames = NULL;   
204  }   
205     
206     
207  /  IMPORT MD2 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
208  /// //   
209  /// //   This is called by the client to open the .Md2 file, read it, then clean up   
210  /// //   
211  /  IMPORT MD2 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
212     
213  bool  CLoadMD2::ImportMD2(t3DModel  * pModel,  char   * strFileName,  char   * strTexture)   
214  {   
215       char  strMessage[ 255 =  { 0 };   
216     
217       //  Open the MD2 file in binary   
218      m_FilePointer  =  fopen(strFileName,  " rb " );   
219     
220       //  Make sure we have a valid file pointer (we found the file)   
221       if ( ! m_FilePointer)    
222      {   
223           //  Display an error message and don't load anything if no file was found   
224          sprintf(strMessage,  " Unable to find the file: %s! " , strFileName);   
225          MessageBox(NULL, strMessage,  " Error " , MB_OK);   
226           return   false ;   
227      }   
228         
229       //  Just like most file formats, there is a header that needs to be read   
230       //  from the .Md2 format.  If you look at the tMd2Header structure you will   
231       //  find all the data that will be read in.  It's nice to know up front about   
232       //  the data that we will be reading.  This makes it easy to just to large   
233       //  binary reads using fread, instead of counting and reading chunks.   
234     
235       //  Read the header data and store it in our m_Header member variable   
236      fread( & m_Header,  1 sizeof (tMd2Header), m_FilePointer);   
237     
238       //  For some reason, .Md2 files MUST have a version of 8.  I am not sure why,   
239       //  but if it doesn't there is something wrong and the header was read in   
240       //  incorrectly, or perhaps the file format is bad.   
241       if (m_Header.version  !=   8 )   
242      {   
243           //  Display an error message for bad file format, then stop loading   
244          sprintf(strMessage,  " Invalid file format (Version not 8): %s! " , strFileName);   
245          MessageBox(NULL, strMessage,  " Error " , MB_OK);   
246           return   false ;   
247      }   
248     
249       //  Now that we made sure the header had correct data, we want to read in the   
250       //  rest of the data.  Once the data is read in, we need to convert it to our structures.   
251       //  Since we are only reading in the first frame of animation, there will only   
252       //  be ONE object in our t3DObject structure, held within our pModel variable.   
253      ReadMD2Data();   
254         
255       //  Here we pass in our model structure to it can store the read Quake data   
256       //  in our own model and object structure data   
257      ConvertDataStructures(pModel);   
258     
259       //  After we have read the whole MD2 file, we want to calculate our own vertex normals.   
260      ComputeNormals(pModel);   
261     
262       //  If there is a valid texture name passed in, we want to set the texture data   
263       if (strTexture)   
264      {   
265           //  Create a local material info structure   
266          tMaterialInfo texture;   
267     
268           //  Copy the name of the file into our texture file name variable   
269          strcpy(texture.strFile, strTexture);   
270     
271           //  Since there is only one texture for a .Md2 file, the ID is always 0   
272          texture.texureId  =   0 ;   
273     
274           //  The tile or scale for the UV's is 1 to 1 (but Quake saves off a 0-256 ratio)   
275          texture.uTile  =  texture.uTile  =   1 ;   
276     
277           //  We only have 1 material for a model   
278          pModel -> numOfMaterials  =   1 ;   
279     
280           //  Add the local material info to our model's material list   
281          pModel -> pMaterials.push_back(texture);   
282      }   
283     
284       //  Clean up after everything   
285      CleanUp();   
286     
287       //  Return a success   
288       return   true ;   
289  }   
290     
291     
292  /  READ MD2 DATA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
293  /// //   
294  /// //   This function reads in all of the model's data, except the animation frames   
295  /// //   
296  /  READ MD2 DATA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
297     
298  void  CLoadMD2::ReadMD2Data()   
299  {   
300       //  Create a larger buffer for the frames of animation (not fully used yet)   
301      unsigned  char  buffer[MD2_MAX_FRAMESIZE];   
302       int  j  =   0 ;   
303     
304       //  Here we allocate all of our memory from the header's information   
305      m_pSkins      =   new  tMd2Skin [m_Header.numSkins];   
306      m_pTexCoords  =   new  tMd2TexCoord [m_Header.numTexCoords];   
307      m_pTriangles  =   new  tMd2Face [m_Header.numTriangles];   
308      m_pFrames     =   new  tMd2Frame [m_Header.numFrames];   
309     
310       //  Next, we start reading in the data by seeking to our skin names offset   
311      fseek(m_FilePointer, m_Header.offsetSkins, SEEK_SET);   
312         
313       //  Depending on the skin count, we read in each skin for this model   
314      fread(m_pSkins,  sizeof (tMd2Skin), m_Header.numSkins, m_FilePointer);   
315         
316       //  Move the file pointer to the position in the file for texture coordinates   
317      fseek(m_FilePointer, m_Header.offsetTexCoords, SEEK_SET);   
318         
319       //  Read in all the texture coordinates in one fell swoop   
320      fread(m_pTexCoords,  sizeof (tMd2TexCoord), m_Header.numTexCoords, m_FilePointer);   
321     
322       //  Move the file pointer to the triangles/face data offset   
323      fseek(m_FilePointer, m_Header.offsetTriangles, SEEK_SET);   
324         
325       //  Read in the face data for each triangle (vertex and texCoord indices)   
326      fread(m_pTriangles,  sizeof (tMd2Face), m_Header.numTriangles, m_FilePointer);   
327                 
328       //  Move the file pointer to the vertices (frames)   
329      fseek(m_FilePointer, m_Header.offsetFrames, SEEK_SET);   
330     
331       //  Assign our alias frame to our buffer memory   
332      tMd2AliasFrame  * pFrame  =  (tMd2AliasFrame  * ) buffer;   
333     
334       //  Allocate the memory for the first frame of animation's vertices   
335      m_pFrames[ 0 ].pVertices  =   new  tMd2Triangle [m_Header.numVertices];   
336     
337       //  Read in the first frame of animation   
338      fread(pFrame,  1 , m_Header.frameSize, m_FilePointer);   
339     
340       //  Copy the name of the animation to our frames array   
341      strcpy(m_pFrames[ 0 ].strName, pFrame -> name);   
342                 
343       //  After we have read in the data for the model, since there is animation,   
344       //  This means that there are scale and translation values to be dealt with.   
345       //  To apply the scale and translation values, we simply multiply the scale (x, y, z)   
346       //  by the current vertex (x, y, z).  Also notice that we switch the Y and Z values   
347       //  so that Y is faces up, NOT Z.   
348         
349       //  Store off a vertex array pointer to cut down large lines of code   
350      tMd2Triangle  * pVertices  =  m_pFrames[ 0 ].pVertices;   
351     
352       //  Go through all of the number of vertices and assign the scale and translations.   
353       //  Store the vertices in our current frame's vertex list array, while swapping Y and Z.   
354       //  Notice we also negate the Z axis as well to make the swap correctly.   
355       for  (j = 0 ; j  <  m_Header.numVertices; j ++ )   
356      {   
357          pVertices[j].vertex[ 0 =  pFrame -> aliasVertices[j].vertex[ 0 *  pFrame -> scale[ 0 +  pFrame -> translate[ 0 ];   
358          pVertices[j].vertex[ 2 =   - 1   *  (pFrame -> aliasVertices[j].vertex[ 1 *  pFrame -> scale[ 1 +  pFrame -> translate[ 1 ]);   
359          pVertices[j].vertex[ 1 =  pFrame -> aliasVertices[j].vertex[ 2 *  pFrame -> scale[ 2 +  pFrame -> translate[ 2 ];   
360      }   
361  }   
362     
363     
364  /  CONVERT DATA STRUCTURES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
365  /// //   
366  /// //   This function converts the .md2 structures to our own model and object structures   
367  /// //   
368  /  CONVERT DATA STRUCTURES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
369     
370  void  CLoadMD2::ConvertDataStructures(t3DModel  * pModel)   
371  {   
372       int  j  =   0 , i  =   0 ;   
373         
374       //  Assign the number of objects, which is 1 since we only want 1 frame   
375       //  of animation.  In the next tutorial each object will be a key frame   
376       //  to interpolate between.   
377      pModel -> numOfObjects  =   1 ;   
378     
379       //  Create a local object to store the first frame of animation's data   
380      t3DObject currentFrame  =  { 0 };   
381     
382       //  Assign the vertex, texture coord and face count to our new structure   
383      currentFrame.numOfVerts    =  m_Header.numVertices;   
384      currentFrame.numTexVertex  =  m_Header.numTexCoords;   
385      currentFrame.numOfFaces    =  m_Header.numTriangles;   
386     
387       //  Allocate memory for the vertices, texture coordinates and face data.   
388      currentFrame.pVerts     =   new  CVector3 [currentFrame.numOfVerts];   
389      currentFrame.pTexVerts  =   new  CVector2 [currentFrame.numTexVertex];   
390      currentFrame.pFaces     =   new  tFace [currentFrame.numOfFaces];   
391     
392       //  Go through all of the vertices and assign them over to our structure   
393       for  (j = 0 ; j  <  currentFrame.numOfVerts; j ++ )   
394      {   
395          currentFrame.pVerts[j].x  =  m_pFrames[ 0 ].pVertices[j].vertex[ 0 ];   
396          currentFrame.pVerts[j].y  =  m_pFrames[ 0 ].pVertices[j].vertex[ 1 ];   
397          currentFrame.pVerts[j].z  =  m_pFrames[ 0 ].pVertices[j].vertex[ 2 ];   
398      }   
399     
400       //  We can now free the old vertices stored in this frame of animation   
401      delete m_pFrames[ 0 ].pVertices;   
402     
403       //  Go through all of the uv coordinates and assign them over to our structure.   
404       //  The UV coordinates are not normal uv coordinates, they have a pixel ratio of   
405       //  0 to 256.  We want it to be a 0 to 1 ratio, so we divide the u value by the   
406       //  skin width and the v value by the skin height.  This gives us our 0 to 1 ratio.   
407       //  For some reason also, the v coodinate is flipped upside down.  We just subtract   
408       //  the v coordinate from 1 to remedy this problem.   
409       for  (j = 0 ; j  <  currentFrame.numTexVertex; j ++ )   
410      {   
411          currentFrame.pTexVerts[j].x  =  m_pTexCoords[j].u  /   float (m_Header.skinWidth);   
412          currentFrame.pTexVerts[j].y  =   1   -  m_pTexCoords[j].v  /   float (m_Header.skinHeight);   
413      }   
414     
415       //  Go through all of the face data and assign it over to OUR structure   
416       for (j = 0 ; j  <  currentFrame.numOfFaces; j ++ )   
417      {   
418           //  Assign the vertex indices to our face data   
419          currentFrame.pFaces[j].vertIndex[ 0 =  m_pTriangles[j].vertexIndices[ 0 ];   
420          currentFrame.pFaces[j].vertIndex[ 1 =  m_pTriangles[j].vertexIndices[ 1 ];   
421          currentFrame.pFaces[j].vertIndex[ 2 =  m_pTriangles[j].vertexIndices[ 2 ];   
422     
423           //  Assign the texture coord indices to our face data   
424          currentFrame.pFaces[j].coordIndex[ 0 =  m_pTriangles[j].textureIndices[ 0 ];   
425          currentFrame.pFaces[j].coordIndex[ 1 =  m_pTriangles[j].textureIndices[ 1 ];   
426          currentFrame.pFaces[j].coordIndex[ 2 =  m_pTriangles[j].textureIndices[ 2 ];   
427      }   
428     
429       //  Here we add the current object (or frame) to our list object list   
430      pModel -> pObject.push_back(currentFrame);   
431  }   
432     
433     
434  /  CLEAN UP \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
435  /// //   
436  /// //   This function cleans up our allocated memory and closes the file   
437  /// //   
438  /  CLEAN UP \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
439     
440  void  CLoadMD2::CleanUp()   
441  {   
442       //  This just just the regular cleanup or our md2 model class.  We can free   
443       //  all of this data because we already have it stored in our own structures.   
444     
445      fclose(m_FilePointer);                       //  Close the current file pointer   
446     
447       if (m_pSkins)     delete [] m_pSkins;         //  Free the skins data   
448       if (m_pTexCoords) delete m_pTexCoords;        //  Free the texture coord data   
449       if (m_pTriangles) delete m_pTriangles;        //  Free the triangle face data   
450       if (m_pFrames)    delete m_pFrames;           //  Free the frames of animation   
451  }   
452     
453     
454     
455  //  *Note*    
456  //    
457  //  Below are some math functions for calculating vertex normals.  We want vertex normals   
458  //  because it makes the lighting look really smooth and life like.  You probably already   
459  //  have these functions in the rest of your engine, so you can delete these and call   
460  //  your own.  I wanted to add them so I could show how to calculate vertex normals.   
461     
462  //   Math Functions   // //*   
463     
464  //  This computes the magnitude of a normal.   (magnitude = sqrt(x^2 + y^2 + z^2)   
465  #define  Mag(Normal) (sqrt(Normal.x*Normal.x + Normal.y*Normal.y + Normal.z*Normal.z))   
466     
467  //  This calculates a vector between 2 points and returns the result   
468  CVector3 Vector(CVector3 vPoint1, CVector3 vPoint2)   
469  {   
470      CVector3 vVector;                            //  The variable to hold the resultant vector   
471     
472      vVector.x  =  vPoint1.x  -  vPoint2.x;           //  Subtract point1 and point2 x's   
473      vVector.y  =  vPoint1.y  -  vPoint2.y;           //  Subtract point1 and point2 y's   
474      vVector.z  =  vPoint1.z  -  vPoint2.z;           //  Subtract point1 and point2 z's   
475     
476       return  vVector;                              //  Return the resultant vector   
477  }   
478     
479  //  This adds 2 vectors together and returns the result   
480  CVector3 AddVector(CVector3 vVector1, CVector3 vVector2)   
481  {   
482      CVector3 vResult;                            //  The variable to hold the resultant vector   
483         
484      vResult.x  =  vVector2.x  +  vVector1.x;         //  Add Vector1 and Vector2 x's   
485      vResult.y  =  vVector2.y  +  vVector1.y;         //  Add Vector1 and Vector2 y's   
486      vResult.z  =  vVector2.z  +  vVector1.z;         //  Add Vector1 and Vector2 z's   
487     
488       return  vResult;                              //  Return the resultant vector   
489  }   
490     
491  //  This divides a vector by a single number (scalar) and returns the result   
492  CVector3 DivideVectorByScaler(CVector3 vVector1,  float  Scaler)   
493  {   
494      CVector3 vResult;                            //  The variable to hold the resultant vector   
495         
496      vResult.x  =  vVector1.x  /  Scaler;             //  Divide Vector1's x value by the scaler   
497      vResult.y  =  vVector1.y  /  Scaler;             //  Divide Vector1's y value by the scaler   
498      vResult.z  =  vVector1.z  /  Scaler;             //  Divide Vector1's z value by the scaler   
499     
500       return  vResult;                              //  Return the resultant vector   
501  }   
502     
503  //  This returns the cross product between 2 vectors   
504  CVector3 Cross(CVector3 vVector1, CVector3 vVector2)   
505  {   
506      CVector3 vCross;                                 //  The vector to hold the cross product   
507                                                   //  Get the X value   
508      vCross.x  =  ((vVector1.y  *  vVector2.z)  -  (vVector1.z  *  vVector2.y));   
509                                                   //  Get the Y value   
510      vCross.y  =  ((vVector1.z  *  vVector2.x)  -  (vVector1.x  *  vVector2.z));   
511                                                   //  Get the Z value   
512      vCross.z  =  ((vVector1.x  *  vVector2.y)  -  (vVector1.y  *  vVector2.x));   
513     
514       return  vCross;                               //  Return the cross product   
515  }   
516     
517  //  This returns the normal of a vector   
518  CVector3 Normalize(CVector3 vNormal)   
519  {   
520       double  Magnitude;                            //  This holds the magitude             
521     
522      Magnitude  =  Mag(vNormal);                    //  Get the magnitude   
523     
524      vNormal.x  /=  ( float )Magnitude;               //  Divide the vector's X by the magnitude   
525      vNormal.y  /=  ( float )Magnitude;               //  Divide the vector's Y by the magnitude   
526      vNormal.z  /=  ( float )Magnitude;               //  Divide the vector's Z by the magnitude   
527     
528       return  vNormal;                              //  Return the normal   
529  }   
530     
531  /  COMPUTER NORMALS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
532  /// //   
533  /// //   This function computes the normals and vertex normals of the objects   
534  /// //   
535  /  COMPUTER NORMALS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*   
536     
537  void  CLoadMD2::ComputeNormals(t3DModel  * pModel)   
538  {   
539      CVector3 vVector1, vVector2, vNormal, vPoly[ 3 ];   
540     
541       //  If there are no objects, we can skip this part   
542       if (pModel -> numOfObjects  <=   0 )   
543           return ;   
544     
545       //  What are vertex normals?  And how are they different from other normals?   
546       //  Well, if you find the normal to a triangle, you are finding a "Face Normal".   
547       //  If you give OpenGL a face normal for lighting, it will make your object look   
548       //  really flat and not very round.  If we find the normal for each vertex, it makes   
549       //  the smooth lighting look.  This also covers up blocky looking objects and they appear   
550       //  to have more polygons than they do.    Basically, what you do is first   
551       //  calculate the face normals, then you take the average of all the normals around each   
552       //  vertex.  It's just averaging.  That way you get a better approximation for that vertex.   
553     
554       //  Go through each of the objects to calculate their normals   
555       for ( int  index  =   0 ; index  <  pModel -> numOfObjects; index ++ )   
556      {   
557           //  Get the current object   
558          t3DObject  * pObject  =   & (pModel -> pObject[index]);   
559     
560           //  Here we allocate all the memory we need to calculate the normals   
561          CVector3  * pNormals       =   new  CVector3 [pObject -> numOfFaces];   
562          CVector3  * pTempNormals   =   new  CVector3 [pObject -> numOfFaces];   
563          pObject -> pNormals         =   new  CVector3 [pObject -> numOfVerts];   
564     
565           //  Go though all of the faces of this object   
566           for ( int  i = 0 ; i  <  pObject -> numOfFaces; i ++ )   
567          {                                                  
568               //  To cut down LARGE code, we extract the 3 points of this face   
569              vPoly[ 0 =  pObject -> pVerts[pObject -> pFaces[i].vertIndex[ 0 ]];   
570              vPoly[ 1 =  pObject -> pVerts[pObject -> pFaces[i].vertIndex[ 1 ]];   
571              vPoly[ 2 =  pObject -> pVerts[pObject -> pFaces[i].vertIndex[ 2 ]];   
572     
573               //  Now let's calculate the face normals (Get 2 vectors and find the cross product of those 2)   
574     
575              vVector1  =  Vector(vPoly[ 0 ], vPoly[ 2 ]);       //  Get the vector of the polygon (we just need 2 sides for the normal)   
576              vVector2  =  Vector(vPoly[ 2 ], vPoly[ 1 ]);       //  Get a second vector of the polygon   
577     
578              vNormal   =  Cross(vVector1, vVector2);        //  Return the cross product of the 2 vectors (normalize vector, but not a unit vector)   
579              pTempNormals[i]  =  vNormal;                   //  Save the un-normalized normal for the vertex normals   
580              vNormal   =  Normalize(vNormal);               //  Normalize the cross product to give us the polygons normal   
581     
582              pNormals[i]  =  vNormal;                       //  Assign the normal to the list of normals   
583          }   
584     
585           /// / Now Get The Vertex Normals  /// //   
586     
587          CVector3 vSum  =  { 0.0 0.0 0.0 };   
588          CVector3 vZero  =  vSum;   
589           int  shared = 0 ;   
590     
591           for  (i  =   0 ; i  <  pObject -> numOfVerts; i ++ )          //  Go through all of the vertices   
592          {   
593               for  ( int  j  =   0 ; j  <  pObject -> numOfFaces; j ++ //  Go through all of the triangles   
594              {                                                //  Check if the vertex is shared by another face   
595                   if  (pObject -> pFaces[j].vertIndex[ 0 ==  i  ||     
596                      pObject -> pFaces[j].vertIndex[ 1 ==  i  ||     
597                      pObject -> pFaces[j].vertIndex[ 2 ==  i)   
598                  {   
599                      vSum  =  AddVector(vSum, pTempNormals[j]); //  Add the un-normalized normal of the shared face   
600                      shared ++ ;                                //  Increase the number of shared triangles   
601                  }   
602              }         
603                 
604               //  Get the normal by dividing the sum by the shared.  We negate the shared so it has the normals pointing out.   
605              pObject -> pNormals[i]  =  DivideVectorByScaler(vSum,  float ( - shared));   
606     
607               //  Normalize the normal for the final vertex normal   
608              pObject -> pNormals[i]  =  Normalize(pObject -> pNormals[i]);      
609     
610              vSum  =  vZero;                                    //  Reset the sum   
611              shared  =   0 ;                                      //  Reset the shared   
612          }   
613         
614           //  Free our memory and start over on the next object   
615          delete [] pTempNormals;   
616          delete [] pNormals;   
617      }   
618  }   
619     
620     
621  /    
622  //    
623  //  * QUICK NOTES *    
624  //    
625  //  Pretty simple huh?  This is probably the easiest 3D file format I have ever   
626  //  worked with, so good job Carmack!  Once again, the next Md2 tutorial will cover   
627  //  the key frame animation that is associated with these models.  Then you can    
628  //  actually say you have worked with real quake characters and know how they did   
629  //  their animation.  Let's go over a brief explanation of this loader:   
630  //    
631  //  The structures MUST be the same size and data types in order to load the   
632  //  Quake2 data.  First we load the Header information.  This tells us everything   
633  //  about the file and it's contents.   
634  //     
635  //  After the header is loaded, we need to check if the ID is 8.  This is a must.   
636  //  Don't ask me why it's 8, ask John Carmack!  If the version ID checks out, then   
637  //  we can start loading the data.   
638  //     
639  //  For each set of data you want to load is, we use an fseek() to move the file   
640  //  pointer to that location in the file that is given in the header.   
641  //    
642  //  After you load the data, you can then convert the data structures to your own   
643  //  format, that way you don't have ot be stuck with theirs.  I decided to make it   
644  //  like the other loaders for future purposes.  We also compute our own normals.   
645  //    
646  //  There is one thing I didn't mention that was NOT loaded in.  There is an array   
647  //  of OpenGL commands that allow you to render the vertices in triangle strips and   
648  //  a triangle fan.  This is the ugliest code I have ever seen to implement it, so   
649  //  I left it out :)   
650  //    
651  //  I would like to thank Daniel E. Schoenblum <dansch@hops.cs.jhu.edu> for help   
652  //  with explaining the file format.   
653  //    
654  //  Let me know if this helps you out!   
655  //     
656  //     
657  //  Ben Humphrey (DigiBen)   
658  //  Game Programmer   
659  //  DigiBen@GameTutorials.com   
660  //  Co-Web Host of www.GameTutorials.com   
661  //    
662  //  The Quake2 .Md2 file format is owned by ID Software.  This tutorial is being used    
663  //  as a teaching tool to help understand model loading and animation.  This should   
664  //  not be sold or used under any way for commercial use with out written conset   
665  //  from ID Software.   
666  //    
667  //  Quake and Quake2 are trademarks of id Software.   
668  //  All trademarks used are properties of their respective owners.    
669  //    
670  //    
671   
672   

 

 

转载于:https://www.cnblogs.com/IamEasy_Man/archive/2010/03/17/1688466.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值