实验九3D编程基础
一、实验目的
1.熟悉3D基本编程。 2.熟悉视角观察函数的设置和使用。 3.熟悉投影变换函数的设置和使用。 4.熟悉基本3D绘制图元。
二、实验内容
1.读懂以下3D对象程序,并结合本书的内容了解一些新的绘制函数和投影变换函数 义:3D Cube.cpp (见以下参考程序)正交投影下旋转3D按鼠标可以实现不同的立方体 方向旋转,效果图见实验图9-1,分析3D编程代码和程序结构。 记录不同效果图和修改的相应参数: 1)让静态立方体绕Z轴旋转。
gluLookAt(0, 0, 3, 0, 0, 0, 0, 1, 0);///视点设置函数 
2)修改不同视点,目标点不变,观看显示效果。
gluLookAt(3, 0, 0, 0, 0, 0, 0, 1, 0);//视点设置函数 3)修改目标点,不动视点,观看显示效果。
gluLookAt(3, 3, 3, 0, 3, 0, 0, 1, 0);///视点设置函数 4)同时修改视点和目标点,观看显示效果。
gluLookAt(5, 0, 0, 3, 0, 0, 0, 1, 0); ///视点设置函数 5)视点与目标点不变,修改观察体大小,观看显示效果。
gluPerspective(50, w / h, 10, 60); //定义透视投影投影观察体大小 6)将正交投影观察体改为透视投影观察体,并设置其大小,观察显示效果。 正交投影比透视投影观察体的亮度暗些,细节部分缺失。 7)将立方体替换为茶壶,观看显示效果。
8)将立方体替换为圆环,观看显示效果。 2.构思绘制茶壶和圆环造型程序Teapot Torus.cpp。在紧挨着茶壶下方添加一个平行的圆 环,茶壶和圆环不停绕中心轴旋转,观看显示效果。
3.编写或改写程序,构造自己的3D物体场景造型。
void teapot_torus() {
glPushMatrix();
glTranslatef(0, 1, 0);
glColor3f(1, 0.5, 0);
//glutWireTeapot(1.2);
glutSolidTeapot(1.2);
glPopMatrix();
//绘制茶壶
glColor3f(1, 0.5, 0);
//绘制圆环
glColor3f(1, 0, 0);
glPushMatrix();
glTranslatef(0, 0, 0);
glRotatef(90, 1, 0, 0);
glutWireTorus(0.3, 1.2, 30, 30);
glPopMatrix();
glColor3f(0,0,1);
glPushMatrix();
glTranslatef(0, 0, 0);
glRotatef(90, 1,0, 0);
glutWireTorus(1, 1.01, 30, 30);
glPopMatrix();
}
三、函数参考
1 .视点设置函数:
void gluLookAt(GLdouble eyex, GLdouble eyey,GLdouble eyezz GLdouble atx,GLdouble aty,GLdouble atz,GLdouble upx,GLdouble upy,GLdouble upz)
2.正交投影变换设置函数:
void glOrtho(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top,GLdouble near,GLdouble far)
3.透视投影变换设置函数:
void gluPerspective(GLdouble fov, GLdouble aspect, GLdouble near,GLdouble far)
4.三维基本图形绘制函数: 1 )立方体绘制函数:
void glutWireCube(GLdouble size) //线框模式
void glutSolidCube(GLdouble size)//实体模式
功能:绘制一个边长为size的线框或实心立方体,立方体的中心位于原点。 2)小球绘制函数:
void glutWireSphere(GLdouble Radius, Glint slices,Glint stacks) ;//线框模式
void glutSolidSphere(GLdouble Radius, Glint slices,Glint stacks);//实体模式
功能:绘制一个半径为Radius的线框或实心小球,小球的中心点位于原点,slices为小 球的经线数目,stacks为小球的纬线数目。 gluSphere(GLUquadricObj *obj,GLdouble radius,GLint slices,GLint stacks); 用法如下:
GLUquadricObj *sphere;//定义二次曲面对象
sphere = gluNewQuadric();//生成二次曲面对象
gluSphere(Sphere,8,50,50);//半径为8,球心在原点,经线和纬线数目为50的小球
3)茶壶绘制函数:
void glutWireTeapot(GLdouble size);//线框模式
void glutSolidTeapot(GLdouble size);//实体模式
功能:绘制一个半径为size的线框或实心茶壶,茶壶的中心位于原点。 参数说明:参数size为茶壶的近似半径,以size为半径的球体可完全包容这个茶壶。 4)圆环绘制函数:
void glutWireTorus(GLdouble innerRadius, GLdouble outerRadius,Glint slices,Glint stacks) ; //线框模式
void glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius,Glint slices,Glint stacks) ; //实体模式
功能:绘制一个半径为size的线框或实心圆环体,圆环体的中心位于原点,圆环的内径 和外径由参数innerRadius、outerRadius指定。 参数说明:innerRadius为圆环体的内径;outerRadius为圆环体的外径;slices为圆环体 的经线数目;stacks为圆环体的纬线数目。 5)正八面体绘制函数:
void glutWireOctahedron (void) ; // 线框模式
void glutSolidOctahedron (void); //实体模式
功能:绘制一个线框的或实心的正八面体,其中心位于原点,半径为1。 6)正十二面体绘制函数:
void glutWireDodehedron (void) ; // 线框模式
void glutSolidDodehedron (void); //实体模式
功能:绘制一个线框的或实心的正十二面体,其中心位于原点,-半径为3的平方根。 7)正二十面体绘制函数:
void glutWirelcosahedron (void); //线框模式
void glutSolidlcosahedron (void); //实体模式
功能:绘制一个线框的或实心的正二十面体,其中心位于原点,半径为1。 8)正四面体绘制函数:
void glutWireTetrahedron (void); //线框模式
void glutSolidTetrahedron (void); //实体模式
功能:绘制一个线框的或实心的正四面体,其中心位于原点,半径为3的平方根。 9)裁剪平面函数:
void glClipPlane(GLenum plane, const GLdouble *equation)
定义一个附加的裁减平面。plane指岀要定义的附加裁减平面名称,取值为GL_CLIP_ PLANEi,i=0 ~ 5 ; equation指向由平面方程Ax+By+Cz+D=0的4个系数刀、B、C、O构成的 数组,以定义一个裁减平面。调用此函数,先启用glEnable(GL_CLIP_PLANEi),需要时用 glDisable(GL_CLIP_PLANEi)关闭某裁减平面。 5.图形变换函数:
1) glTranslatef(xz y,z)
2) gLRotatef(Q,x, y, z)
3) glScalef(x,y,z)
6.void glPushMatrix (void)函数
7.void glPopMatrix (void)函数
8.void glutIdleFunc( (*f) (void)) 〃注册闲置响应函数
9.void myidle () //闲置响应回调函数
{
//当时间空闲时系统要做的事情
}
四、思考题
1.修改目标点与视点,显示结果有何不同?
2.视点与目标点不变,修改观察体大小,显示结果有什么规律?
3.正交投影与透视投影有何不同?
五、课后加分题
如何编写程序从不同角度观看物体模型?如按“A”键,视点越来越远;按“S”键视点 越来越近?如何切换俯视、侧视或正视?
将视点设为变量,按相应的键进行改变。切换俯视、侧视或正视,设置键位使视点切换至相应的方向。
六、程序代码
#define GLUT_DISABLE_ATEXIT_HACK
//3D Cube.cpp,旋转立方体参考程序
#include <windows.h>
#include <gl/glut.h>
#include <math.h>
int flag = 0;
//GLfloat vertices[][3] = {
{-1.0,-1.0,1.0},{-1.0,1.0,1.0},{1.0,1.0,1.0},{1.0,-1.0,1.0}, {-1.0,-1.0,-1.0},
//{-1.0,1.0,-1.0},{1.0,1.0,-1.0},{1.0,-1.0,-1.0}};
GLfloat vertices[][3] = {
{
-1.0,-1.0,-1.0},{
1.0,-1.0,-1.0},{
1.0,1.0,-1.0 }, {
-1.0,1.0, -1.0 }, {
-1.0, -1.0, 1.0},
{
1.0, -1.0, 1.0},{
1.0,1.0,1.0 }, {
-1.0,1.0,1.0 }};
GLfloat colors[][3] = {
{
1.0,0.0,0.0}, {
0.0,1.0,1.0}, {
1.0,1.0,0.0}, {
0.0,1.0,0.0}, {
0.0, 0.0,1.0},
{
1.0,0.0,1.0 }, {
0.0, 1.0, 1.0}, {
1.0, 1.0, 1.0}};
static GLfloat theta[] = {
0.0,0.0,0.0 };
static GLint axis = 2;
void reshape(int w,int h);
void init();
void display();
void mouse(int btn, int state,int x, int y);
void polygon(int a,int b,int c,int d);
void colorcube(void);
void spinCube();
int main(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库
int sheight = glutGet(GLUT_SCREEN_WIDTH);
int swidth = glutGet(GLUT_SCREEN_HEIGHT);
glutInitWindowSize(800, 800); //设置显示窗口大小
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); //设置显示模式(注意双缓存 )
glutInitWindowPosition(sheight / 2 - 400, swidth / 2 - 400); //窗口左上角在屏幕的位置
glutCreateWindow("colorcube"); //创建显示窗口
init(); //初始化设置
glutReshapeFunc(reshape); //注册窗口改变回调函数
glutDisplayFunc(display); //注册显示回调函数
glutIdleFunc(spinCube);
glutMouseFunc(mouse);
glutMainLoop(); //进入事件处理循环
return 0;
}
void display() {
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(0, 0, 4, 0, 0, 0, 0, 1, 0);
glRotatef(theta[0], 1.0, 0.0, 0.0);
glRotatef(theta[1], 0.0, 1.0, 0.0);
glRotatef(theta[2], 0.0, 0.0, 1.0);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
flag = 0;
colorcube(); //绘制彩色立方体
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
flag = 1;
colorcube(); //绘制彩色立方体
glutSwapBuffers();
}
void init() {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_DEPTH_TEST);
glLineWidth(3);
}
void polygon(int a,int b,int c,int d){
/* draw a polygon via list of vertices */
if (flag == 0){
glBegin(GL_POLYGON);
glColor3fv(colors[a]);
glVertex3fv(vertices[a]);
glColor3fv(colors[b]);
glVertex3fv(vertices[b]);
glColor3fv(colors[c]);
glVertex3fv(vertices[c]);
glColor3fv(colors[d]);
glVertex3fv(vertices[d]);
glEnd();
}
else{
glColor3f(0, 0, 0);
glBegin(GL_POLYGON);
glVertex3fv(vertices[a]);
glVertex3fv(vertices[b]);
glVertex3fv(vertices[c]);
glVertex3fv(vertices[d]);
glEnd();
}
}
void colorcube(void) {
/* map vertices to faces */
polygon(0, 3, 2, 1);
polygon(2, 3, 7, 6);
polygon(0, 4, 7, 3);
polygon(1, 2, 6, 5);
polygon(4, 5, 6, 7);
polygon(0, 1, 5, 4);
}
void mouse(int btn, int state,int x, int y){
if (btn==GLUT_LEFT_BUTTON && state==GLUT_DOWN) axis=0;
if (btn==GLUT_MIDDLE_BUTTON && state==GLUT_DOWN) axis=1;
if (btn==GLUT_RIGHT_BUTTON && state==GLUT_DOWN) axis=2;
}
void reshape(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//定义正交投影观察体
if (w <= h)
glOrtho(-2.0, 2.0, -2.0 * (GLfloat)h / (GLfloat)w, 2.0 * (GLfloat)h / (GLfloat)w, 1.0, 20.0);
else
glOrtho(-2.0 * (GLfloat)w / (GLfloat)h, 2.0 * (GLfloat)w / (GLfloat)h, -2.0, 2.0, 1.0, 20.0); //glu Perspective (120,w/hzl,60); / / 定义透视投影观察体
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void spinCube(){
theta[axis] += 1.0;
if (theta[axis] > 360.0) theta[axis] -= 360.0; glutPostRedisplay();
}
实验九3D编程基础