1. 程式人生 > >Opengl讀取及渲染Obj三維模型

Opengl讀取及渲染Obj三維模型

宣告:本文內容及原始碼只能作為學習參考用,轉載請註明本宣告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();
}

隨便下載一個模型渲染出來效果圖: