两个礼拜之前,李凤霞老师又布置了一次虚拟现实作业,这次的作业题目是自己从网上找一个汽车的3D模型(一般都是3D Max建的),然后把这个模型导入到OpenGL中,在工程中显示出来,同时能通过鼠标的移动切换视角。由于时间太紧(矩阵分析要考试),这个作业就拜托了宿舍的一个同学,可是没想到最后还是自己做了,就这样也学了点东西(不过不知道有什么用)。
先贴下实现效果,车辆是网上找的一个奥迪Q7 3D模型,为了简单不再贴纹理了
下面说下实现步骤:
1、转换3D Max模型
3D MAX建模后生成的一般都是3ds后缀的文件,直接导入貌似还要在opengl中建立对应的数据结构,上网查了一些资料后,我发现可以用View3D软件把3DS文件转换成.h和.gl两个文件,然后把这两个文件拷贝到工程目录下http://hi.baidu.com/chyrcpxjpxbcege/item/3fe0cd59f170af3e32e0a919 给出了其他的一些导入方法
2、添加头文件和初始化
把.h文件添加到工程中去后,在.h文件中加入一个新的类用以导入
class CModernho { public: CModernho(void); public: ~CModernho(void); public: long ScanBytes(int pixWidth, int bitsPixel); void MyMaterial(GLenum mode, GLfloat * f, GLfloat alpha); void SelectMaterial(int i); GLint Gen3DObjectList(); }; CModernho::CModernho(void) { } CModernho::~CModernho(void) { }
然后在主文件中添加对应的内容
开头定义一个变量,应该对应导入的数目
int listnum;//导入变量
在main函数中初始化时载入该模型
CModernho cmodernho; listnum = GL3DS_initialize_audi(); //载入audi
最后在渲染函数中调用该模型
glCallList(listnum);// 调用载入函数
这样就得到了以上的效果,工程结构如下:
audi.h就是view3d转换后的文件,很长,其中包含很多点线的信息,显然是把模型的各个点和线都保存下来了
testcar.cpp代码如下:
#include <gl/glaux.h> #include <gl/glu.h> #include <GL/glut.h> #include "math.h" #include <stdio.h> #include"audi.h" int flag=1; double front_Point_x,front_Point_y,front_Point_z; double pos_Up[3],pos_Down[3],pos_Motion[3]; double viewmatrix[16],modelviewmatrix[16]; #define GLUT_MIDDLE_UP_BUTTON 0x0003 #define GLUT_MIDDLE_DOWN_BUTTON 0x0004 float PI = 3.141592654; int listnum;//导入变量 GLfloat xangle = 0.0; GLfloat yangle = 0.0; GLfloat oDistance = 5.0; int cacheX = 0; int cacheY = 0; int xSpeed = 1; int ySpeed = 1; BOOL light=true; // 光源的开/关 BOOL lp=true; // L键按下了么? GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f }; //环境光参数 GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f }; // 漫射光参数 GLfloat LightPosition[]= { 0.0f, 0.0f, 2.0f, 1.0f }; // 光源位置 void motion(int x, int y) //鼠标响应事件 { if (x > cacheX) { yangle = yangle - xSpeed; } if (x < cacheX) { yangle = yangle + xSpeed; } if (y > cacheY) { xangle = xangle + ySpeed; } if (y < cacheY) { xangle = xangle - ySpeed; } glutPostRedisplay(); cacheX = x; cacheY = y; } void setView() //设置观察角度 { glRotatef(10,1.0,0.0,0.0); glRotatef(22,0.0,1.0,0.0); glTranslatef(-20.5,-10.0,-55.0); glGetDoublev(GL_MODELVIEW_MATRIX,viewmatrix); } void SetRC() //设置渲染 { glEnable (GL_LINE_SMOOTH); glEnable (GL_BLEND); glShadeModel(GL_FLAT); glFrontFace(GL_CW); glEnable (GL_LINE_SMOOTH); glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glHint(GL_LINE_SMOOTH,GL_NICEST); glEnable(GL_DEPTH_TEST); glPolygonMode(GL_BACK,GL_LINE); glEnable( GL_COLOR_MATERIAL); } void renderWorld() //模拟场景 { glFrontFace(GL_CCW); glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); float oXhudu = PI / (180 / xangle); //沿着X轴旋转的角度 float oYhudu = PI / (180 / yangle); //沿着Y轴旋转的角度 //设置场景坐标 GLfloat btm = oDistance * cos(oXhudu); GLfloat vpY = oDistance * sin(oXhudu); GLfloat vpX = btm * sin(oYhudu); GLfloat vpZ = btm * cos(oYhudu); if (fabs(xangle) < 90.0) { gluLookAt(vpX, vpY, vpZ, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); } else { if (fabs(xangle) >= 270.0) { if (fabs(xangle) >= 360.0) { xangle = 0.0; } gluLookAt(vpX, vpY, vpZ, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); } else { gluLookAt(vpX, vpY, vpZ, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0); } } if (fabs(yangle) >= 360.0) { yangle = 0; } //绘制场景坐标轴 glLineWidth(1); glBegin(GL_LINES); glColor3f(1.0,0.0,0.0); glVertex3f(0.0,0.0,0.0); glVertex3f(200,0,0); glColor3f(0.0,1.0,0.0); glVertex3f(0.0,0.0,0.0); glVertex3f(0.0,200,0.0); glColor3f(0.0,0.0,1.0); glVertex3f(0.0,0.0,0.0); glVertex3f(0.0,0.0,200.0); glEnd(); glColor3f(0.3,0.5,0.1); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glGetDoublev(GL_MODELVIEW_MATRIX,modelviewmatrix); glCallList(listnum);// 调用载入函数 } void myDisplay(void) { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glClearColor(0.1,0.1,0.1,0.1); glPushMatrix(); setView(); renderWorld(); glPopMatrix(); glutSwapBuffers(); } void myReshape(int w,int h) //重新绘制场景 { GLfloat nRange = 100.0f; glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if(w<=h) //建立裁剪区域(左右下上近远) { glOrtho(-nRange,nRange,-nRange*h/w,nRange*h/w,-100,100); } else { glOrtho(-nRange*w/h,nRange*w/h,-nRange,nRange,-100,100); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void mouse(int btn, int state, int x, int y) { if(btn==GLUT_RIGHT_BUTTON ) { if(state == GLUT_DOWN) { if(light) { glDisable(GL_LIGHT1); // 启用光源 light=!light; } else { glEnable(GL_LIGHT1); light=!light; } } } glutPostRedisplay();//重新加载 } int main(int argc, char *argv[]) //主函数 { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE|GLUT_DEPTH); glutInitWindowPosition(10, 10); glutInitWindowSize(800, 800); glutCreateWindow("VR-2"); glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // 设置环境光 glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // 设置漫射光 glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // 光源位置 glEnable(GL_LIGHT1); // 启用光源 CModernho cmodernho; listnum = GL3DS_initialize_audi(); //载入audi glutDisplayFunc(&myDisplay); glutReshapeFunc(&myReshape); SetRC(); glutMouseFunc(mouse); glutMotionFunc(&motion); glutMainLoop(); return 0; }
至于鼠标控制完全不会,抄了一个同学的代码,不过我知道鼠标响应是在glutMotionFunc(&motion);这个函数中实现的,具体也不深究了,做完这一次后还有最后一次作业,希望不要太难。