两个礼拜之前,李凤霞老师又布置了一次虚拟现实作业,这次的作业题目是自己从网上找一个汽车的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);这个函数中实现的,具体也不深究了,做完这一次后还有最后一次作业,希望不要太难。