您的位置:首页 > 运维架构

obj格式文件导入到opengl中 OBJLoader

2012-08-30 19:26 302 查看
.cpp代码

/*********************************************************

3D model loader by gameloftyou

use for obj model

*********************************************************/

#include <windows.h>

#include <iostream>

#include <iterator>

#include <vector>

#include <string>

#include <math.h>

#include <map>

#include <set>

#include <fstream>

#include <sstream>

#include <algorithm>

#include <cstdlib>

#include <gl/glut.h>

#include "object.h"

#include <ctime>

#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")

using namespace std;

map<string,Object> objmap1;

set<string> objname1;

map<string,Material> matname;

map<string,Object> objmap2;

set<string> objname2;

GLfloat dx = 0,dy = 0,dz = 0;

GLfloat ax = 0,ay = 0,az = 0;

GLfloat bx = 0,by = 0,bz = 0;

GLfloat arot;

GLint mx = 0,my = 0;

GLint MouseDown = 0;

GLfloat aspect = 1;

const float piover180 = 0.0174532925f; //折算因子用来折算度和弧度

float heading;

float xpos;

float zpos;

GLfloat yrot; // Y Rotation

GLfloat walkbias = 0;

GLfloat walkbiasangle = 0;

static int sy = 0;

int power_of_two(int n)

{

if(n<=0) return 0;

return n&(n-1)==0;

}

GLuint load_texture(const char *file_name)

{

GLint width,height,total_bytes;

GLuint last_texture_ID,texture_ID = 0;

GLubyte *pixels = NULL;

FILE *pFile;

if((pFile=fopen(file_name,"rb"))==NULL)

{

cout<<"Read texture error"<<endl;

return 0;

}

fseek(pFile,18,SEEK_SET);

fread(&width,sizeof(width),1,pFile);

fread(&height,sizeof(height),1,pFile);

fseek(pFile,54,SEEK_SET);

total_bytes = (width*3+(4-width*3%4)%4)*height;

if((pixels=(GLubyte *)malloc(total_bytes))==NULL)

{

fclose(pFile);

return 0;

}

if(fread(pixels,total_bytes,1,pFile)<=0)

{

free(pixels);

fclose(pFile);

return 0;

}

{

GLint max;

glGetIntegerv(GL_MAX_TEXTURE_SIZE,&max);

if(!power_of_two(width)||!power_of_two(height)||width>max||height>max)

{

const GLint new_width = 1024;

const GLint new_height = 1024;

GLint new_total_bytes;

GLubyte *new_pixels = NULL;

new_total_bytes = (new_width*3+(4-new_width*3%4)%4)*new_height;

new_pixels = (GLubyte *)malloc(new_total_bytes);

if(new_pixels==NULL)

{

free(pixels);

fclose(pFile);

return 0;

}

gluScaleImage(GL_RGB,width,height,GL_UNSIGNED_BYTE,pixels,new_width,new_height,GL_UNSIGNED_BYTE,new_pixels);

free(pixels);

pixels = new_pixels;

width = new_width;

height = new_height;

}

}

glGenTextures(1,&texture_ID);

if(texture_ID==0)

{

free(pixels);

fclose(pFile);

return 0;

}

glGetIntegerv(GL_TEXTURE_BINDING_2D,(GLint *)&last_texture_ID);

glBindTexture(GL_TEXTURE_2D,texture_ID);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);

glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);

glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,width,height,0,GL_BGR_EXT,GL_UNSIGNED_BYTE,pixels);

glBindTexture(GL_TEXTURE_2D,last_texture_ID);

free(pixels);

fclose(pFile);

return texture_ID;

}

void ReadMtl(string mtlfile,map<string,Material> &mat)

{

ifstream in;

string line,word,ptname,ntname,fname;

unsigned map;

bool hasmap = false;

float ambient[3] = {0.0,0.0,0.0};

float diffuse[3] = {0.0,0.0,0.0};

float specular[3] = {0.0,0.0,0.0};

float emission[3] = {0.0,0.0,0.0};

in.open(mtlfile.c_str());

if(!in)

{

cout<<"Read mtl error !"<<endl;

return;

}

while(getline(in,line))

{

if(line.size()==0||line[0]=='#') continue;

istringstream is(line);

is>>word;

if(word=="newmtl")

{

is>>ntname;

if(!ptname.empty())

{

if(hasmap)

{

mat.insert(make_pair(ptname,Material(ambient,diffuse,specular,emission,map)));

}

else

{

mat.insert(make_pair(ptname,Material(ambient,diffuse,specular,emission,0)));

}

}

ptname = ntname;

hasmap = false;

}

else if(word=="Ka")

{

is>>ambient[0]>>ambient[1]>>ambient[2];

}

else if(word=="Kd")

{

is>>diffuse[0]>>diffuse[1]>>diffuse[2];

}

else if(word=="Ks")

{

is>>specular[0]>>specular[1]>>specular[2];

}

else if(word=="Ke")

{

is>>emission[0]>>emission[1]>>emission[2];

}

else if(word=="map_Ka")

{

is>>fname;

map = load_texture(fname.c_str());

hasmap = true;

}

}

if(!ntname.empty())

{

if(hasmap)

{

mat.insert(make_pair(ptname,Material(ambient,diffuse,specular,emission,map)));

}

else

{

mat.insert(make_pair(ptname,Material(ambient,diffuse,specular,emission,0)));

}

}

in.close();

}

void ReadObj(string file,map<string,Object> &m,set<string> &n)

{

ifstream in;

vector<VERTEX> vertexs;

vector< pair<float,float> > texcoords;

vector<VERTEX> normals;

vector<int> faces;

int row = 0,col = 0;

string line,word,goname,mtlname;

in.open(file.c_str());

if(!in)

{

cout<<"Read obj error !"<<endl;

exit(0);

}

while(getline(in,line))

{

if(line.size()==0||line[0]=='#') continue;

istringstream is(line);

is>>word;

if(word=="v")

{

VERTEX p;

is>>p.x>>p.y>>p.z;

vertexs.push_back(p);

}

else if(word=="vt")

{

pair<float,float> p;

is>>p.first>>p.second;

texcoords.push_back(p);

}

else if(word=="vn")

{

VERTEX p;

is>>p.x>>p.y>>p.z;

normals.push_back(p);

}

else if(word=="o"||word=="g")

{

if(!goname.empty()&&!faces.empty())

{

Object obj(vertexs.begin(),vertexs.end(),texcoords.begin(),texcoords.end(),normals.begin(),normals.end(),faces.begin(),faces.end(),row,col,mtlname);

while(n.count(goname)!=0)

{

goname+='0';

}

m.insert(make_pair(goname,obj));

n.insert(goname);

faces.clear();

}

is>>goname;

}

else if(word=="f")

{

int r = 0,c = 0;

while(is>>word)

{

c = count(word.begin(),word.end(),'/');

if(c==0)

{

faces.push_back(atoi(word.c_str()));

}

else if(c==1)

{

faces.push_back(atoi(string(word.begin(),word.begin()+word.find("/")).c_str()));

faces.push_back(atoi(string(word.begin()+word.find("/")+1,word.end()).c_str()));

}

else if(c==2)

{

int a = word.find("/");

int b = word.find("/",a+1);

faces.push_back(atoi(string(word.begin(),word.begin()+a).c_str()));

faces.push_back(atoi(string(word.begin()+a+1,word.begin()+b).c_str()));

faces.push_back(atoi(string(word.begin()+b+1,word.end()).c_str()));

}

++r;

}

row = r;

col = c+1;

}

else if(word=="mtllib")

{

is>>word;

ReadMtl(word,matname);

for(map<string,Material>::iterator it=matname.begin();it!=matname.end();++it)

{

cout<<it->first<<endl;

}

}

else if(word=="usemtl")

{

is>>mtlname;

}

}

if(!goname.empty()&&!faces.empty())

{

Object obj(vertexs.begin(),vertexs.end(),texcoords.begin(),texcoords.end(),normals.begin(),normals.end(),faces.begin(),faces.end(),row,col,mtlname);

while(n.count(goname)!=0)

{

goname+='0';

}

m.insert(make_pair(goname,obj));

n.insert(goname);

faces.clear();

}

in.close();

}

void myIdle()

{

Sleep(10);

glutPostRedisplay();

}

void myReshape(int width,int height)

{

aspect = (float)width/(height?height:1);

glViewport(0,0,width,height);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

gluPerspective(75,aspect,1,10000);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

gluLookAt(0,0,20,0,0,0,0,1,0);

}

void myKeyboard(unsigned char key,int x,int y)

{

switch(key)

{

case 's':

xpos -= (float)sin(heading*piover180) * 0.4f;

zpos -= (float)cos(heading*piover180) * 0.4f;

if (walkbiasangle >= 359.0f)

{

walkbiasangle = 0.0f;

}

else

{

walkbiasangle+= 10;

}

walkbias = (float)sin(walkbiasangle * piover180)/20.0f;

break;

case 'w':

xpos += (float)sin(heading*piover180) * 0.4f;

zpos += (float)cos(heading*piover180) * 0.4f;

if (walkbiasangle <= 1.0f)

{

walkbiasangle = 359.0f;

}

else

{

walkbiasangle-= 10;

}

walkbias = (float)sin(walkbiasangle * piover180)/20.0f;

break;

case 'd':

yrot += 5.0f;

break;

case 'a':

yrot -= 5.0f;

break;

}

}

void myMouse(int button,int state,int x,int y)

{

if(button==GLUT_DOWN) MouseDown = 1,mx = x,my = y;

else if(button==GLUT_WHEEL_UP)

{

dz+=1.0f;

}

else if(button==GLUT_WHEEL_DOWN)

{

dz-=1.0f;

}

else

{

MouseDown = 0;

}

}

void myMotion(int x,int y)

{

if(MouseDown)

{

ax += (y-my)/5.0f;

ay += (x-mx)/5.0f;

mx = x;

my = y;

}

}

void setLight()

{

static const GLfloat light_position[] = {50.0f,50.0f,50.0f,0.0f};

static const GLfloat light_ambient[] = {0.0f,0.0f,0.0f,0.0f};

static const GLfloat light_diffuse[] = {0.5f,0.5f,0.5f,0.0f};

static const GLfloat light_specular[] = {1.0f,1.0f,1.0f,0.0f};

static const GLfloat light_direction[] = {0.0f,0.0f,-1.0f};

glLightfv(GL_LIGHT0,GL_POSITION,light_position);

glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);

glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);

glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);

glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,light_direction);

glLightf(GL_LIGHT0,GL_SPOT_EXPONENT,10.0f);

glLightf(GL_LIGHT0,GL_SPOT_CUTOFF,90.0f);

glEnable(GL_LIGHT0);

glEnable(GL_LIGHTING);

glEnable(GL_DEPTH_TEST);

}

void setMaterial(Material &mat)

{

glMaterialfv(GL_FRONT,GL_AMBIENT,mat.ambient);

glMaterialfv(GL_FRONT,GL_DIFFUSE,mat.diffuse);

glMaterialfv(GL_FRONT,GL_SPECULAR,mat.specular);

glMaterialfv(GL_FRONT,GL_EMISSION,mat.emission);

glMaterialf(GL_FRONT,GL_SHININESS,0.0);

}

void myDisplay()

