实验11— 交互的3D漫游世界

一、实验目的

1.进一步掌握3D编程概念
2.主要掌握视点和目标的改变对场景生成的影响
3.掌握3D漫游场景的基本技巧

二、实验内容

附属程序rotating_torus.cpp为一视点保持不变的3D旋转程序,3D场景为一个圆环、一个小球和一个以四边形为基本单位的方块墙包围盒,且小球和圆环在“方块墙”的包围盒中。视点设在正前方观察物体,小球和圆环一起绕着环心某处不停旋转不停旋转。
添加键盘响应函数,使得:
1)按键盘的”W”,”S”键,可实现视点前后移动(直走前进倒退);(此时应该视点与目标点的距离保持不变,且视线方向保持不变)。
2)按键盘的”A”,”D”键,可实现视点左右旋转左看右看;(此时应该视点固定,目标点围绕视点旋转,视点与目标点的距离仍然保持不变)。
3)视点左右旋转一定角度后,再按键盘的”W”,”S”键仍可实现视线直走,即沿着旋转后的视线方向行走。
4)程序修改后观看效果,并用键盘验证。在实验报告中写出前后直走和左转右转的关键点和核心代码。
代码修改:

void mykeyboard(unsigned char key,int x,int y){
    
    //重点在于视点和目标点的变化Y坐标不变化
	switch(key){
    
    
		case 'W':
		case 'w'://向前直走
			//代码
			eyex=eyex-step*sin(angle*PI/180.0);
			eyez=eyez-step*cos(angle*PI/180.0);
			atx=atx-step*sin(angle*PI/180.0);
			atz=atz-step*cos(angle*PI/180.0);
			break;
		case 'S':
		case 's'://向后退
			//代码
			eyex=eyex+step*sin(angle*PI/180.0);
			eyez=eyez+step*cos(angle*PI/180.0);
			atx=atx+step*sin(angle*PI/180.0);
			atz=atz+step*cos(angle*PI/180.0);
			break;
		case 'A':
		case 'a'://左看
			//代码
			angle+=1;
			atx=eyex-x*sin(angle*PI/180.0);
			atz=eyez-x*cos(angle*PI/180.0);
			break;
		case 'D':
		case 'd'://右看
			//代码
			angle-=1;
			atx=eyex-x*sin(angle*PI/180.0);
			atz=eyez-x*cos(angle*PI/180.0);
			break;
	}
	glutPostRedisplay();//参数修改后调用重画函数,屏幕图形将发送改变
} 

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
5)如果圆环中心要加一个不断自转的茶壶,代码如何实现?将效果截图、核心代码粘贴到实验报告中。
代码修改:
加在void drawsphere()中最后;

glPushMatrix();
	glColor3f(0,0,1);
	glTranslatef(0,0,0);
	glRotatef(theta,1,0,0);
	glTranslatef(0,0,0);
	glutWireTeapot(30);
	glPopMatrix();

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
6)修改场景,在场景既定的位置增加自己相要的3D物体,将效果截图、核心代码粘贴到实验报告中。
修改:

void drawsphere(){
    
    
	float tr;
	tr=(outer+3*inner);
	glRotatef(theta,0,1,0);
	glPushMatrix();
	 glPushMatrix();
	  glColor3f(1.0,0,0);
	  glRotatef(90,1,0,0);
	  glutWireTorus(inner,outer,30,50);
	 glPopMatrix();

	 glPushMatrix();
	 glColor3f(1.0,1,0);
	 glRotatef(45,1,0,0);
	 glutWireTorus(inner,outer-40,30,50);
	 glPopMatrix();
	 glPushMatrix();
	 glColor3f(0,1,0.5);
	  glRotatef(-45,1,0,0);
	  glutWireTorus(inner,outer-60,30,50);
	  glPopMatrix();

	  glPushMatrix();
	  glColor3f(0,1,0.5);
	  glRotatef(-45,1,0,0);
	  glutWireTorus(inner,outer-60,30,50);
	  glPopMatrix();

	  glPushMatrix();
	  glColor3f(1.0,0,1.0);
	  glutWireTorus(inner-20,outer-20,30,50);
	  glPopMatrix();

	  glPushMatrix();//小球饶outer点转,其实是x=outer这条相对于Y的轴
	  glTranslatef(outer,0,0);
	  glRotatef(theta,0,1,0);
	  glTranslatef(-outer,0,0);

	  glPushMatrix();//画小球,饶x轴转
	  glTranslatef(tr,0,0);
	  glRotatef(-45,1,0,0);
	  glColor3f(0.0,1.0,0);
	  glutSolidIcosahedron();
	  glPopMatrix();
	  glPopMatrix();
	  glPopMatrix();

	glPushMatrix();
	glColor3f(0,0,1);
	glTranslatef(0,0,0);
	glRotatef(theta,1,0,0);
	glTranslatef(0,0,0);
	glScalef(10,10,10);
	glutWireSphere(inner,20,20);
	glPopMatrix();
}

