1. 程式人生 > >北理工虛擬現實作業-OpenGL下實現3D Max模型的匯入

北理工虛擬現實作業-OpenGL下實現3D Max模型的匯入

兩個禮拜之前,李鳳霞老師又佈置了一次虛擬現實作業,這次的作業題目是自己從網上找一個汽車的3D模型(一般都是3D Max建的),然後把這個模型匯入到OpenGL中,在工程中顯示出來,同時能通過滑鼠的移動切換視角。由於時間太緊(矩陣分析要考試),這個作業就拜託了宿舍的一個同學,可是沒想到最後還是自己做了,就這樣也學了點東西(不過不知道有什麼用)。

先貼下實現效果,車輛是網上找的一個奧迪Q7 3D模型,為了簡單不再貼紋理了

下面說下實現步驟:

1、轉換3D Max模型

3D MAX建模後生成的一般都是3ds字尾的檔案,直接匯入貌似還要在opengl中建立對應的資料結構,上網查了一些資料後,我發現可以

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);這個函式中實現的,具體也不深究了,做完這一次後還有最後一次作業,希望不要太難。