{

static int c = 0;

static clock_t pre = 0;

static clock_t now = 0;

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

//把用户操作引起的视角变化转化为以以游戏者为中心对场景的移动和旋转

GLfloat xtrans = -xpos; // 用于游戏者沿X轴平移时的大小

GLfloat ztrans = -zpos; // 用于游戏者沿Z轴平移时的大小

GLfloat ytrans = -walkbias-0.25f; // 用于头部的上下摆动

GLfloat sceneroty = 360.0f - yrot; // 位于游戏者方向的360度角

glPushMatrix();

glRotatef(20.0f,1.0f,0.0f,0.0f);

glRotatef(sceneroty,0.0f,1.0f,0.0f);

glTranslatef(0.0,1.5,0.0);

glTranslatef(0.0,0.0,2.0);

glTranslatef(xtrans, ytrans, ztrans);

glScalef(0.3,0.3,0.3);

for(set<string>::iterator it=objname1.begin();it!=objname1.end();++it)

{

Object temp = objmap1[*it];

setMaterial(matname[temp.material]);

glBindTexture(GL_TEXTURE_2D,matname[temp.material].map);

if(temp.row==3) glBegin(GL_TRIANGLES);

else glBegin(GL_QUADS);

vector<int>::iterator iter = temp.faces.begin();

if(temp.col==1)

{

while(iter!=temp.faces.end())

{

glVertex3f(temp.vertexs[*iter-1].x,temp.vertexs[*iter-1].y,temp.vertexs[*iter-1].z);

++iter;

}

}

else if(temp.col==2)

{

while(iter!=temp.faces.end())

{

glTexCoord2f(temp.texcoords[*(iter+1)-1].first,temp.texcoords[*(iter+1)-1].second);

glVertex3f(temp.vertexs[*iter-1].x,temp.vertexs[*iter-1].y,temp.vertexs[*iter-1].z);

iter+=2;

}

}

else if(temp.col==3&&!temp.texcoords.empty())

{

while(iter!=temp.faces.end())

{

glNormal3f(temp.normals[*(iter+2)-1].x,temp.normals[*(iter+2)-1].y,temp.normals[*(iter+2)-1].z);

glTexCoord2f(temp.texcoords[*(iter+1)-1].first,temp.texcoords[*(iter+1)-1].second);

glVertex3f(temp.vertexs[*iter-1].x,temp.vertexs[*iter-1].y,temp.vertexs[*iter-1].z);

iter+=3;

}

}

else

{

while(iter!=temp.faces.end())

{

glNormal3f(temp.normals[*(iter+2)-1].x,temp.normals[*(iter+2)-1].y,temp.normals[*(iter+2)-1].z);

glVertex3f(temp.vertexs[*iter-1].x,temp.vertexs[*iter-1].y,temp.vertexs[*iter-1].z);

iter+=3;

}

}

glBindTexture(GL_TEXTURE_2D,0);

glEnd();

}

if(c%50==0)

{

now = clock();

cout<<now-pre<<endl;

pre = now;

}

glPopMatrix();

glPushMatrix();

glRotatef(20.0,1.0,0.0,0.0);

glTranslatef(0.0,0.0,5.0);

glTranslatef(xpos,0.0,zpos);

glRotatef(-sceneroty,0.0,1.0,0.0);

glScalef(0.008,0.008,0.008);

for(set<string>::iterator it2=objname2.begin();it2!=objname2.end();++it2)

{

Object temp = objmap2[*it2];

setMaterial(matname[temp.material]);

glBindTexture(GL_TEXTURE_2D,matname[temp.material].map);

if(temp.row==3) glBegin(GL_TRIANGLES);

else glBegin(GL_QUADS);

vector<int>::iterator iter = temp.faces.begin();

if(temp.col==1)

{

while(iter!=temp.faces.end())

{

glVertex3f(temp.vertexs[*iter-1].x,temp.vertexs[*iter-1].y,temp.vertexs[*iter-1].z);

++iter;

}

}

else if(temp.col==2)

{

while(iter!=temp.faces.end())

{

glTexCoord2f(temp.texcoords[*(iter+1)-1].first,temp.texcoords[*(iter+1)-1].second);

glVertex3f(temp.vertexs[*iter-1].x,temp.vertexs[*iter-1].y,temp.vertexs[*iter-1].z);

iter+=2;

}

}

else if(temp.col==3&&!temp.texcoords.empty())

{

while(iter!=temp.faces.end())

{

glNormal3f(temp.normals[*(iter+2)-1].x,temp.normals[*(iter+2)-1].y,temp.normals[*(iter+2)-1].z);

glTexCoord2f(temp.texcoords[*(iter+1)-1].first,temp.texcoords[*(iter+1)-1].second);

glVertex3f(temp.vertexs[*iter-1].x,temp.vertexs[*iter-1].y,temp.vertexs[*iter-1].z);

iter+=3;

}

}

else

{

while(iter!=temp.faces.end())

{

glNormal3f(temp.normals[*(iter+2)-1].x,temp.normals[*(iter+2)-1].y,temp.normals[*(iter+2)-1].z);

glVertex3f(temp.vertexs[*iter-1].x,temp.vertexs[*iter-1].y,temp.vertexs[*iter-1].z);

iter+=3;

}

}

glBindTexture(GL_TEXTURE_2D,0);

glEnd();

}

if(c%50==0)

{

now = clock();

cout<<now-pre<<endl;

pre = now;

}

glPopMatrix();

glutSwapBuffers();

sy = (sy + 2)%360;

++c;

}

