實驗六 2D圖形變換
一、實驗目的
1.瞭解和掌握2D圖形變換:學會使用OpenGL平移、旋轉和比例縮放函式,掌握基本圖形變換和複合圖形變換實現的方法。
2.綜合運用2D圖形變換函式、人機互動函式,設計2D互動圖形程式。
二、實驗內容
要求使用OpenGL幾何變換函式改寫程式碼。
1)使用glTranslatef()函式,實現2D圖形平移,可以改寫實驗二的矩形互動移動程式,如圖6-1。
a)平移前 b)平移後
圖6-1 平移變換
2)使用glRotatef()函式,實現2D圖形繞平面固定點旋轉,可以改寫實驗三的六邊形旋轉程式,如圖6-2。
a)旋轉前 b)旋轉後
圖6-2 旋轉變化
3)使用glScalef()函式,實現繞固定點縮放2D圖形,在前面程式的基礎上設計修改,如圖6-3。
a)縮放前 b)縮放後
圖6-3 比例變換
4)修改程式碼,使得一面帶杆小三角紅旗沿著杆底不斷旋轉,如圖6-4
圖6-4 旋轉的小紅旗
- 正六邊形邊旋轉邊放大,放大到接近整個顯示屏後再不停縮小,如此往復。
三、參考函式
1.glTranslatef(x,y,z);//x、y、z分別代表x、y、z方向的平移量,對於2D圖形,z=0
2.glRotatef(Q,x,y,z);//Q為逆時針方向旋轉的角度度數(0~360),(x,y,z)為旋轉軸的方向向量,(x,y,z)=(0,0,1)時代表沿z軸方向旋轉;(x,y,z)=(1,0,0)時代表沿x軸方向旋轉;(x,y,z)=(0,1,0)時代表沿y軸方向旋轉。
3.glScalef(x,y,z);//x、y、z分別表示x、y、z方向的比例因子。對於2D圖形,z=0。比例因子取-1時,產生對稱變換。
四、程式碼示例
1.某圖形沿水平方向和垂直方向分別平移Tx、Ty段距離。
清屏
glMatrixMode(GL_MODELVIEW);//設定矩陣模式為模型變換模式,表示在世界座標系下
glLoadIdentity();//將當前矩陣設定為單位矩陣
glTranslatef(Tx,Ty,0)
DrawSomeShape();
重新整理
2.某圖形繞任意點(cx,cy)旋轉ALPHA角度。
清屏
glMatrixMode(GL_MODELVIEW);//設定矩陣模式為模型變換模式,表示在世界座標系下
glLoadIdentity();//將當前矩陣設定為單位矩陣
glTranslatef(cx,cy,0)//平移回去
glRotatef(ALPHA,0,0,1);//繞原點旋轉ALPHA角度
glTranslatef(-cx,-cy,0)//平移回原點
DrawSomeShape();
重新整理
3.某圖形繞任意點(cx,cy)縮放Sx、Sy比例因子。
清屏
glMatrixMode(GL_MODELVIEW);//設定矩陣模式為模型變換模式,表示在世界座標系下
glLoadIdentity();//將當前矩陣設定為單位矩陣
glTranslatef(cx,cy,0)//平移回去
glScalef(Sx,Sy,1);//繞原點水平縮放係數Sx,垂直縮放係數Sy
glTranslatef(-cx,-cy,0)//平移回原點
DrawSomeShape();
重新整理
五、思考題
1.繞某個固定點旋轉時,程式碼的順序改寫為:
glTranslatef(-cx,-cy,0)//平移回原點
glRotatef(ALPHA,0,0,1);//繞原點旋轉ALPHA角度
glTranslatef(cx,cy,0)//平移回去
圖形將變成怎樣?
答:圖形形狀不變,但是位置會改變。因為因為glTranslatef的變換是以當前位置來變換的,也就是說用的是相對座標而不是絕對座標。
2.繞某個固定點進行比例縮放時,程式碼的順序改寫為:
glTranslatef(-cx,-cy,0)//平移回原點
glScalef(Sx,Sy,1);//繞原點水平縮放係數Sx,垂直縮放係數Sy
glTranslatef(cx,cy,0)//平移回去
圖形將變成怎樣?為什麼?
答:會縮放,但是位置會改變。因為縮放是相對於原點進行的,而不是自身的中心。當平移後再縮放,再平移回去,會改變座標。
六、完整程式碼
#include<glut.h>
#include<stdio.h>
#include<windows.h>
#include"math.h"
#define PI 3.1415926
int n = 6,flag=0;
float R = 0.5,theta=0,sx=1,sy=1;
void myidle()
{
theta += 1.0;
Sleep(5);
if (theta >= 360) theta -= 360;
/*if (sx >= 2.83) flag = 1;
if (sx <= 0.1) flag = 0;
if (flag == 0)
{
sx *= 1.01, sy *= 1.01;
}
if(flag==1)
{
sx *= 0.99, sy *=0.99;
}*/
glutPostRedisplay();
}
void display(void)
{
glClearColor(1, 1, 1, 1);//設定清屏顏色
glClear(GL_COLOR_BUFFER_BIT);//重新整理顏色快取區
glColor3f(0, 0, 0); //設定黑色繪圖顏色
glMatrixMode(GL_MODELVIEW);//設定矩陣模式為模型變換模式,表示在世界座標系下
glLoadIdentity();//將當前矩陣設定為單位矩陣
glTranslatef(-0.5, -0.5, 0);//平移回原點
glScalef(0.5, 0.5, 1);//繞原點水平縮放係數Sx,垂直縮放係數Sy
//glTranslatef(0.5, 0.5, 0);//平移回去
//glTranslatef(0.5, 0.5, 0);//平移
//glRotatef(45, 0, 0, 1);//繞z軸旋轉45°
//glScalef(0.5, 0.5, 0);//縮小
//glRotatef(theta, 0, 0, 1);//繞z軸不停旋轉
//glScalef(sx, sy, 0);//放大
glRectf(-0.5, -0.5,0.5,0.5);//矩形
/*glBegin(GL_POLYGON); //六邊形
for (int i = 0; i < n; i++)
glVertex2f(R*cos(i * 2 * PI / n), R*sin(i * 2 * PI / n));
glEnd();
*/
/*
glColor3f(1, 0, 0); //畫小紅旗
glBegin(GL_LINES);
glVertex2f(0, 0);
glVertex2f(0, 0.7);
glEnd();
glBegin(GL_TRIANGLES);
glVertex2f(0, 0.8);
glVertex2f(0.4, 0.8);
glVertex2f(0, 0.5);
glEnd();
*/
glFlush();//重新整理命令佇列和快取區,使所有尚未執行的OpenGL命令得到執行
}
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
char *argv[] = { "hello "," " };
int argc = 2;
glutInit(&argc, argv); //初始化GLUT庫;
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); //設定顯示模式;(緩衝,顏色型別)
glutInitWindowSize(300, 300);//繪製視窗大小
glutInitWindowPosition(1024 / 2 - 250, 768 / 2 - 250);//視窗左上角在螢幕的位置
glutCreateWindow("hello"); //建立視窗,標題為“hello”;
glutDisplayFunc(display); //顯示回撥函式用於繪製當前視窗;
glutIdleFunc(myidle);
glutMainLoop(); //表示開始執行程式,用於程式的結尾;
return 0;
}