Opengl讀取及渲染Obj三維模型
阿新 • • 發佈:2019-02-10
宣告:本文內容及原始碼只能作為學習參考用,轉載請註明本宣告blog.csdn.net/t163ang。
最近為了測試我的碰撞檢測程式碼,需要使用Opengl來匯入模型及渲染出來做碰撞,之前我發表一篇文章是對斯坦福模型ply檔案渲染的,ply模型資源有限,所以今天看了其它三維模型,發現Obj模型網上有豐富的資源,且表達能力更強,但解析其就相對來講複雜一些,我看網上一些程式碼,不是過於簡單就是過於複雜,於是自己寫了一個,上網下載了幾個模型效果可以。渲染呼叫很簡單直接呼叫RenderObj函式即可。當然如果你要應用到你的專案中,這個程式碼需要稍微改一改就行羅。另外如果是四邊形將會拆成兩個三角形,網上好多程式碼都沒這個功能。
#define MAXN 1024*1024 #define MAXTEX 32 map<string,size_t> ObjMp; size_t vn,vtn,vnn,fn; float V[MAXN][3]; float VT[MAXN][2]; float VN[MAXN][3]; size_t F[MAXN][3][3]; size_t TexFacCnt[MAXTEX],TexFacID[MAXTEX],tfn; #pragma comment( lib, "glaux.lib") void _InitMtl(const char *filename){ ifstream in(filename); assert(in); ObjMp.clear(); char buffer[300],word[300]; while(in.getline(buffer,300)){ if(strncmp("newmtl",buffer,strlen("newmtl"))==0){ sscanf(buffer,"%*s%s",word); }else if(strncmp("map_Kd",buffer+1,strlen("map_Kd"))==0){ GLuint texName; glGenTextures(1,&texName); AUX_RGBImageRec *aux = auxDIBImageLoadA(buffer+strlen("\tmap_Kd ")); glBindTexture(GL_TEXTURE_2D,texName); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexImage2D(GL_TEXTURE_2D,0,3,aux->sizeX,aux->sizeY,0,GL_RGB,GL_UNSIGNED_BYTE,aux->data); ObjMp.insert(make_pair(word,texName)); delete aux; } } in.close(); } void ReadObj(const char *filename){ ifstream in(filename); assert(in); char buffer[300]; vn=1;vnn=1;vtn=1;tfn=0; while(in.getline(buffer,300)){ if(buffer[0] == 'v'){ if(buffer[1]==' '){ //v sscanf(buffer,"%*s %f %f %f",&V[vn][0],&V[vn][1],&V[vn][2]); ++vn; }else if(buffer[1]=='n' && buffer[2] == ' '){ //vn sscanf(buffer,"%*s %f %f %f",&VN[vnn][0],&VN[vnn][1],&VN[vnn][2]); ++vnn; }else if(buffer[1]=='t' && buffer[2] == ' '){ //vt sscanf(buffer,"%*s %f %f",&VT[vtn][0],&VT[vtn][1]); ++vtn; } }else if(buffer[0]=='f'){ //f if(buffer[1] == ' '){ char str[4][32]; int sn = sscanf(buffer,"%*s %s %s %s %s",str[0],str[1],str[2],str[3]); if(sn == 3){ for(size_t i = 0; i < 3; ++i){ sscanf(str[i],"%d/%d/%d",&F[fn][i][0],&F[fn][i][1],&F[fn][i][2]); } ++fn; /* 直接渲染,但是當模型很大時,速度將很慢 glBegin(GL_TRIANGLES); { size_t iv,it,in; for(size_t i = 0; i < 3; ++i){ sscanf(str[i],"%d/%d/%d",&iv,&it,&in); glNormal3fv(VN[in]); glTexCoord2fv(VT[it]); glVertex3fv(V[iv]); } } glEnd();*/ }else if(sn == 4){ //拆分成兩個三角形,四邊形0123分成Tri012和Tri023 for(size_t i = 0; i < 3; ++i){ sscanf(str[i],"%d/%d/%d",&F[fn][i][0],&F[fn][i][1],&F[fn][i][2]); } ++fn; for(size_t i = 0; i < 3; ++i){ sscanf(str[i!=0?i+1:0],"%d/%d/%d",&F[fn][i][0],&F[fn][i][1],&F[fn][i][2]); } ++fn; /* glBegin(GL_TRIANGLES); { size_t iv,it,in; for(size_t i = 0; i < 3; ++i){ sscanf(str[i],"%d/%d/%d",&iv,&it,&in); glNormal3fv(VN[in]); glTexCoord2fv(VT[it]); glVertex3fv(V[iv]); } for(size_t i = 0; i < 3; ++i){ sscanf(str[i!=0?i+1:0],"%d/%d/%d",&iv,&it,&in); glNormal3fv(VN[in]); glTexCoord2fv(VT[it]); glVertex3fv(V[iv]); } } glEnd(); */ }else{ assert(false); } } }else if(buffer[0]=='m'){ //mtllib if(buffer[1]=='t' && buffer[2]=='l' && buffer[3]=='l' &&buffer[4]=='i' && buffer[5] == 'b' && buffer[6] == ' '){ _InitMtl(buffer+strlen("mtllib ")); } }else if(buffer[0]=='u'){ //usemtl if(buffer[1]=='s' && buffer[2]=='e' && buffer[3]=='m' &&buffer[4]=='t' && buffer[5] == 'l' && buffer[6] == ' '){ string key = string(buffer+strlen("usemtl ")); TexFacCnt[tfn]=fn;//記錄資訊,以後渲染使用 if(ObjMp.find(key) != ObjMp.end()){ //直接在讀檔案時渲染,處理很方便,但渲染更新速度慢 //glBindTexture(GL_TEXTURE_2D,ObjMp[key]); TexFacID[tfn] = ObjMp[key]; }else{ //glBindTexture(GL_TEXTURE_2D,0); TexFacID[tfn] = 0; } ++tfn; } } } } void RenderObj(const char* filename){ static bool firstRender = true; if(firstRender){ ReadObj(filename); firstRender = false; } glBegin(GL_TRIANGLES); { for(size_t i =0,j = 0; i < fn; ++i){ if(j < tfn && i == TexFacCnt[j]){ glBindTexture(GL_TEXTURE_2D,TexFacID[j]); ++j; } glNormal3fv(VN[F[i][0][2]]); glTexCoord2fv(VT[F[i][0][1]]); glVertex3fv(V[F[i][0][0]]); glNormal3fv(VN[F[i][1][2]]); glTexCoord2fv(VT[F[i][1][1]]); glVertex3fv(V[F[i][1][0]]); glNormal3fv(VN[F[i][2][2]]); glTexCoord2fv(VT[F[i][2][1]]); glVertex3fv(V[F[i][2][0]]); } } glEnd(); }
隨便下載一個模型渲染出來效果圖: