3DS读取.docx
《3DS读取.docx》由会员分享,可在线阅读,更多相关《3DS读取.docx(10页珍藏版)》请在冰豆网上搜索。
![3DS读取.docx](https://file1.bdocx.com/fileroot1/2022-11/24/dd75c1b0-9a9b-4a3f-bf3e-b78d34394ecb/dd75c1b0-9a9b-4a3f-bf3e-b78d34394ecb1.gif)
3DS读取
在OpenGL中读取3DS模型文件
这里要解决的一个关键问题是:
如何在OpenGL中读取3DS模型文件。
在这部分介绍了3DS文件的存储格式,给出了OpenGL与3DS的接口编程,这对三维模型的创建提供了极大的方便,还综合运用其他的技术和算法来完成三维动画。
6.13ds文件格式简介
3DS文件由许多块组成,每个块首先描述其信息类别,即该块是如何组成的。
块的信息类别用ID来标识,块还包含了下一个块的相对位置信息。
因此,即使不理解一个块的含义,也可以很容易地跳过它,因为该块中指出了下一个块的相对于该块起始位置的偏移字节数。
与许多文件格式一样,3DS二进制文件中的数据也是按低位在前、高位在后的方式组织的,例如,2个十六进制字节,4A5C组成的整型数,表明5C是高位字节,4A是低位字节;对于长整型数,如:
4A5C3B8F表明5C4A是低位字,而8F3B是高位字。
下面描述块的具体定义。
块的前两项信息分别是:
块的ID和块的长度(下一个块相对于该块的字节偏移量),块的ID是一个整型数,而块的长度是一个长整型数。
每个块实际上是一个层次结构,不同类型的块,其层次结构也不相同。
3DS文件中有一个基本块,其ID是4D4D,每一个3DS文件的开头都是由这样一个块构成。
基本块内的块称为主块。
为了对块的层次结构有一个初步的认识,下面给出一个图表来说明不同类型(ID)的块及其各自在文件中的位置。
如下图所示给每一个块都起了一个名字,这样更便于理解或直接转换为源程序。
图6.13DS文件结构图
颜色块是文件中自始至终都能见到的一种块类型,颜色块总共有3种类型,它们是COL_RGB,COL_TRU和COL_UNK。
6.2存储3ds文件的数据结构
本节将对程序中所用到的一些重要数据结构进行简单说明,以便使读者更进一步了解3ds文件所存储的数据。
1.t3Dmodel:
structt3DModel
{
intnumOfObjects;//object的数量(总数)
intnumOfMaterials;//materials的数量(总数)
vectorpMaterials;//存贮materials信息的列表
vectorpObject;//存贮object信息的列表
};
2.tMaterialInfo:
structtMaterialInfo
{
charstrName[255];//材质的名字
charstrFile[255];//材质的文件名(真正存在harddisk的bmp)
BYTEcolor[3];//object的颜色(RGB)(0~255)
InttexureId;//材质的ID
}
3.3DObject:
structt3DObject
{
intnumOfVerts;//object的顶点数
intnumOfFaces;//object的面数
intnumTexVertex;//材质坐标的个数
intmaterialID;//材质ID,正是材质数组中的索引
boolbHasTexture;//有材质就为真
charstrName[255];//object的名字
CVector3*pVerts;//object的顶点,将会指向一个数组
CVector3*pNormals;//object的法线(只是一个近似的法线)将会指向一个数组
CVector3*pFaceNorm;//面的法线,将会指向一个数组
CVector3*pFaceVert1;//面的顶点x,将会指向一个数组
CVector3*pFaceVert2;//面的顶点y,将会指向一个数组
CVector3*pFaceVert3;//面的顶点z,将会指向一个数组
CVector2*pTexVerts;//材质的坐标(二维)将会指向一个数组
tFace*pFaces;//面的结构(在后面有注解)将会指向一个数组
};
其中:
structtFace
{
intvertIndex[3];//组成面三角形顶点的索引(整型)
intcoordIndex[3];//组成面三角形材质的索引(整型)
};
6.33D动画的实现
读取3DS文件的全部操作封装在了CLoad3DS类中,有关CLoad3DS类的具体定义所附光盘中的源程序3ds.cppand3ds.h。
/////////////////////////////////IMPORT3DS\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
//
//Thisiscalledbytheclienttoopenthe.3dsfile,readit,thencleanup
//
//////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
boolCLoad3DS:
:
Import3DS(t3DModel*pModel,char*strFileName)
{
charstrMessage[255]={0};
//Openthe3DSfile
m_FilePointer=fopen(strFileName,"rb");
//Makesurewehaveavalidfilepointer(wefoundthefile)
if(!
m_FilePointer)
{
sprintf(strMessage,"Unabletofindthefile:
%s!
",strFileName);
MessageBox(NULL,strMessage,"Error",MB_OK);
returnfalse;
}
//Oncewehavethefileopen,weneedtoreadtheveryfirstdatachunk
//toseeifit'sa3DSfile.Thatwaywedon'treadaninvalidfile.
//Ifitisa3DSfile,thenthefirstchunkIDwillbeequaltoPRIMARY(somehexnum)
//Readthefirstchuckofthefiletoseeifit'sa3DSfile
ReadChunk(m_CurrentChunk);
//Makesurethisisa3DSfile
if(m_CurrentChunk->ID!
=PRIMARY)
{
sprintf(strMessage,"UnabletoloadPRIMARYchuckfromfile:
%s!
",strFileName);
MessageBox(NULL,strMessage,"Error",MB_OK);
returnfalse;
}
//Nowweactuallystartreadinginthedata.ProcessNextChunk()isrecursive
//Beginloadingobjects,bycallingthisrecursivefunction
ProcessNextChunk(pModel,m_CurrentChunk);
//Afterwehavereadthewhole3DSfile,wewanttocalculateourownvertexnormals.
ComputeNormals(pModel);
//Cleanupaftereverything
CleanUp();
returntrue;
}
See光盘中的源程序StepinGlView.cpp
//StepinGlView.cpp:
implementationoftheCStepinGlViewclass
//
……
#include"main.h"//Thisincludesourheaderfile
#include"3ds.h"//Includethe3DSheaderfile.
……
#defineFILE_NAME"moon.3ds"//Thisisthe3Dfilewewillload.
UINTg_Texture[MAX_TEXTURES]={0};//Thisholdsthetextureinfo,referencedbyanID
CLoad3DSg_Load3ds;//Thisis3DSclass.Thisshouldgoinagoodmodelclass.
t3DModelg_3DModel;//Thisholdsthe3DModelinfothatweloadin
intg_ViewMode=GL_TRIANGLES;//Wewantthedefaultdrawingmodetobenormal
boolg_bLighting=true;//Turnlightingoninitially
floatg_RotateX=0.0f;//Thisisthecurrentvalueatwhichthemodelisrotated
floatg_RotationSpeed=0.8f;//Thisisthespeedthatourmodelrotates.(-speedrotatesleft)
……
/////////////////////////////////////////////////////////////////////////////
//CStepinGlViewmessagehandlers
voidCStepinGlView:
:
Init()
{
PIXELFORMATDESCRIPTORpfd;
intn;
HGLRChrc;
m_pDC=newCClientDC(this);
ASSERT(m_pDC!
=NULL);
if(!
bSetupPixelFormat())
return;
n=:
:
GetPixelFormat(m_pDC->GetSafeHdc());
:
:
DescribePixelFormat(m_pDC->GetSafeHdc(),n,sizeof(pfd),&pfd);
hrc=wglCreateContext(m_pDC->GetSafeHdc());
wglMakeCurrent(m_pDC->GetSafeHdc(),hrc);
GetClientRect(&m_oldRect);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
//glMatrixMode(GL_MODELVIEW);
//glLoadIdentity();
g_Load3ds.Import3DS(&g_3DModel,FILE_NAME);//Loadour.3DSfileintoourmodelstructure
//Dependingonhowmanytextureswefound,loadeachone(Assuming.BMP)
//Ifyouwanttoloadotherfilesthanbitmaps,youwillneedtoadjustCreateTexture().
//Below,wegothroughallofthematerialsandcheckiftheyhaveatexturemaptoload.
//Otherwise,thematerialjustholdsthecolorinformationandwedon'tneedtoloadatexture.
//Gothroughallthematerials
for(inti=0;i{
//Checktoseeifthereisafilenametoloadinthismaterial
if(strlen(g_3DModel.pMaterials[i].strFile)>0)
{
//Usethenameofthetexturefiletoloadthebitmap,withatextureID(i).
//Wepassinourglobaltexturearray,thenameofthetexture,andanIDtoreferenceit.
CreateTexture(g_Texture,g_3DModel.pMaterials[i].strFile,i);
}
//SetthetextureIDforthismaterial
g_3DModel.pMaterials[i].texureId=i;
}
glLightfv(GL_LIGHT0,GL_AMBIENT,m_lightAmb);
glLightfv(GL_LIGHT0,GL_DIFFUSE,m_lightDif);
glLightfv(GL_LIGHT0,GL_SPECULAR,m_lightSpe);
glLightfv(GL_LIGHT0,GL_POSITION,m_lightPos);
glEnable(GL_LIGHT0);//Turnonalightwithdefaultsset
glEnable(GL_LIGHTING);//Turnonlighting
glEnable(GL_COLOR_MATERIAL);//Allowcolor
}
voidCStepinGlView:
:
DrawScene()
{
glClearColor(0.0f,0.0f,0.0f,1.0f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(m_posx,m_posy,-5.0f);
glRotatef(m_fAngleY,0.0f,1.0f,0.0f);
glRotatef(m_fAngleZ,0.0f,0.0f,1.0f);
for(inti=0;i{
//Makesurewehavevalidobjectsjustincase.(size()isinthevectorclass)
if(g_3DModel.pObject.size()<=0)break;
//Getthecurrentobjectthatwearedisplaying
t3DObject*pObject=&g_3DModel.pObject[i];
//Checktoseeifthisobjecthasatexturemap,ifsobindthetexturetoit.
if(pObject->bHasTexture){
//Turnontexturemappingandturnoffcolor
glEnable(GL_TEXTURE_2D);
//Resetthecolortonormalagain
glColor3ub(255,255,255);
//Bindthetexturemaptotheobjectbyit'smaterialID
glBindTexture(GL_TEXTURE_2D,g_Texture[pObject->materialID]);
}else{
//Turnofftexturemappingandturnoncolor
glDisable(GL_TEXTURE_2D);
//Resetthecolortonormalagain
glColor3ub(255,255,255);
}
//Thisdeterminesifweareinwireframeornormalmode
glBegin(g_ViewMode);//Begindrawingwithourselectedmode(trianglesorlines)
//Gothroughallofthefaces(polygons)oftheobjectanddrawthem
for(intj=0;jnumOfFaces;j++)
{
//Gothrougheachcornerofthetriangleanddrawit.
for(intwhichVertex=0;whichVertex<3;whichVertex++)
{
//Gettheindexforeachpointoftheface
intindex=pObject->pFaces[j].vertIndex[whichVertex];
//GiveOpenGLthenormalforthisvertex.
glNormal3f(pObject->pNormals[index].x,pObject->pNormals[index].y,pObject->pNormals[index].z);
//Iftheobjecthasatextureassociatedwithit,giveitatexturecoordinate.
if(pObject->bHasTexture){
//MakesuretherewasaUVWmapappliedtotheobjectorelseitwon'thavetexcoords.
if(pObject->pTexVerts){
glTexCoord2f(pObject->pTexVerts[index].x,pObject->pTexVerts[index].y);
}
}else{
//Makesurethereisavalidmaterial/colorassignedtothisobject.
//Youshouldalwaysatleastassignamaterialcolortoanobject,
//butjustincasewewanttocheckthesizeofthemateriallist.
//ifthesizeisatleastone,andthematerialID!
=-1,
//thenwehaveavalidmaterial.
if(g_3DModel.pMaterials.size()&&pObject->materialID>=0)
{
//Getandsetthecolorthattheobjectis,sinceitmustnothaveatexture
BYTE*pColor=g_3DModel.pMaterials[pObject->materialID].color;
//Assignthecurrentcolortothismodel
glColor3ub(pColor[0],pColor[1],pColor[2]);
}
}
//Passinthecurrentvertexoftheobject(Cornerofcurrentface)
glVertex3f(pObject->pVerts[index].x,pObject->pVerts[index].y,pObject->pVerts[index].z);
}
}
glEnd();//Endthedrawing
}
glFinish();
SwapBuffers(wglGetCurrentDC());
}