void init()

{

glEnable(GL_TEXTURE_2D);

ReadObj("redcar.obj",objmap1,objname1);

ReadObj("f1road2.obj",objmap2,objname2);

glClearColor(0.5,0.5,0.5,1.0);

glEnable(GL_DEPTH_TEST);

glShadeModel(GL_SMOOTH);

glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

setLight();

}

int main(int argc,char **argv)

{

glutInit(&argc,argv);

glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE);

glutInitWindowPosition(50,50);

glutInitWindowSize(640,480);

glutCreateWindow("赛车游戏 前进W 后退S 左移A 右移D ");

glutReshapeFunc(&myReshape);

glutKeyboardFunc(&myKeyboard);

glutMouseFunc(&myMouse);

glutMotionFunc(&myMotion);

glutDisplayFunc(&myDisplay);

glutIdleFunc(&myIdle);

init();

glutMainLoop();

return 0;

}

.h代码

/*********************************************************

object.h by gameloftyou

use for obj model

*********************************************************/

#ifndef OBJECT_H_INCLUDED

#define OBJECT_H_INCLUDED

#include <utility>

#include <vector>

#include <string>

typedef struct

{

float x;

float y;

float z;

} VERTEX;

class Object {

public:

typedef std::vector<VERTEX>::iterator viter;

typedef std::vector< std::pair<float,float> >::iterator titer;

typedef std::vector<VERTEX>::iterator niter;

typedef std::vector<int>::iterator fiter;

Object(viter vbeg,viter vend,titer tbeg,titer tend,niter nbeg,niter nend,fiter fbeg,fiter fend,int r,int c,std::string mat)

:vertexs(vbeg,vend),texcoords(tbeg,tend),normals(nbeg,nend),faces(fbeg,fend),row(r),col(c),material(mat){}

Object(){}

std::vector<VERTEX> vertexs;

std::vector< std::pair<float,float> > texcoords;

std::vector<VERTEX> normals;

std::vector<int> faces;

std::string material;

int row,col;

};

class Material {

public:

Material(float *a,float *d,float *s,float *e,unsigned m)

{

ambient[0] = *a;

ambient[1] = *(a+1);

ambient[2] = *(a+2);

ambient[3] = 0;

diffuse[0] = *d;

diffuse[1] = *(d+1);

diffuse[2] = *(d+2);

diffuse[3] = 0;

specular[0] = *s;

specular[1] = *(s+1);

specular[2] = *(s+2);

specular[3] = 0;

emission[0] = *e;

emission[1] = *(e+1);

emission[2] = *(e+2);

emission[3] = 0;

map = m;

}

Material()

{

ambient[0] = 0;

ambient[1] = 0;

ambient[2] = 0;

ambient[3] = 0;

diffuse[0] = 1.0;

diffuse[1] = 1.0;

diffuse[2] = 1.0;

diffuse[3] = 0;

specular[0] = 1.0;

specular[1] = 1.0;

specular[2] = 1.0;

specular[3] = 0;

emission[0] = 0;

emission[1] = 0;

emission[2] = 0;

emission[3] = 0;

map = 0;

}

float ambient[4];

float diffuse[4];

float specular[4];

float emission[4];

unsigned map;

};

#endif

学习了很久,大概有了个模子,这里导入了两个模型,能够运动起来,但是其中redcar的运动还不是很规范,这里正在改进。作为一个月的总结,也是理顺一下思路。

还有计时器、碰撞等都还在学习中。还请大家指导,谢谢~呵呵~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: