实验二 几何图形变换实验
一、实验目的和要求
- 进一步掌握二维、三维变换的数学知识、变换原理、变换种类、变换方法;
- 利用OpenGL实现二维、三维图形变换,在屏幕上显示变换过程或变换结果;
- 掌握OpenGL常用的变换函数,利用OpenGL绘制简单的三维物体。
二、实验内容
1、下面的代码采用GLUT库,使用了双缓存,在按下鼠标左键后,程序在空闲时一直不停地调用spinDisplay函数,实现了一个矩形在窗口中匀速转动(单击鼠标右键停止转动)。请修改代码,实现矩形在窗口内沿着水平线从左侧移动到右侧。通过实验说明glPushMatrix()和glPopMatrix()的作用。
/*
* double.c
* This is a simple double buffered program.
* Pressing the left mouse button rotates the rectangle.
* Pressing the right mouse button stops the rotation.
*/
#include <GL/glut.h>
#include <stdlib.h>
static GLfloat spin = 0.0;
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glRotatef(spin, 0.0, 0.0, 1.0);
glColor3f(1.0, 1.0, 1.0);
glRectf(-10.0, -10.0, 10.0, 10.0);
glPopMatrix();
glutSwapBuffers(); //交换双缓存
}
void spinDisplay(void)
{
spin = spin + 2.0;
if (spin > 360.0)
spin = spin - 360.0;
glutPostRedisplay(); //屏幕重绘
}
void init(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel (GL_FLAT);
}
void reshape(int w, int h)
{
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-50.0, 50.0, -50.0, 50.0, -1.0, 1.0); //平行投影
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void mouse(int button, int state, int x, int y)
{
switch (button) {
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN)
glutIdleFunc(spinDisplay); //设备空闲时调用的函数
break;
case GLUT_MIDDLE_BUTTON:
case GLUT_RIGHT_BUTTON:
if (state == GLUT_DOWN)
glutIdleFunc(NULL);
break;
default:
break;
}
}
/*
* Request double buffer display mode.
* Register mouse input callback functions
*/
void main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB); //使用双缓存模式
glutInitWindowSize (500, 500);
glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);
init ();
glutDisplayFunc(display); //注册重绘函数
glutReshapeFunc(reshape); //注册改变窗口形状函数
glutMouseFunc(mouse); //注册鼠标动作函数
glutMainLoop();
}
2. 已知某三角形的三顶点坐标{50.0,50.0},{150.0,50.0},{100.0,150.0}。
要求:(1)创建一个长宽分别为600、600的窗口,窗口的左上角位于屏幕坐标(100,100)处。
(2)绘制一个由上述顶点所描绘的三角形,使得三角形位于窗口的中心;对三角形进行下列的几何变换:首先使三角形沿着其中心的x轴,y轴方向缩小到原来的25%;然后绕中心旋转-90度;最后沿着x轴平移70个单位,绘制出变换后的结果。
3. 绘制一个椅子的透视投影图,并使椅子旋转起来,通过鼠标或键盘控制旋转的方向。
参考函数:glutSolidCube(size)绘制实心立方体/glutWireCube(size)绘制线框立方体
这两个函数分别用于绘制中心位于世界坐标系原点的实心立方体和线框立方体,立方体的半径为size,size是一个双精度浮点值。
参考代码: wireobject
三、实验设计思路
1. 创建一个OpenGL工程,修改上述初始化代码display函数,将旋转glRotatef()函数修改成平移变换函数glTranslatef(),再修改一下初始位置。
2. 将上述代码进行鼠标交互等函数的清除,删减后类似与实验一中的代码。修改main函数中的窗口大小和窗口位置。主要修改display函数,glBegin(GL_TRIANGLES);开始画三角形,输入三个点glEnd绘制完成,用平移函数glTranslated、旋转函数glRotated、比例变换函数glScaled,进行从后往前的变换。最后重新绘制原来的三角形。
3. 先绘制一个桌子腿,再将椅子的整体绘制出来,利用的是glutWireCube(size)绘制线框立方体函数,最后通过平移、旋转、缩放函数将椅子在固定位置旋转起来。其中鼠标右键是停止旋转,鼠标左键是继续旋转,鼠标滚轮按钮是控制椅子的旋转方向。
四、实验代码
1.
/* * double.c * This is a simple double buffered program. * Pressing the left mouse button rotates the rectangle. * Pressing the right mouse button stops the rotation. */ #include <GL/glut.h> #include <stdlib.h> static GLfloat spin = 0.0; void display(void) { glClear(GL_COLOR_BUFFER_BIT); glPushMatrix(); //glRotatef(spin, 0.0, 0.0, 1.0); glTranslatef(spin, 0.0, 0.0); glColor3f(1.0, 1.0, 1.0); glRectf(-50.0, -10.0, -30.0, 10.0); glPopMatrix(); glutSwapBuffers(); //交换双缓存 } void spinDisplay(void) { spin = spin + 0.03; if (spin > 360.0) spin = spin - 360.0; glutPostRedisplay(); //屏幕重绘 } void init(void) { glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_FLAT); } void reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-50.0, 50.0, -50.0, 50.0, -1.0, 1.0); //平行投影 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void mouse(int button, int state, int x, int y) { switch (button) { case GLUT_LEFT_BUTTON: if (state == GLUT_DOWN) glutIdleFunc(spinDisplay); //设备空闲时调用的函数 break; case GLUT_MIDDLE_BUTTON: case GLUT_RIGHT_BUTTON: if (state == GLUT_DOWN) glutIdleFunc(NULL); break; default: break; } } /* * Request double buffer display mode. * Register mouse input callback functions */ void main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); //使用双缓存模式 glutInitWindowSize(500, 500); glutInitWindowPosition(100, 100); glutCreateWindow(argv[0]); init(); glutDisplayFunc(display); //注册重绘函数 glutReshapeFunc(reshape); //注册改变窗口形状函数 glutMouseFunc(mouse); //注册鼠标动作函数 glutMainLoop(); }
2.
/* * double.c * This is a simple double buffered program. * Pressing the left mouse button rotates the rectangle. * Pressing the right mouse button stops the rotation. */ #include <GL/glut.h> #include <stdlib.h> void display(void) { glClear(GL_COLOR_BUFFER_BIT); glPushMatrix(); //操作矩阵堆栈,调用函数,相当于把矩阵放到堆栈上 glBegin(GL_TRIANGLES); glVertex2f(50, 50); glVertex2f(150, 50); glVertex2f(100, 150); glEnd(); glFlush(); glColor3f(1.0f, 1.0f, 1.0f); glTranslated(100, 100, 0); glTranslated(70, 0, 0); glRotated(-90, 0, 0, 1); glScaled(0.25, 0.25, 0.0); glTranslated(-100, -100, 0); glBegin(GL_TRIANGLES); glVertex2f(50, 50); glVertex2f(150, 50); glVertex2f(100, 150); glEnd(); glFlush(); glPopMatrix(); } void init(void) { glMatrixMode(GL_PROJECTION); //设置投影参数 glLoadIdentity(); gluOrtho2D(0.0, 200.0, 0.0, 200.0); } /* * Request double buffer display mode. * Register mouse input callback functions */ void main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_RGB); //使用双缓存模式 glutInitWindowSize(600, 600); glutInitWindowPosition(100, 100); glutCreateWindow(argv[0]); init(); glutDisplayFunc(display); //注册重绘函数 //glutReshapeFunc(reshape); //注册改变窗口形状函数 //glutMouseFunc(mouse); //注册鼠标动作函数 glutMainLoop(); }
3.
#include <GL/glut.h> float size = 0.25; //缩放 float fTranslate; float fRotate; float fScale = 1.0f; // set inital scale value to 1.0f float K = 1.0f; float x = 1, y = 0, z = 0; void Draw_Leg() // This function draws one of the table leg { //绘制一个桌子腿 glPushMatrix(); glScalef(1.0f, 1.0f, 3.0f); glutWireCube(1.0 * size); glPopMatrix(); } void Draw_Table() // This function draws a Table { glPushMatrix(); //将当前矩阵保存入堆栈顶(保存当前矩阵)。 glScalef(5.0f, 4.0f, 1.0f); //缩放函数 glColor3f(1.0, 0.0, 1.0); glutSolidCube(1 * size); //绘制线立方体 glPopMatrix(); //pop出来 glPushMatrix(); //将当前矩阵保存入堆栈顶(保存当前矩阵)。 glScalef(4.0f, 1.0f, 4.0f); //缩放函数 glTranslatef(0.0 * size, 1.5 * size, 0.5 * size); glColor3f(0.0, 0.0, 1.0); glutSolidCube(1 * size); //绘制线立方体 glPopMatrix(); //pop出来 glPushMatrix(); //左下角的柱子 glTranslatef(-1.5 * size, -1 * size, -1.5 * size); //尺寸是相对于中心的坐标原点,按照实验指导上的大小进行的 Draw_Leg(); glPopMatrix(); glPushMatrix(); //右下角的柱子 glTranslatef(1.5 * size, -1 * size, -1.5 * size); Draw_Leg(); glPopMatrix(); glPushMatrix(); //右上角的柱子 glTranslatef(1.5 * size, 1 * size, -1.5 * size); Draw_Leg(); glPopMatrix(); glPushMatrix(); //左上角的柱子 glTranslatef(-1.5 * size, 1 * size, -1.5 * size); Draw_Leg(); glPopMatrix(); } void reshape(int width, int height) { if (height == 0) // Prevent A Divide By Zero By { height = 1; // Making Height Equal One } glViewport(0, 0, width, height); // Reset The Current Viewport glMatrixMode(GL_PROJECTION); // Select The Projection Matrix glLoadIdentity(); // Reset The Projection Matrix // Calculate The Aspect Ratio Of The Window gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f); glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix glLoadIdentity(); // Reset The Modelview Matrix } void idle() { glutPostRedisplay(); } void redraw() { // If want display in wireframe mode //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glClear(GL_COLOR_BUFFER_BIT); //当前缓冲区清除值,这里是清除颜色缓冲 glLoadIdentity(); // Reset The Current Modelview Matrix if (K == 1) { glPushMatrix(); glTranslatef(-1.0f, 0.0f, -6.0f); // Place the triangle at Center glRotatef(fRotate * K, x, y, z); // Rotate around Y axis Draw_Table(); // Draw triangle glPopMatrix(); glPushMatrix(); glTranslatef(1.0f, 0.0f, -6.0f); glRotatef(fRotate * K, y, x, z); Draw_Table(); glPopMatrix(); fRotate += 0.05f; } else if (K == 0) { glPushMatrix(); glTranslatef(-1.0f, 0.0f, -6.0f); // Place the triangle at Center glRotatef(fRotate, x, y, 0); // Rotate around Y axis Draw_Table(); // Draw triangle glPopMatrix(); glPushMatrix(); glTranslatef(1.0f, 0.0f, -6.0f); glRotatef(fRotate, y, x, z); Draw_Table(); glPopMatrix(); } glutSwapBuffers(); } void myMouse(int button, int state, int x, int y) { if (state == GLUT_DOWN) { if (button == GLUT_LEFT_BUTTON) { K = 1; } else if (button == GLUT_RIGHT_BUTTON) { K = 0; } } } void processMenuEvents_two(int option) { switch (option) { case 1:x = 1; y = 0; z = 0; break; case 2:x = 0; y = 1; z = 0; break; case 3:x = 0; y = 0; z = 1; break; default: break; } } int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); glutInitWindowSize(640, 480); int windowHandle = glutCreateWindow("Simple GLUT App"); glutDisplayFunc(redraw); glutReshapeFunc(reshape); glutIdleFunc(idle); glutMouseFunc(myMouse); //鼠标滚轮 glutCreateMenu(processMenuEvents_two); glutAddMenuEntry("X", 1); glutAddMenuEntry("Y", 2); glutAddMenuEntry("Z", 3); glutAttachMenu(GLUT_MIDDLE_BUTTON); glutMainLoop(); return 0; }
五、实验结果及心得体会
1.
编辑编辑
2.
编辑
3.
编辑
编辑
编辑
此次实验,进一步掌握二维、三维变换的数学知识、变换原理、变换种类及变换方法;使用了OpenGL利用常用的变换函数实现了二维、三维图形变换;同时还绘制了一个简单的三维立体图形。通过本次实验,进一步学习了图形学中的几何图形知识以及变换过程,收获颇多,对今后本课程的学习有了较大的帮助。