在这里插入图片描述
在这里插入图片描述

三、思考题

1.透视投影函数中远裁剪平面离相机的距离在本例中为何设为2outer8inner250 有何依据?
答:gluperspective(90,w/h,10,2outer+8inner+250);远裁剪平面离相机(视点)的距离为2outer8inner250,而s=outer+4*inner+50;远裁剪平面到视点的距离,至少比眼睛到目标点的距离2倍大,这样才能使物体在旋转过程中都在整个窗口中显示。
2.如果用鼠标移动(鼠标坐标为二维坐标)来进行左右上下拖拽整个场景(三维世界坐标),程序又如何修改?
答:如果这个场景是二维的,将z轴有关j的设定都改为y轴。
3.在此基础上再实现镜头的放大缩小,俯视等,程序应该如何修改?
答:通过改变投影变换矩阵实现。

四、函数参考

参考实验九和实验十。

五、演示程序

//3D_Rota
#include "Shiyan11-1.h"
#include "stdafx.h"
#include <math.h>
#include <gl/glut.h>
#include "stdafx.h"
#define PI 3.14159
float theta=-90;
int inner=10,outer=80;
float s=outer+4*inner+50;
float eyex=0,eyey=0,eyez=s;
float atx=0,aty=0,atz=0;
int ww,hh;
bool flag=true;
double angle=0;//漫游移动旋转角
float step=0.1*s;//步长为视点到目标点的距离
void display(void);
void reshape(int w,int h);
void mytime(int value);
void drawground();
void drawsphere();
void drawwall();
void init();
void mykeyboard(unsigned char key,int x, int y);
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow){
    
    
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);
	char* argv[] = {
    
     (char*)"hello ",(char*)" " };
	int argc = 2;		//argv中的字符串数
	glutInit(&argc, argv);  //初始化GLUT库
	glutInitWindowSize(800, 800);                       //设置显示窗口大小 
	int sheight = glutGet(GLUT_SCREEN_WIDTH);
	int swidth = glutGet(GLUT_SCREEN_HEIGHT);
	glutInitWindowPosition(sheight / 2 - 400, swidth / 2 - 400);  //窗口左上角在屏幕的位置
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);        //设置显示模式(注意双缓存 )
	glutCreateWindow("Rotating 3D world");						
	glutReshapeFunc(reshape); 
	init();						
	glutDisplayFunc(display);                           //用于绘制当前窗口
	glutKeyboardFunc(mykeyboard);
	glutTimerFunc(100,mytime,10);
	glutMainLoop();                                     //开始运行程序
	return 0;
}
void init() {
    
    
	glClearColor(1,1,1,1);
	glPixelStorei(GL_PACK_ALIGNMENT,1);
	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 
}
void mykeyboard(unsigned char key,int x,int y){
    
    //重点在于视点和目标点的变化Y坐标不变化
	switch(key){
    
    
		case 'W':
		case 'w'://向前直走
			//代码
			eyex=eyex-step*sin(angle*PI/180.0);
			eyez=eyez-step*cos(angle*PI/180.0);
			atx=atx-step*sin(angle*PI/180.0);
			atz=atz-step*cos(angle*PI/180.0);
			break;
		case 'S':
		case 's'://向后退
			//代码
			eyex=eyex+step*sin(angle*PI/180.0);
			eyez=eyez+step*cos(angle*PI/180.0);
			atx=atx+step*sin(angle*PI/180.0);
			atz=atz+step*cos(angle*PI/180.0);
			break;
		case 'A':
		case 'a'://左看
			//代码
			angle+=1;
			atx=eyex-x*sin(angle*PI/180.0);
			atz=eyez-x*cos(angle*PI/180.0);
			break;
		case 'D':
		case 'd'://右看
			//代码
			angle-=1;
			atx=eyex-x*sin(angle*PI/180.0);
			atz=eyez-x*cos(angle*PI/180.0);
			break;
	}
	glutPostRedisplay();//参数修改后调用重画函数,屏幕图形将发送改变
}
void display(void) {
    
    
	glClear(GL_COLOR_BUFFER_BIT); 
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(eyex,eyey,eyez,atx,aty,atz,0,1,0);
	glPushMatrix();
	glColor3f(0,0,1);
	drawwall();
	glColor3f(1,0,0);
	drawground();
	drawsphere();
	glPopMatrix();
	glutSwapBuffers();
}
void drawsphere(){
    
    
	float tr;
	tr=(outer+3*inner);
	glRotatef(theta,0,1,0);
	glPushMatrix();
	 glPushMatrix();
	  glColor3f(1.0,0,0);
	  glRotatef(90,1,0,0);
	  glutWireTorus(inner,outer,30,50);
	 glPopMatrix();

	 glPushMatrix();
	 glColor3f(1.0,1,0);
	 glRotatef(45,1,0,0);
	 glutWireTorus(inner,outer-40,30,50);
	 glPopMatrix();
	 glPushMatrix();
	 glColor3f(0,1,0.5);
	  glRotatef(-45,1,0,0);
	  glutWireTorus(inner,outer-60,30,50);
	  glPopMatrix();

	  glPushMatrix();
	  glColor3f(0,1,0.5);
	  glRotatef(-45,1,0,0);
	  glutWireTorus(inner,outer-60,30,50);
	  glPopMatrix();

	  glPushMatrix();
	  glColor3f(1.0,0,1.0);
	  glutWireTorus(inner-20,outer-20,30,50);
	  glPopMatrix();

	  glPushMatrix();//小球饶outer点转,其实是x=outer这条相对于Y的轴
	  glTranslatef(outer,0,0);
	  glRotatef(theta,0,1,0);
	  glTranslatef(-outer,0,0);

	  glPushMatrix();//画小球,饶x轴转
	  glTranslatef(tr,0,0);
	  glRotatef(-45,1,0,0);
	  glColor3f(0.0,1.0,0);
	  glutSolidIcosahedron();
	  glPopMatrix();
	  glPopMatrix();
	  glPopMatrix();
	glPushMatrix();
	glColor3f(0,0,1);
	glTranslatef(0,0,0);
	glRotatef(theta,1,0,0);
	glTranslatef(0,0,0);
	glScalef(10,10,10);
	glutWireSphere(inner,20,20);
	glPopMatrix();
}
void drawground(){
    
    
	//ground
	for(int i=-outer-4*inner;i<outer+4*inner;i+=2*inner)
		for(int j=-outer-4*inner;j<outer+4*inner;j+=2*inner){
    
    
			glBegin(GL_QUADS);
			  glVertex3d(j,-outer-4*inner,i);
			  glVertex3d(j,-outer-4*inner,i+2*inner);
			  glVertex3d(j+2*inner,-outer-4*inner,i+2*inner);
			  glVertex3d(j+2*inner,-outer-4*inner,i);
			glEnd();
		}
	//top
	for(int i=-outer-4*inner;i<outer+4*inner;i+=2*inner)
		for(int j=-outer-4*inner;j<outer+4*inner;j+=2*inner){
    
    
			glBegin(GL_QUADS);
			  glVertex3d(j,outer+4*inner,i);
			  glVertex3d(j,outer+4*inner,i+2*inner);
			  glVertex3d(j+2*inner,outer+4*inner,i+2*inner);
			  glVertex3d(j+2*inner,outer+4*inner,i);
			glEnd();
		}
}
void drawwall(){
    
    
	int i,j;
	glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
	//left
	for(i=-outer-4*inner;i<outer+4*inner;i+=2*inner)
		for(j=-outer-4*inner;j<outer+4*inner;j+=2*inner){
    
    
			glBegin(GL_QUADS);
			  glVertex3d(-outer-4*inner,j,i);
			  glVertex3d(-outer-4*inner,j+2*inner,i);
			  glVertex3d(-outer-4*inner,j+2*inner,i+2*inner);
			  glVertex3d(-outer-4*inner,j,i+2*inner);
			glEnd();
		}
	//right
	for(i=-outer-4*inner;i<outer+4*inner-2*inner;i+=2*inner)
		for(j=-outer-4*inner;j<outer+4*inner-2*inner;j+=2*inner){
    
    
			glBegin(GL_QUADS);
			  glVertex3d(outer+4*inner,j,i);
			  glVertex3d(outer+4*inner,j+2*inner,i);
			  glVertex3d(outer+4*inner,j+2*inner,i+2*inner);
			  glVertex3d(outer+4*inner,j,i+2*inner);
			glEnd();
		}
			glColor3f(1,1,0);
	//front
	for(i=-outer-4*inner;i<outer+4*inner-2*inner;i+=2*inner)
		for(j=-outer-4*inner;j<outer+4*inner-2*inner;j+=2*inner){
    
    
			glBegin(GL_QUADS);
			  glVertex3d(j,i,-outer-4*inner);
			  glVertex3d(j+2*inner,i,-outer-4*inner);
			  glVertex3d(j+2*inner,i+2*inner,-outer-4*inner);
			  glVertex3d(j,i+2*inner,-outer-4*inner);
			glEnd();
		}
}
void mytime(int value){
    
    
	theta+=0.5;
	if(theta>360)theta=-360;
	glutPostRedisplay();
	glutTimerFunc(100,mytime,10);
}
void reshape(GLsizei w, GLsizei h) {
    
    
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(90, w / h, 10, 2*outer+8*inner+250); //定义透视投影投影观察体大小
	glViewport(0, 0, w, h);
	glMatrixMode(GL_MODELVIEW);
	ww=w;
	hh=h;
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_52030647/article/details/130730105