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的运动还不是很规范,这里正在改进。作为一个月的总结,也是理顺一下思路。
还有计时器、碰撞等都还在学习中。还请大家指导,谢谢~呵呵~
/*********************************************************
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的运动还不是很规范,这里正在改进。作为一个月的总结,也是理顺一下思路。
还有计时器、碰撞等都还在学习中。还请大家指导,谢谢~呵呵~
相关文章推荐
- 将YCB模型库中的obj格式文件导入VREP并保存为ttm文件
- OpenGL - obj文件的导入
- Opengl中导入obj文件
- OpenGL 导入obj文件
- Glade两种布局文件格式GtkBuilder和Libglade在python中的导入代码
- 用MR生成HFile文件格式后,数据批量导入HBase
- ArcGIS教程:已知经纬度坐标导入ArcMap生成shp格式文件
- .obj文件格式与.mtl文件格式
- 3D模型-OBJ材质文件 MTL格式分析
- MySQL如何导入csv格式数据文件解决方案
- 使用PHPExcel导入导出excel格式文件
- CSV格式文件向安卓小米手机中导入通讯录
- opengl关于obj文件相关知识
- Access导入文本文件的Schema.ini文件格式
- OBJ文件格式详解
- opengl导入3DS文件(带纹理)之填坑
- YAML的Java实现——JYAML基本原理与示例(2)导入YAML格式文件
- [导入]解决打开CHM格式文件出现“网页不能浏览”错误的方法
- 3D模型文件格式之OBJ详解
- 3D中的OBJ文件格式详解