1. 程式人生 > >計算機圖形與OpenGL學習五(二維幾何變換1.平移、旋轉、縮放)

計算機圖形與OpenGL學習五(二維幾何變換1.平移、旋轉、縮放)

二維幾何變換(平移、旋轉、縮放)

本章涉及數學變換比較多,程式碼是次要的,數學理論可自己推導一下。

二維平移

通過將二維量加到一個點的座標上來生成一個新的座標位置,可以實現一次平移。將平移距離加到原始座標上獲得一個新的座標,實現一個二維位置的平移。

為平移向量,使用列向量來表示各點座標的話:


例項

對一個四邊形進行平移,平移量自己輸入,結果圖平移量為(200,200),程式碼:

#include<GL/glut.h>
#include<math.h>
#include<Windows.h>
#include<iostream>
#include<stdlib.h>
using namespace std;
GLsizei winWidth = 500, winHeight = 500;
GLuint regHex;//顯示錶標識
class wcPt2D
{
public:
	GLfloat x, y;
	wcPt2D(GLfloat x=0,GLfloat y=0)
	{
		this->x = x;
		this->y = y;
	}
};
wcPt2D verts[4] = { wcPt2D(10.0, 20.0), wcPt2D(100.0, 50.0), wcPt2D(120, 240.0), wcPt2D (30.0,220.0)};
GLfloat tx; GLfloat ty;
void Move(wcPt2D *verts,GLfloat tx,GLfloat ty)
{
	//平移函式,作為例子平移四邊形
	GLint nverts = 4;
	GLint k;
	wcPt2D newVerts[4];//使用一個新的頂點物件集,方便觀察平移效果
	for (k = 0; k < nverts;++k)
	{
		newVerts[k].x = verts[k].x + tx;
		newVerts[k].y = verts[k].y + ty;
	}
	
	glBegin(GL_QUADS);
	for (k = 0; k < nverts; ++k)
	{
		glVertex2f(verts[k].x, verts[k].y);
	}
	for (k = 0; k < nverts; ++k)
	{
		glVertex2f(newVerts[k].x, newVerts[k].y);
	}
	glEnd();

	glFlush();
}
void funcPlot()
{
	glClear(GL_COLOR_BUFFER_BIT);
	Move(verts,tx,ty);
}

static void init(void)
{
	//初始化函式,並加入表

	glClearColor(1.0, 1.0, 1.0, 0.0);//設定為白色背景
	regHex = glGenLists(1);//獲得一個標識
	glColor3f(1.0, 0.0,0.0);
	glPointSize(2);
	

}



void winReshapeFcn(int newWidth, int newHeight)
{
	//視窗重定形函式
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();//將當前的使用者座標系的原點移到了螢幕中心:類似於一個復位操作
	gluOrtho2D(0.0, (GLdouble)newWidth, 0.0, (GLdouble)newWidth);
	glClear(GL_COLOR_BUFFER_BIT);


} int main(int argc, char**argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(winWidth, winHeight);
	glutCreateWindow("Example");
	cout << "輸入x,y偏移量(範圍為0-200,0-200):" << endl;
	cin >> tx >> ty;
	init();
	glutDisplayFunc(funcPlot);
	glutReshapeFunc(winReshapeFcn);
	glutMainLoop();
	return 0;
}

結果


【二維旋轉】

通過指定一個旋轉軸和一個旋轉角度,進行一次旋轉,即是讓物件的所有頂點按指定角度繞指定旋轉軸旋轉。

當繞原點旋轉時,設是點的原始角度位置與水平線的夾角,是旋轉角。旋轉後的座標表示為:




例項:將上個例子的四邊形,輸入旋轉基點,繞指定角度。本次結果為基點(0,450),旋轉角度45°。程式碼與平移相似,只展示核心程式碼:

class wcPt2D
{
public:
	GLfloat x, y;
	wcPt2D(GLfloat x=0,GLfloat y=0)
	{
		this->x = x;
		this->y = y;
	}
};
wcPt2D verts[4] = { wcPt2D(10.0, 20.0), wcPt2D(100.0, 50.0), wcPt2D(120, 240.0), wcPt2D (30.0,220.0)};
GLfloat xr; GLfloat yr;//基準點
GLdouble theta;//旋轉角度
void rotate(wcPt2D *verts,GLfloat xr,GLfloat yr,GLdouble theta)
{
	//旋轉函式,作為例子平移四邊形
	GLint nverts = 4;
	GLint k;
	wcPt2D newVerts[4];//使用一個新的頂點物件集,方便觀察平移效果
	for (k = 0; k < nverts;++k)
	{
		newVerts[k].x = xr + (verts[k].x - xr)*cos(theta) - (verts[k].y - yr)*sin(theta);
		newVerts[k].y = yr + (verts[k].x - xr)*sin(theta) + (verts[k].y - yr)*cos(theta);
	}
	
	glBegin(GL_QUADS);
	for (k = 0; k < nverts; ++k)
	{
		glVertex2f(verts[k].x, verts[k].y);
	}
	for (k = 0; k < nverts; ++k)
	{
		glVertex2f(newVerts[k].x, newVerts[k].y);
	}
	glEnd();

	glFlush();
}

結果


【二維縮放】

改變一個物件的大小,可使用縮放變換。一個簡單的二維縮放操作可通過將縮放係數和與物件座標位置相乘得到:

當縮放係數絕對值小於1時,縮放物件向原點靠近;當縮放係數絕對值大於1時,縮放物件遠離原點。我們可以選擇一個在縮放後不改變位置的點,稱為固定點。固定點設為(xf,yf),縮放後的座標可計算為:

等式變形為:




例項

依然用上面的四邊形,選擇左下角的點作為縮放基點,縮放係數需要輸入,結果是縮放係數Sx,Sy=2時的效果。縮放後我進行了200畫素的向左平移,以獲得對比效果,核心程式碼如下:


class wcPt2D
{
public:
	GLfloat x, y;
	wcPt2D(GLfloat x=0,GLfloat y=0)
	{
		this->x = x;
		this->y = y;
	}
};
wcPt2D verts[4] = { wcPt2D(10.0, 20.0), wcPt2D(100.0, 50.0), wcPt2D(120, 240.0), wcPt2D (30.0,220.0)};
GLfloat sx; GLfloat sy;//縮放係數
void scale(wcPt2D *verts,GLfloat sx,GLfloat sy)
{
	//縮放函式,作為例子平移四邊形
	GLint nverts = 4;
	wcPt2D fixedPt = verts[0];//選擇左下的點作為基準點
	GLint k;
	wcPt2D newVerts[4];//使用一個新的頂點物件集,方便觀察平移效果
	for (k = 0; k < nverts;++k)
	{
		newVerts[k].x = verts[k].x*sx+fixedPt.x*(1-sx)+200;//加200是為了水平平移200個畫素,方便比較
		newVerts[k].y = verts[k].y*sy + fixedPt.y*(1 - sy);
	}
	
	glBegin(GL_QUADS);
	for (k = 0; k < nverts; ++k)
	{
		glVertex2f(verts[k].x, verts[k].y);
	}
	for (k = 0; k < nverts; ++k)
	{
		glVertex2f(newVerts[k].x, newVerts[k].y);
	}
	glEnd();

	glFlush();
}
void funcPlot()
{
	glClear(GL_COLOR_BUFFER_BIT);
	scale(verts,sx,sy);
}

結果: