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