计算机图形学 实验3 《图形变换》
一、实验目的
学习图形的基本几何变换。
二、实验内容
1、投影变换;
2、视口变换;
3、旋转、平移和缩放。
三、实验方法
本次实验将投影变换、视口变换结合到具体的旋转、平移、缩放操作当中,其中旋转、平移、缩放操作通过对键盘的响应进行处理实现人机交互;这三个操作可以通过OpenGL提供的glScalef
、glTranslatef
、glRotatef
函数进行实现,本质上是传入参数形成一个变换矩阵M,将该矩阵M与当前选定的矩阵(模型视图矩阵)做乘法最后重绘完成变换。
四、实验步骤
1、完成一个基本图元的绘制,这里为了突出变换效果,目标绘制一个白色的正方形;
2、定义相关变换参数,存进数组并进行初始化;
3、通过glViewport
函数划分视口区域,即进行视口变换;
4、编写键盘消息处理函数并进行注册,选择合适的按键,通过glScalef
、glTranslatef
、glRotatef
函数对特定的按键按下的消息进行响应处理,完成上述旋转、平移和缩放的操作。
五、实验结果与实验结论
1、视口划分

关键源码:
glClear(GL_COLOR_BUFFER_BIT); //清空缓冲区
// 划分第一个视口,位置为(200, 200),长200,宽200
glLoadIdentity(); //将当前矩阵设为单位矩阵
glViewport(200, 200, 200, 200);
// 划分第二个视口
glLoadIdentity();
glViewport(0, 0, 200, 200);
2、旋转
左图:按下D键,顺时针旋转;右图:按下A键,逆时针旋转;


3、平移
4、缩放


源码:
#define PI 3.14
#define DEG_TO_RAD 0.017453 // 角度转为弧度的参数,即 2*PI/360
float theta[4];
float ud[4], lr[4];
float s[4] = { 1.0, 1.0, 1.0, 1.0 };
int ctr = 0;// 0整体,1红色,2绿色,3蓝色
void init(void) {
glClearColor(0.0, 0.0, 0.0, 1.0);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(-5.0, 5.0, -5.0, 5.0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
}
void drawDiamond(void) {
// 绘制中心在原点的正方形
glBegin(GL_QUADS); // 顶点指定需要按逆时针方向
glVertex2f(1.0f, 1.0f);// 右上点
glVertex2f(1.0f, -1.0f);// 右下点
glVertex2f(-1.0f, -1.0f);// 左下点
glVertex2f(-1.0f, 1.0f);// 左上点
glEnd();
}
void display() {
glClear(GL_COLOR_BUFFER_BIT); //清空
glLoadIdentity(); //将当前矩阵设为单位矩阵
glViewport(200, 200, 200, 200);
glScalef(s[0], s[0], s[0]);
glScalef(s[1], s[1], s[1]);
glTranslatef(lr[0], ud[0], 0.0);
glTranslatef(lr[1], ud[1], 0.0);
glRotatef(90.0 + theta[0] + theta[1], 0.0, 0.0, 1.0); //顺时针旋转90角度
glTranslatef(2.0, 0.0, 0.0);
glColor3f(0.0f, 1.0f, 1.0f);
drawDiamond();
glLoadIdentity(); //将当前矩阵设为单位矩阵
glViewport(0, 0, 200, 200);
glScalef(s[0], s[0], s[0]);
glScalef(s[2], s[2], s[2]);
glTranslatef(lr[0], ud[0], 0.0);
glTranslatef(lr[2], ud[2], 0.0);
glRotatef(90.0 + theta[0] + theta[2], 0.0, 0.0, 1.0);
glTranslatef(-2.0, 0.0, 0.0);
glColor3f(1.0f, 1.0f, 1.0f);//白色
drawDiamond();
glFlush();
}
void myKeyboard(unsigned char key, int x, int y) {
//a、d控制旋转
if (key >= '0' && key <= '3') ctr = key - '0';
if (key == 'a' || key == 'A')
theta[ctr] += 5.0;
if (key == 'd' || key == 'D')
theta[ctr] -= 5.0;
if (key == 'c' || key == 'C')
exit(0);
if (theta[ctr] > 360) theta[ctr] -= 360;
if (theta[ctr] < 0) theta[ctr] += 360;
if(key=='=')
s[ctr] += 0.05;
if(key=='-')
s[ctr] -= 0.05; //控制大小(缩放)
glutPostRedisplay(); //重新调用绘制函数
}
void mySpecialKeyboard(int key, int x, int y) {
// 方向控制、移动控制
if (key == GLUT_KEY_UP)
ud[ctr] += 0.1;//上
if (key == GLUT_KEY_DOWN)
ud[ctr] -= 0.1;//下
if (key == GLUT_KEY_LEFT)
lr[ctr] -= 0.1;//左
if (key == GLUT_KEY_RIGHT)
lr[ctr] += 0.1;//右
glutPostRedisplay(); //重新调用绘制函数
}
void myMouse(int button, int state, int x, int y) {//滑轮控制缩放
if (button == GL_RIGHT)
s[ctr] += 0.05;
if (button == 4 && s[ctr] > 0.1)
s[ctr] -= 0.05;
glutPostRedisplay(); //重新调用绘制函数
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(100, 100);
glutInitWindowSize(400, 400);
glutCreateWindow("exp3");
init();
glutKeyboardFunc(myKeyboard);
glutSpecialFunc(mySpecialKeyboard);
glutMouseFunc(myMouse);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
六、实验小结
本次实验了解了一些变换的主要形式(主要是通过代码展现的),同时通过查阅资料还了解了通过注册键盘相关的消息处理函数达到键盘监听的一个效果,如本次实验为了更好的控制展示变换效果,采用了普适键盘消息处理函数和特殊键盘消息处理函数,将键盘的上下左右作为平移的按键,将"A"、“D"作为顺逆时针旋转的按键,将”-"、"+"("=") 作为放大缩小的按键,方便了程序的展示,并且还了解到当输入法为中文时,键入产生的消息是无效的,即OpenGL程序将不会做出响应。