一、实验目的
1.进一步掌握3D编程概念。
2.主要掌握视点和目标的改变对场景生成产生的影响。
3.掌握3D漫游场景的基本技巧。
二、实验内容
附属程序Rotating_World.exe为一视点不变的3D旋转程序,3D场景为一个圆环、一个小球和一个以四边形为基本单位的方块盒包围墙,且小球和圆环在“方块墙”的包围盒中。视点设在正前方观察物体,且小球和圆环一起绕着环心不停旋转,如图:
实验图11-1 旋转的3D世界
添加键盘响应函数,使得:
1)按键盘的“W”、“S”键,可实现视点的前后移动(直走:前进或倒退)(此时应该视点与目标点的距离保持不变,且视线方向保持不变)。
2)按键盘的“A”、“D”键,可实现视点的左右移动(左看右看)(此时应该视点固定,目标点围绕视点旋转,视点与目标点的距离仍然保持不变)。
3)视点左右旋转一定角度后,再按键盘的“W”“S”键仍可实现视线直走,即沿着旋转后的视线方向行走。
4)程序修改后观看效果,并用键盘验证。在实验报告中写出前后直走和左转右转的关键点和核心代码。
5)如果圆环中心要加一个不断自转的茶壶,代码如何实现?将效果截图、核心代码粘贴到实验报告中。(下为转换视角和前后移动效果图)
答:在display()里的darwsphere();后面加一个绘制茶壶函数glutWireTeapot(20);就行了
6)在场景既定的位置增加自己想要的3D物体,将效果截图、核心代码粘贴到实验报告中。
答:添加了正四面体,见上图。
三、思考题
1.透视投影函数中远裁剪平面离相机的距离在本例中为何设为:2*outer+8*inner+250?有何依据?
答:此距离可以保证全部场景与视角相当。
答:添加鼠标操作相关函数:
float du = 90, oldmy = -1, oldmx = -1;
float r = s, h = 0;
void Mouse(int button, int state, int x, int y)
{
if (state == GLUT_DOWN)
oldmx = x, oldmy = y;
}
void onMouseMove(int x, int y)
{
du += x - oldmx;
h += y - oldmy;
oldmx = x, oldmy = y;
eyex = r * cos(du*PI/180);
eyez = r * sin(du*PI/180);
eyey = h;
}
3.在此基础上再实现镜头的放大、缩小、俯视等,程序应该如何修改?
答:添加键盘操作相关函数(Z缩小,X放大):
case 'Z':
case 'z'://缩小
if (eyex > 0) eyex++;
else if (eyex < 0) eyex--;
if (eyey > 0) eyey++;
else if (eyey < 0) eyey--;
if (eyez > 0) eyez++;
else if (eyez < 0) eyez--;
break;
case 'X':
case 'x'://放大
if (eyex > 0) eyex--;
else if (eyex < 0) eyex++;
if (eyey > 0) eyey--;
else if (eyey < 0) eyey++;
if (eyez > 0) eyez--;
else if (eyez < 0) eyez++;
break;
}
四、函数参考
参考实验九和实验十。
五、演示程序
3D_Rotating_World.exe。
六、课后加分题
在场景内,靠近视点的视线方向前面放置一个小机器人(上次实验课已编写机器人代码),前后走时让机器人跟着走,左右看时机器人也左右看,相当于场景中的一个角色。
七、课后作业题
参考本次实验的代码,搭建你自己的3D场景。
八、附属程序
#include"stdafx.h" #include<glut.h> #include<math.h> #define PI 3.14159 int c = 0; float theta = -90.0;//旋转角 float theta2 = 0;//视角 float theta3 = 0; float derta = 10;//角度增量 int inner = 10, outer = 80; float s = outer + 4 * inner + 50; float d = 1;//一步的距离 float eyex = 0, eyey = 0, eyez = s; float atx = 0,atz = 0,aty=0; int ww, hh; bool flag = true; float du = 90, oldmy = -1, oldmx = -1; float r = s, h = 0; void display(); void reshape(int w, int h); void mytime(int value); void darwground(); void darwsphere(); void drawwall(); void init(); void mykeyboard(unsigned char key, int x, int y); void Mouse(int button, int state, int x, int y); void onMouseMove(int x, int y); void robot(); int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); char *argv[] = { "hello ", " " }; int argc = 2; // must/should match the number of strings in argv这个值应该与argv里的字符串数量相等 glutInit(&argc, argv); //初始化GLUT库; glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);//设置显示模式;(缓存,颜色类型) glutInitWindowSize(500, 500); glutCreateWindow("Rotating 3D World"); // 创建显示窗口,标题为"Rotating 3D World" glutReshapeFunc(reshape); init(); glutDisplayFunc(display); //用于绘制当前窗口 glutKeyboardFunc(mykeyboard); glutTimerFunc(100, mytime, 10); glutMouseFunc(Mouse); glutMotionFunc(onMouseMove); 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) { switch (key) { case 'W': case 'w'://向前直走 eyex += d * sin(theta2*PI / 180); eyez -= d * cos(theta2*PI / 180); c++; break; case 'S': case 's'://后退 eyex -= d * sin(theta2*PI / 180); eyez += d * cos(theta2*PI / 180); c--; break; case 'A': case 'a'://左看 theta2 -= 1; if (theta2 <= -360.0) theta2 += 360.0; break; case 'D': case 'd'://右看 theta2 += 1; if (theta2 >= 360.0) theta2 -= 360.0; break; case 'Z': case 'z'://缩小 if (eyex > 0) eyex++; else if (eyex < 0) eyex--; if (eyey > 0) eyey++; else if (eyey < 0) eyey--; if (eyez > 0) eyez++; else if (eyez < 0) eyez--; break; case 'X': case 'x'://放大 if (eyex > 0) eyex--; else if (eyex < 0) eyex++; if (eyey > 0) eyey--; else if (eyey < 0) eyey++; if (eyez > 0) eyez--; else if (eyez < 0) eyez++; break; } atx = eyex + d * sin(theta2*PI / 180); atz = eyez - d * cos(theta2*PI / 180); glutPostRedisplay();//参数修改后调用重画函数,屏幕图形发生改变 } void display() { glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(eyex, eyey, eyez, atx, aty, atz, 0, 1, 0); glPushMatrix(); glColor3f(0, 0, 1.0); drawwall(); glColor3f(1.0, 0, 0); darwground(); darwsphere(); //glutWireTeapot(20); //茶壶 glColor3f(0, 0, 0); glScalef(30, 30, 30); glTranslatef(0, 0, 1); //glutWireTetrahedron();//正四面体 glPopMatrix(); glTranslatef(0, 0, s - 20); glRotatef(180, 0, 1, 0); glTranslatef(c * sin(theta2*PI / 180), 0, c * cos(theta2*PI / 180)); glRotatef(-theta2, 0, 1, 0); robot();//机器人 glutSwapBuffers(); } void darwsphere() { float tr; tr = (outer + 3 * inner); glRotatef(theta, 0, 1, 0); glPushMatrix(); glPushMatrix(); glColor3f(1.0, 0, 1.0); glutWireTorus(inner, outer, 30, 50); glPopMatrix(); glPushMatrix(); glTranslatef(outer, 0, 0); glRotatef(theta, 0, 1, 0); glTranslatef(-outer, 0, 0); glPushMatrix(); glTranslatef(tr, 0, 0); glRotatef(-45, 1, 0, 0); glColor3f(0, 1, 0); glutWireSphere(inner, 20, 20); glPopMatrix(); glPopMatrix(); glPopMatrix(); } void darwground() { //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(); } //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.0) theta -= 360.0; if (theta3 > 40 || theta3 < -40) derta *= -1; theta3 += derta; 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; } void Mouse(int button, int state, int x, int y) { if (state == GLUT_DOWN) oldmx = x, oldmy = y; } void onMouseMove(int x, int y) { du += x - oldmx; h += y - oldmy; oldmx = x, oldmy = y; eyex = r * cos(du*PI/180); eyez = r * sin(du*PI/180); eyey = h; } void robot()//绘制机器人 { glPushMatrix(); glColor3f(1, 0, 0); glScalef(4, 4, 0.5); glutSolidCube(1);//绘制立方体身 glPopMatrix(); glPushMatrix(); glColor3f(1, 1, 0); glTranslatef(0, 2.5, 0); glScalef(1, 1, 0.5); glutSolidCube(1);//绘制立方体头 glPopMatrix(); glPushMatrix(); glPushMatrix(); glTranslatef(0, 2, 0); glRotatef(theta3, 1, 0, 0); glTranslatef(0, -2, 0); glColor3f(1, 0.5, 0.2); glTranslatef(-2.5, 1.25, 0); glScalef(1, 1.5, 0.5); glutSolidCube(1);//绘制立方体右手 glPopMatrix(); glTranslatef(0, 2, 0); glRotatef(theta3, 1, 0, 0); glTranslatef(0, -2, 0);//大臂 glTranslatef(0, 0.5, 0); glRotatef(theta3, 1, 0, 0); glTranslatef(0, -0.5, 0); glColor3f(1, 0.5, 0.2); glTranslatef(-2.5, 0.25, 0.5); glRotatef(-60, 1, 0, 0); glScalef(1, 1.5, 0.5); glutSolidCube(1);//小臂 glPopMatrix(); glPushMatrix(); glPushMatrix(); glTranslatef(0, 2, 0); glRotatef(-1 * theta3, 1, 0, 0); glTranslatef(0, -2, 0); glColor3f(1, 0.5, 0.2); glTranslatef(2.5, 1.25, 0); glScalef(1, 1.5, 0.5); glutSolidCube(1);//绘制立方体左手 glPopMatrix(); glTranslatef(0, 2, 0); glRotatef(theta3*-1, 1, 0, 0); glTranslatef(0, -2, 0);//大臂 glTranslatef(0, 0.5, 0); glRotatef(theta3*-1, 1, 0, 0); glTranslatef(0, -0.5, 0); glColor3f(1, 0.5, 0.2); glTranslatef(2.5, 0.25, 0.5); glRotatef(-60, 1, 0, 0); glScalef(1, 1.5, 0.5); glutSolidCube(1);//小臂 glPopMatrix(); glPushMatrix(); glPushMatrix(); glTranslatef(-3.5, -4, 0); glTranslatef(0, 2, 0); glRotatef(-1 * theta3, 1, 0, 0); glTranslatef(0, -2, 0); glColor3f(0.5, 0.5, 1); glTranslatef(2.5, 1.25, 0); glScalef(1, 1.5, 0.5); glutSolidCube(1);//绘制立方体右腿 glPopMatrix(); glTranslatef(-3.5, -4, 0); glTranslatef(0, 2, 0); glRotatef(-1 * theta3, 1, 0, 0); glTranslatef(0, -2, 0);//大腿 glTranslatef(0, 0.5, 0); glRotatef(-1 * theta3*0.4, 1, 0, 0); glTranslatef(0, -0.5, 0); glColor3f(0.5, 0.5, 1); glTranslatef(2.5, 0.25, -0.5); glRotatef(60, 1, 0, 0); glScalef(1, 1.5, 0.5); glutSolidCube(1);//小腿 glPopMatrix(); glPushMatrix(); glPushMatrix(); glTranslatef(-1.5, -4, 0); glTranslatef(0, 2, 0); glRotatef(theta3, 1, 0, 0); glTranslatef(0, -2, 0); glColor3f(0.5, 0.5, 1); glTranslatef(2.5, 1.25, 0); glScalef(1, 1.5, 0.5); glutSolidCube(1);//绘制立方体左腿 glPopMatrix(); glTranslatef(-1.5, -4, 0); glTranslatef(0, 2, 0); glRotatef(theta3, 1, 0, 0); glTranslatef(0, -2, 0);//大腿 glTranslatef(0, 0.5, 0); glRotatef(theta3*0.4, 1, 0, 0); glTranslatef(0, -0.5, 0); glColor3f(0.5, 0.5, 1); glTranslatef(2.5, 0.25, -0.5); glRotatef(60, 1, 0, 0); glScalef(1, 1.5, 0.5); glutSolidCube(1);//小腿 glPopMatrix(); }