一、实验目的
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;
}