OpenGL读取3DS文件示例(C++语言编写


这个代码不算成熟,但是可以读取一般的3DS文件了,还有重现时物体材质没有精心设计,这里请阅读的朋友自行设计吧。这个例子的目的是给刚学的朋友提供一个例子,代码如下:

3dsId.h

#ifndef _3DS_ID_H_
#define _3DS_ID_H_

const GLsizei   PRIMARY             = 0x4D4D;
const GLsizei   MAINOBJECT          = 0x3D3D;     // 网格对象的版本号
const GLsizei   EDITKEYFRAME        = 0xB000;     // 所有关键帧信息的头部
const GLsizei   MATERIAL         = 0xAFFF;     // 保存纹理信息
const GLsizei   OBJECT          = 0x4000;     // 保存对象的面、顶点等信息
const GLsizei   MATNAME             = 0xA000;     // 保存材质名称
const GLsizei   OBJECT_MESH         = 0x4100;     // 新的网格对象
const GLsizei   OBJECT_VERTICES     = 0x4110;    // 对象顶点
const GLsizei   OBJECT_FACES     = 0x4120;    // 对象的面
const GLsizei   OBJECT_MATERIAL     = 0x4130;    // 对象的材质
const GLsizei MAT_AMBIENT    = 0xa010;
const GLsizei MAT_DIFFUSE    = 0xa020;
const GLsizei MAT_SPECULAR   = 0xa030;
const GLsizei MAT_SHININESS   = 0xa040;
const GLsizei MAT_TRANSPARENCY = 0xa050;
const GLsizei INT_PERCENTAGE   = 0x0030;
const GLsizei FLOAT_PERCENTAGE = 0x0031;
const GLsizei COLOR_F     = 0x0010;
const GLsizei COLOR_24    = 0x0011;

#endif

MyModel.h

#ifndef __MY_MODEL_H__
#define __MY_MODEL_H__

#include <gl\glut.h>
#include <vector>
#include <string>

struct Vertex
{
GLfloat x;
GLfloat y;
GLfloat z;
};

struct Face
{
GLushort Index[3];
GLushort MaterialPos;
Vertex Normal;
};

struct Chunk
{
GLushort ID;
GLuint Len;
};

struct Material
{
std::string               name;
GLfloat                ambientColor[3];
GLfloat                diffuseColor[3];
GLfloat                specularColor[3];
GLfloat                emissiveColor[3];
GLfloat                shininess;
GLfloat                transparency;
};

struct Object
{
std::string                  Name;
std::vector< Vertex >       Vertexs;
std::vector< Face >          Faces;
};

struct Model
{
std::vector< Object >        MyObject;
std::vector< Material >      MyMaterial;
};

#endif

MyLoader.h

#ifndef __3DS_LOADER_H__
#define __3DS_LOADER_H__

#include <fstream>
#include "MyModel.h"

class MyLoader
{
public:
MyLoader();
void               OpenFile( const std::string& );
void               LoadFile();
void               CloseFile();
const Model&       GetModel();
private:
void               LoadModel( const Chunk& );

void               LoadMaterial( const Chunk& );
void               LoadColor( float* );
void               LoadPercent( float* );

void               LoadObject( const Chunk& );
void               LoadVertex( Object* const& );
void               LoadFaces( Object* );
void               LoadObjectMaterial( Object* );
void               LoadMesh( const Chunk& MyChunk );
private:
Vertex             Vectors( const Vertex&, const Vertex& );
Vertex             Cross( const Vertex&, const Vertex& );
void               Normalize( Vertex* Point );
void               ComputeNormals();
private:
void               ReadChunk( Chunk* MyChunk );
void               ReadGLfloat( GLfloat* );
void               ReadGLushort( GLushort* );
void               ReadGLuint( GLuint* );
void               ReadGLubyte( GLubyte* );
void               SkipNByte( const size_t& );
std::string        ReadString();
private:
size_t             NowPos;
size_t             FileLength;
size_t             Version;
Model              MyModel;
std::ifstream      FileReader;
};

#endif

MyLoader.cpp

#include "MyLoader.h"
#include <stdexcept>
#include <cmath>
#include "3dsId.h"

using namespace std;

MyLoader::MyLoader() : NowPos( 0 ),FileLength( 0 ), Version( 0 )
{}
void MyLoader::OpenFile( const string& FileRoad )
{
locale::global( locale("") );
FileReader.open( FileRoad.c_str(), ifstream::binary );
locale::global( locale("C") );
if( !FileReader )
   throw std::runtime_error( "打开文件失败" );;
}
void MyLoader::CloseFile()
{
FileReader.close();
}
void MyLoader::LoadFile()
{
Chunk MyChunk;
ReadChunk( &MyChunk );
if( PRIMARY != MyChunk.ID )
   throw runtime_error( "文件损坏" );
FileLength = MyChunk.Len;

ReadChunk( &MyChunk );
ReadGLuint( &Version );
while( NowPos < FileLength )
{
   ReadChunk( &MyChunk );
   if( MAINOBJECT == MyChunk.ID )
    LoadModel( MyChunk );
   else
    SkipNByte( MyChunk.Len - 6 );
}

ComputeNormals();
}
void MyLoader::LoadModel( const Chunk& MyChunk )
{
size_t BeginPos( NowPos - 6 );
Chunk TempChunk;
while( NowPos - BeginPos != MyChunk.Len )
{
   ReadChunk( &TempChunk );
   switch( TempChunk.ID )
   {
   case OBJECT:
    LoadObject( TempChunk );
    break;

   case MATERIAL:
    LoadMaterial( TempChunk );
    break;

   default:
    SkipNByte( TempChunk.Len - 6 );
   }
}
}
void MyLoader::LoadObject( const Chunk& MyChunk )
{
Object object;
object.Name = ReadString();
MyModel.MyObject.push_back( object );

Chunk ThisChunk;
size_t BeginPos( NowPos - 7 - object.Name.size() );
while( NowPos - BeginPos != MyChunk.Len )
{
   ReadChunk( &ThisChunk );
   if( OBJECT_MESH == ThisChunk.ID )
    LoadMesh( ThisChunk );
   else
    SkipNByte( ThisChunk.Len - 6 );
}
}
void MyLoader::LoadMesh( const Chunk& MyChunk )
{
Object &object = MyModel.MyObject[ MyModel.MyObject.size() - 1 ];

size_t BeginPos( NowPos - 6 );
Chunk ThisChunk;
while( NowPos - BeginPos != MyChunk.Len )
{
   ReadChunk( &ThisChunk );
   switch( ThisChunk.ID )
   {
   case OBJECT_VERTICES: //顶点
    LoadVertex( &object );
    break;

   case OBJECT_FACES:     //面
    LoadFaces( &object );
    break;

   case OBJECT_MATERIAL: //材质
    LoadObjectMaterial( &object );
    break;

   default:              //跳过不需要的块
    SkipNByte( ThisChunk.Len - 6 );
   }
}
}
void MyLoader::LoadObjectMaterial( Object* object )
{
string Name = ReadString();
int Pos( -1 );
for( size_t i = 0; i != MyModel.MyMaterial.size(); ++ i )
{
   if( MyModel.MyMaterial[ i ].name == Name )
    Pos = i;
}

if( Pos == -1 )
   throw runtime_error( "没有找到该材质" );

GLushort Sum( 0 ); GLushort FacePos( 0 );
ReadGLushort( &Sum );
for( size_t i = 0; i != Sum; ++ i )
{
   ReadGLushort( &FacePos );
   object->Faces[ FacePos ].MaterialPos = Pos;
}
}
void MyLoader::LoadMaterial( const Chunk& MyChunk )
{
Chunk TempChunk;
Material material;
size_t BeginPos( NowPos - 6 );

while( NowPos - BeginPos < MyChunk.Len )
{
   ReadChunk( &TempChunk );
   switch( TempChunk.ID )
   {
   case MATNAME:                       //材质名称
    material.name = ReadString();
    break;
   case MAT_AMBIENT:                  //材质Ambient
    LoadColor( material.ambientColor );
    break;
   case MAT_DIFFUSE:                  //材质Diffuse
    LoadColor( material.diffuseColor );
    break;
   case MAT_SPECULAR:                 //材质Specular
    LoadColor( material.specularColor );
    break;
   case MAT_SHININESS:                //材质Shininess
    LoadPercent( &material.shininess );
    break;
   case MAT_TRANSPARENCY:             //材质透明度
    LoadPercent( &material.transparency );
    break;
   default:
    SkipNByte( TempChunk.Len - 6 );
   }
}
MyModel.MyMaterial.push_back( material );
}
void MyLoader::LoadColor( float* color )
{
Chunk TempChunk;
ReadChunk( &TempChunk );
switch( TempChunk.ID )
{
case COLOR_F:
   ReadGLfloat( &color[ 0 ] );
   ReadGLfloat( &color[ 1 ] );
   ReadGLfloat( &color[ 2 ] );
   break;
case COLOR_24:
   GLubyte Byte;
   for( size_t i = 0; i != 3; ++ i )
   {
    ReadGLubyte( &Byte );
    color[ i ] = Byte / 255.0;
   }
   break;
default:
   SkipNByte( TempChunk.Len - 6 );
}
}
void MyLoader::LoadPercent( GLfloat* Temp )
{
Chunk TempChunk;
ReadChunk( &TempChunk );
switch( TempChunk.ID )
{
case INT_PERCENTAGE:    //Int型 百分数
   GLushort Percent;
   ReadGLushort( &Percent );
   *Temp = Percent / 100.0;
   break;
case FLOAT_PERCENTAGE: //Float型 百分数
   ReadGLfloat( Temp );
   break;
default:
   SkipNByte( TempChunk.Len - 6 );
}
}
Vertex MyLoader::Vectors( const Vertex& lPoint, const Vertex& rPoint )
{
Vertex Point;
Point.x = lPoint.x - rPoint.x;
Point.y = lPoint.y - rPoint.y;
Point.z = lPoint.z - rPoint.z;
return Point;
}
Vertex MyLoader::Cross( const Vertex& lPoint, const Vertex& rPoint )
{
Vertex Point;
Point.x = lPoint.y * rPoint.z - lPoint.z * rPoint.y;
Point.y = lPoint.z * rPoint.x - lPoint.x * rPoint.z;
Point.z = lPoint.x * rPoint.y - lPoint.y * rPoint.x;
return Point;
}
void MyLoader::Normalize( Vertex* point )
{
float Magnitude = sqrt( point->x * point->x + point->y * point->y + point->z * point->z );
if( 0 == Magnitude )
   Magnitude = 1;
point->x /= Magnitude;    
point->y /= Magnitude;    
point->z /= Magnitude;           
}
void MyLoader::ComputeNormals()
{
for( size_t i = 0; i != MyModel.MyObject.size(); ++ i )
{
   Object& object = MyModel.MyObject[ i ];
   for( size_t j = 0; j != MyModel.MyObject[ i ].Faces.size(); ++ j )
   {
    Face& face = object.Faces[ j ];
    const Vertex &Point1 = object.Vertexs[ face.Index[ 0 ] ];
    const Vertex &Point2 = object.Vertexs[ face.Index[ 1 ] ];
    const Vertex &Point3 = object.Vertexs[ face.Index[ 2 ] ];

    face.Normal = Cross( Vectors( Point1, Point3 ), Vectors( Point3, Point2 ) );
    Normalize( &face.Normal );
   }
}
}
const Model& MyLoader::GetModel()
{
return MyModel;
}
void MyLoader::LoadFaces( Object* ThisObject )
{
GLushort Sum( 0 );
ReadGLushort( &Sum );
Face face; GLushort Temp( 0 );
for( size_t i = 0; i != Sum; ++ i )
{
   for( size_t j = 0; j != 4; ++ j )
   {
    ReadGLushort( &Temp );
    if( j < 3 )
     face.Index[ j ] = Temp;
   }
   ThisObject->Faces.push_back( face );
}
}
void MyLoader::LoadVertex( Object* const& ThisObject )
{
GLushort Sum( 0 );
ReadGLushort( &Sum );
Vertex Point;
float Num( 0 );float distence( 0 );
for( size_t i = 0; i != Sum; ++ i )
{

   ReadGLfloat( &Point.x );
   ReadGLfloat( &Point.z );
   ReadGLfloat( &Point.y );
   Point.z *= -1;
   ThisObject->Vertexs.push_back( Point );
}
}


void MyLoader::ReadChunk( Chunk* MyChunk )
{
ReadGLushort( &MyChunk->ID );
ReadGLuint( &MyChunk->Len );
}

void MyLoader::ReadGLubyte( GLubyte* Ubyte )
{
FileReader.read( reinterpret_cast< char* >( Ubyte ), sizeof( GLubyte ) );
NowPos += sizeof( GLubyte );
}

void MyLoader::ReadGLushort( GLushort* Ushort )
{
FileReader.read( reinterpret_cast< char* >( Ushort ), sizeof( GLushort ) );
NowPos += sizeof( GLushort );
}

void MyLoader::ReadGLuint( GLuint* Uint )
{
FileReader.read( reinterpret_cast< char* >( Uint ), sizeof( GLuint ) );
NowPos += sizeof( GLuint );
}

void MyLoader::ReadGLfloat( GLfloat* Float )
{
FileReader.read( reinterpret_cast< char* >( Float ), sizeof( GLfloat ) );
NowPos += sizeof( GLfloat );
}

std::string MyLoader::ReadString()
{
char alpha; string TempWord;
while( FileReader.get( alpha ), alpha != 0 )
   TempWord += alpha;
NowPos += TempWord.size() + 1;
return TempWord;
}

void MyLoader::SkipNByte( const size_t& Num )
{
FileReader.seekg( Num, ifstream::cur );
NowPos += Num;
}

main.cpp

#include "MyLoader.h"
#include <iostream>

using namespace std;

MyLoader Loader;

static GLfloat Spin = 0;
GLint MyList;

void BuildList()
{
MyList = glGenLists( 1 );
glNewList( MyList, GL_COMPILE );

Model TempModel = Loader.GetModel();
for( size_t i = 0; i != TempModel.MyObject.size(); ++ i )
{
   const Object& object = TempModel.MyObject[i];
   glBegin( GL_TRIANGLES );
   for(int j = 0; j != object.Faces.size(); j++)
   {
    const Face& ThisFace = object.Faces[ j ];
    const Material& MyMaterial = TempModel.MyMaterial[ ThisFace.MaterialPos ];

    glNormal3f( ThisFace.Normal.x, ThisFace.Normal.y, ThisFace.Normal.z );
    glColor4f( MyMaterial.diffuseColor[ 0 ], MyMaterial.diffuseColor[ 1 ],
               MyMaterial.diffuseColor[ 2 ], MyMaterial.transparency );

    if( MyMaterial.transparency )
     glEnable( GL_BLEND );
    for( size_t k = 0; k != 3; ++ k )
    {
     size_t index = object.Faces[ j ].Index[ k ];
     glVertex3f( object.Vertexs[ index ].x, object.Vertexs[ index ].y, object.Vertexs[ index ].z );
    }
    if( MyMaterial.transparency )
     glDisable( GL_BLEND );
   }
   glEnd();
}
glEndList();
}

void Init()
{
try
{
   Loader.OpenFile( "Car.3DS" );
   Loader.LoadFile();
   Loader.CloseFile();
}
catch( runtime_error e )
{
   cout << e.what() << endl;
}
catch(...)
{
   cout << "未知错误" << endl;
}

glShadeModel( GL_SMOOTH );
glClearColor( 0.0, 0.0, 0.0, 0.0 );
glClearDepth( 1.0 );

GLfloat Ambient[4] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat Diffuse[4] = { 0.7, 0.7, 0.7, 1.0 };
GLfloat Position[4] = { 0.0, 0.0, -1.0, 1.0 };
GLfloat GlobalLight[4] = { 0.1, 0.1, 0.1, 1.0 };

glLightfv( GL_LIGHT0, GL_AMBIENT, Ambient );
glLightfv( GL_LIGHT0, GL_DIFFUSE, Diffuse );
glLightfv( GL_LIGHT0, GL_POSITION, Position );

glLightModelfv( GL_LIGHT_MODEL_AMBIENT, GlobalLight );
glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
glBlendFunc( GL_SRC_ALPHA, GL_SRC_ALPHA );

glEnable( GL_LIGHTING );
glEnable( GL_LIGHT0 );
glEnable( GL_COLOR_MATERIAL );
glEnable( GL_DEPTH_TEST );
glEnable( GL_CULL_FACE );

BuildList();
}

void SpinDisplay()
{
if( ++ Spin > 360 )
   Spin -= 360;
glutPostRedisplay();
}

void Display()
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glLoadIdentity();
gluLookAt( 0., 0.0, 200.0 , 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 );

glRotatef( Spin, 0.0, 1.0, 0.0 );
glCallList( MyList );

glFlush();
glutSwapBuffers();
}

void Reshape( int width, int high )
{
if ( high == 0 )
   high = 1;
glViewport( 0, 0, static_cast< GLsizei >( width ), static_cast< GLsizei >( high ) );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 45.0, static_cast< GLdouble >( width ) / static_cast< GLdouble >( high ), 0.1, 1000.0 );

glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
}

int main( int argc, char* argv[] )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH );
glutInitWindowSize( 800, 600 );
glutInitWindowPosition( 100, 100 );
glutCreateWindow( "MySystem" );

Init();

glutDisplayFunc( Display );
glutReshapeFunc( Reshape );
glutIdleFunc( SpinDisplay );
glutMainLoop();
return 0;
}



你可能感兴趣的:(OpenGL读取3DS文件示例(C++语言编写)