实验五: 图形变换实验
(二维、三维图形的变换)
1、实验目的和要求
理解二维、三维图形变换的数学原理原理,并能利用OpenGL绘制简单的二维、三维图形,调用OpenGL命令实现基本的图形变换。
2、实验设备
PC机、CodeBlocks\VS系列\OpenGL安装包
3、实验内容及原理
- 通过一个正弦曲线,来进行平移变换。
- 参照Autocad的交互式方式,实现交互式放缩、旋转和对称变换
实验原理(基本知识)
1) 键盘回调函数:glutKeyboardFunc(void(*func)(unsigned char key, int x, int y));
key表示键盘上按下的键,如’w’, ‘a’, ‘s’, ‘d’等。
2) 鼠标回调函数:glutMouseFunc(void(*func)(int button, int state, int x, int y));
button表示鼠标上的按键,有三种取值:
GLUT_LEFT_BUTTON, GLUT_RIGHT_BUTTON, GLUT_MIDDLE_BUTTON,分别表示鼠标左键、右键和中键。
state表示按键的状态,有两种取值:
GLUT_UP, GLUT_DOWN,分别表示弹起或按下。
x, y表示当前鼠标的位置。
3) 鼠标动作回调函数:glutMotionFunc(void(*func)(int x, int y));
x, y表示当前鼠标的位置。
4) 图形变换函数:
① glTranslate{f/d},平移变换。以glTranslatef为例,void glTranslatef(GLfloat x, GLfloat y, GLfloat z); 表示在X, Y, Z轴方向上平移x, y, z单位。
② glRotate{f/d},旋转变换。以glRotatef为例,void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); 表示以(0, 0, 0)到(x, y, z)的向量为轴,逆时针旋转angle度(以度为单位)。
③ glScale{f/d},缩放变换。以glScalef为例,void glScalef(GLfloat x, GLfloat y, GLfloat z); 表示X, Y, Z轴分别缩放至原来的x, y, z倍。
4、实验源程序代码、运行结果
4.1 sin函数的图形变换
4.1.1源程序代码
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <cmath>
#include <vector>
#include <iostream>
using namespace std;
void resize(int w, int h) {
if (h == 0) {
h = 1;
}
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h) {
glOrtho(0.0f, 400.0f, 0.0f, 400.f * h / w, 1.0f, -1.0f);
} else {
glOrtho(0.0f, 400.0f * w / h, 0.0f, 400.0f, 1.0f, -1.0f);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void DrawSin() {
// sin
glBegin(GL_LINE_STRIP);
for (float x = 0; x < 80; x += 0.1) {
glVertex2f(x * 10, sin(x) * 40 + 40);
}
glEnd();
}
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3d(1, 0, 0);
DrawSin();
glTranslatef(0, 100, 0);
glColor3d(0, 0, 1);
DrawSin();
glLoadIdentity();
glTranslatef(0, 200, 0);
glScaled(1.5f, 1.0f, 1.0f);
glColor3d(0, 0, 0);
DrawSin();
glLoadIdentity();
glTranslatef(-50, 300, 0);
DrawSin();
glutSwapBuffers();
}
int main(int argc, char *argv[]) {
glutInit(&argc, argv);
glutInitWindowSize(400, 400);
glutInitWindowPosition(10, 10);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutCreateWindow("sin");
glutReshapeFunc(resize);
glutDisplayFunc(display);
// SetRC
glClearColor(1, 1, 1, 1);
glutMainLoop();
return 0;
}
4.1.2运行结果
4.2绘制立方体
4.2.1源程序代码
源代码中,正方体的顶点下标设置如图所示:
源代码如下:
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <cmath>
#include <vector>
#include <iostream>
using namespace std;
float mouse[2] = {0}; // 鼠标当前的位置, [x, y]轴
float r[2] = {0}; // 旋转的角度, [x, y]轴方向上
float trans[2] = {0}; // 平移,[x, y]轴
float scale = 1.0f; // 整体缩放比
bool isMouseLeftDown = false; // 鼠标左键是否按下
bool isMouseRightDown = false; // 鼠标右键是否按下
float vertices[][3] = { // 正方体的顶点
-0.5, -0.5, -0.5,
-0.5, -0.5, 0.5,
-0.5, 0.5, -0.5,
-0.5, 0.5, 0.5,
0.5, -0.5, -0.5,
0.5, -0.5, 0.5,
0.5, 0.5, -0.5,
0.5, 0.5, 0.5,
};
int indices[][4] = { // 六个面的下标
0, 1, 5, 4,
2, 3, 7, 6,
4, 5, 7, 6,
0, 1, 3, 2,
1, 3, 7, 5,
0, 2, 6, 4,
};
void keyboardEvent(unsigned char key, int x, int y) {
if (key == 'w') { // 上移
trans[1] += 0.1f;
} else if (key == 's') { // 下移
trans[1] -= 0.1f;
} else if (key == 'a') { // 左移
trans[0] -= 0.1f;
} else if (key == 'd') { // 右移
trans[0] += 0.1f;
}
if (key == 'z') { // 缩小
scale -= 0.1f;
} else if (key == 'x') { // 放大
scale += 0.1f;
} else if (key == 'c') { // 复原
scale = 1.0f;
}
}
void mouseEvent(int button, int state, int x, int y) {
mouse[0] = x;
mouse[1] = y;
switch (button) {
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN) {
isMouseLeftDown = true;
// cout << "mouse_left_button down!" << endl;
} else {
isMouseLeftDown = false;
}
break;
case GLUT_RIGHT_BUTTON:
if (state == GLUT_DOWN) {
isMouseRightDown = true;
} else {
isMouseRightDown = false;
}
break;
case GLUT_MIDDLE_BUTTON:
break;
default:
break;
}
}
void mouseMotionEvent(int x, int y) {
if (isMouseLeftDown) { // 鼠标左键按下时,进行旋转变换
// cout << "previous x,y: " << mouse[0] << ' ' << mouse[1] << endl;
// cout << "current x, y: " << x << ' ' << y << endl;
r[0] += (y - mouse[1]) * 0.25f;
r[1] += (x - mouse[0]) * 0.25f;
mouse[0] = x;
mouse[1] = y;
}
if (isMouseRightDown) {
mouse[0] = x;
mouse[1] = y;
}
}
void drawCube() {
glBegin(GL_QUADS);
// 绘制正方体的6个面
for (int i = 0; i < 6; i++) {
// 每个面的4个顶点
for (int j = 0; j < 4; j++) {
glVertex3fv(vertices[indices[i][j]]);
}
}
glEnd();
}
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
// w, a, s, d 控制平移变换
glTranslatef(trans[0], trans[1], 0);
// z, x, c键控制缩放: z 缩小,x 放大, c 复原
glScalef(scale, scale, 1);
// 鼠标左键控制旋转变换
glRotatef(r[0], 1, 0, 0);
glRotatef(r[1], 0, 1, 0);
// 仅绘制线框
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glColor3f(0, 0, 0);
drawCube();
glPopMatrix();
glutSwapBuffers();
}
int main(int argc, char *argv[]) {
glutInit(&argc, argv);
glutInitWindowSize(400, 400);
glutInitWindowPosition(10, 10);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutCreateWindow("Cube");
glutDisplayFunc(display);
glutIdleFunc(display);
glutKeyboardFunc(keyboardEvent); // 设置键盘的回调函数
glutMouseFunc(mouseEvent); // 设置鼠标的回调函数
glutMotionFunc(mouseMotionEvent); // 设置鼠标动作的回调函数
// SetRC
glClearColor(1, 1, 1, 1);
glutMainLoop();
return 0;
}
4.2.2运行结果
使用键盘上的W, A, S, D控制立方体上、左、下、右移动(平移变换)。
鼠标左键按下时移动时,立方体进行旋转(旋转变换)。
使用键盘的Z, X, C控制缩放变换: