計算機圖形學-實驗4-掌握幾何變換的原理

實驗四:2學時)

 

一、 實驗目的:

掌握幾何變換的原理,尤其是複合變換

 

二、 實驗內容:

1、利用OpenGL函數畫一個三維物體;

2、運用齊次座標,採用矩陣相乘的方式自己編程實現幾何變換,不能直接調用OpenGL幾何變換函數;

3、利用鼠標或鍵盤控制三維物體在屏幕上移動、旋轉和放縮;

 

三、 實現效果及步驟(或流程)

1、利用OpenGL函數畫一個三維物體;


實現方法:

(1)初始化時給八個座標,座標之間兩兩相連畫線,代碼如下:

// 將立方體的八個頂點保存到一個數組裏面 
static float vertex_list[][3] =
{
	-0.5f, -0.5f, -0.5f,
	0.5f, -0.5f, -0.5f,
	-0.5f, 0.5f, -0.5f,
	0.5f, 0.5f, -0.5f,
	-0.5f, -0.5f, 0.5f,
	0.5f, -0.5f, 0.5f,
	-0.5f, 0.5f, 0.5f,
	0.5f, 0.5f, 0.5f,
};
// 將要使用的頂點的序號保存到一個數組裏面 
static const GLint index_list[][2] =
{
	{ 0, 1 },
	{ 2, 3 },
	{ 4, 5 },
	{ 6, 7 },
	{ 0, 2 },
	{ 1, 3 },
	{ 4, 6 },
	{ 5, 7 },
	{ 0, 4 },
	{ 1, 5 },
	{ 7, 3 },
	{ 2, 6 }
};
//繪製立方體
void DrawCube(void)
{
	int i, j;
	glBegin(GL_LINES);
	for (i = 0; i < 12; ++i) // 12 條線段
	{
		for (j = 0; j < 2; ++j) // 每條線段 2個頂點
		{
			glVertex3fv(vertex_list[index_list[i][j]]);
		}
	}
	glEnd();
}


2、運用齊次座標,採用矩陣相乘的方式自己編程實現幾何變換,不能直接調用OpenGL幾何變換函數;

實現方法:

(1)移動函數:

typedef GLfloat Matrix4x4[4][4];
void matrix4x4SetIdentity(Matrix4x4 matIdent4x4) {
	GLint row, col;
	for (row = 0; row < 4; row++)
		for (col = 0; col < 4; col++)    matIdent4x4[row][col] = (row == col);
}
//自定義平移函數
void translate3D(GLfloat tx, GLfloat ty, GLfloat tz) {
	Matrix4x4 matTransl3D;
	matrix4x4SetIdentity(matTransl3D);
	matTransl3D[0][3] = tx;
	matTransl3D[1][3] = ty;
	matTransl3D[2][3] = tz;
	for (int i = 0; i < 8; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			vertex_list[i][j] += matTransl3D[j][3];
		}
	}
}

(2)旋轉函數:

typedef GLfloat Matrix4x4[4][4];
void matrix4x4SetIdentity(Matrix4x4 matIdent4x4) {
	GLint row, col;
	for (row = 0; row < 4; row++)
		for (col = 0; col < 4; col++)    matIdent4x4[row][col] = (row == col);
}
//自定義旋轉函數
void rotate3D(GLfloat e, GLfloat rx, GLfloat ry, GLfloat rz)
{
	Matrix4x4 matRotate3D;
	matrix4x4SetIdentity(matRotate3D);
	if (rx == 1 && ry == 0 && rz == 0)
	{
		matRotate3D[0][0] = 1;
		matRotate3D[1][1] = cos(e);
		matRotate3D[1][2] = sin(e);
		matRotate3D[2][1] = -sin(e);
		matRotate3D[2][2] = cos(e);
		for (int i = 0; i < 8; i++)
		{
			vertex_list[i][0] = matRotate3D[0][0] * vertex_list[i][0];
			vertex_list[i][1] = matRotate3D[1][1] * vertex_list[i][1] + matRotate3D[1][2] * vertex_list[i][2];
			vertex_list[i][2] = matRotate3D[2][1] * vertex_list[i][1] + matRotate3D[2][2] * vertex_list[i][2];
		}
	}
	else if (rx == 0 && ry == 1 && rz == 0)
	{
		matRotate3D[0][0] = cos(e);
		matRotate3D[0][2] = -sin(e);
		matRotate3D[1][1] = 1;
		matRotate3D[2][0] = sin(e);
		matRotate3D[2][2] = cos(e);
		for (int i = 0; i < 8; i++)
		{
			vertex_list[i][0] = matRotate3D[0][0] * vertex_list[i][0] + matRotate3D[0][2] * vertex_list[i][2];
			vertex_list[i][1] = matRotate3D[1][1] * vertex_list[i][1];
			vertex_list[i][2] = matRotate3D[2][0] * vertex_list[i][0] + matRotate3D[2][2] * vertex_list[i][2];
		}
	}
	else if (rx == 0 && ry == 0 && rz == 1)
	{
		matRotate3D[0][0] = cos(e);
		matRotate3D[0][1] = -sin(e);
		matRotate3D[1][0] = sin(e);
		matRotate3D[1][1] = cos(e);
		matRotate3D[2][2] = 1;
		for (int i = 0; i < 8; i++)
		{
			vertex_list[i][0] = matRotate3D[0][0] * vertex_list[i][0] + matRotate3D[0][1] * vertex_list[i][1];
			vertex_list[i][1] = matRotate3D[1][0] * vertex_list[i][0] + matRotate3D[1][1] * vertex_list[i][1];
			vertex_list[i][2] = matRotate3D[2][2] * vertex_list[i][2];
		}
	}
}

(3)縮放函數:

wcPt3D fixedPt = wcPt3D();

typedef GLfloat Matrix4x4[4][4];
void matrix4x4SetIdentity(Matrix4x4 matIdent4x4) {
	GLint row, col;
	for (row = 0; row < 4; row++)
		for (col = 0; col < 4; col++)    matIdent4x4[row][col] = (row == col);
}
//自定義縮放函數
void scale3D(GLfloat sx, GLfloat sy, GLfloat sz, wcPt3D fixedPt) {
	Matrix4x4 matScale3D;
	matrix4x4SetIdentity(matScale3D);
	matScale3D[0][0] = sx;
	matScale3D[0][3] = (1 - sx) * fixedPt.getx();
	matScale3D[1][1] = sy;
	matScale3D[1][3] = (1 - sy) * fixedPt.gety();
	matScale3D[2][2] = sz;
	matScale3D[2][3] = (1 - sz) * fixedPt.getz();
	for (int i = 0; i < 8; i++)
	{
		vertex_list[i][0] = matScale3D[0][0] * vertex_list[i][0] + matScale3D[0][3] * vertex_list[i][3];
		vertex_list[i][1] = matScale3D[1][1] * vertex_list[i][1] + matScale3D[1][3] * vertex_list[i][3];
		vertex_list[i][2] = matScale3D[2][2] * vertex_list[i][2] + matScale3D[2][3] * vertex_list[i][3];
	}
}

3、利用鼠標或鍵盤控制三維物體在屏幕上移動、旋轉和放縮;

實現效果:

(1)鼠標左鍵拖拽可以移動圖形。

(2)鼠標右鍵拖拽可以旋轉圖形。

(3)鼠標滾輪滾動可以縮放圖形

實現代碼如下:

void OnMouseMove(int x, int y)
{
	printf("x:%d,y:%d\n", x, y);
	if (LeftButtonIsDown == 1)
	{
		x1 = x;
		y11 = 500 - y;
		tx = x1 - x0;
		ty = y11 - y00;
		tz = 0;
	}
	if (RightButtonIsDown == 1)
	{
		x3 = x;
		y3 = 500 - y;
		rx = x3 - x2;
		ry = y3 - y2;
		rz = 0;
	}
}

void MouseFunc(int button, int state, int x, int y)
{
	if (button == GLUT_LEFT_BUTTON)
	{
		if (state == GLUT_DOWN)
		{
			if (LeftButtonIsDown == 0)
			{
				x0 = x;
				y00 = 500 - y;
				LeftButtonIsDown = 1;
			}
		}
		else
		{
			LeftButtonIsDown = 0;
		}
	}

	if (button == GLUT_RIGHT_BUTTON)
	{
		if (state == GLUT_DOWN)
		{
			if (RightButtonIsDown == 0)
			{
				x2 = x;
				y2 = 500 - y;
				RightButtonIsDown = 1;
			}
		}
		else
		{
			RightButtonIsDown = 0;
		}
	}

	if (button == GLUT_WHEEL_UP)
	{
		zoom += 0.01;
	}

	if (button == GLUT_WHEEL_DOWN)
	{
		zoom -= 0.01;
	}
}



完整的項目源碼如下:

// test4.cpp : 定義控制檯應用程序的入口點。

#include "stdafx.h"
#include<GL/glut.h>
#include<math.h>
#define GLUT_WHEEL_UP 3
#define GLUT_WHEEL_DOWN 4

// 繪製立方體

//參數
static float rotate = 0.001;
static float translate = 0.0001;
static float PI = 3.14159;

//鼠標按下時的座標
int x0, y00;
//鼠標停下時的座標
int x1, y11;
//鼠標是否按下
int LeftButtonIsDown = 0;

//鼠標按下時的座標
int x2, y2;
//鼠標停下時的座標
int x3, y3;
//鼠標是否按下
int RightButtonIsDown = 0;

//位移增量
float tx = 0;
float ty = 0;
float tz = 0;
//旋轉增量
float rx = 0;
float ry = 0;
float rz = 0;
//縮放增量
float zoom = 1;

// 將立方體的八個頂點保存到一個數組裏面 
static float vertex_list[][3] =
{
	-0.5f, -0.5f, -0.5f,
	0.5f, -0.5f, -0.5f,
	-0.5f, 0.5f, -0.5f,
	0.5f, 0.5f, -0.5f,
	-0.5f, -0.5f, 0.5f,
	0.5f, -0.5f, 0.5f,
	-0.5f, 0.5f, 0.5f,
	0.5f, 0.5f, 0.5f,
};

// 將要使用的頂點的序號保存到一個數組裏面 

static const GLint index_list[][2] =
{
	{ 0, 1 },
	{ 2, 3 },
	{ 4, 5 },
	{ 6, 7 },
	{ 0, 2 },
	{ 1, 3 },
	{ 4, 6 },
	{ 5, 7 },
	{ 0, 4 },
	{ 1, 5 },
	{ 7, 3 },
	{ 2, 6 }
};

class wcPt3D {
private:
	GLfloat x, y, z;
public:
	wcPt3D() {
		x = y = z = 0.0;
	}
	void setCoords(GLfloat xCoord, GLfloat yCoord, GLfloat zCoord) {
		x = xCoord;
		y = yCoord;
		z = zCoord;
	}
	GLfloat getx() const { return x; }
	GLfloat gety() const { return y; }
	GLfloat getz() const { return z; }
};

wcPt3D fixedPt = wcPt3D();

typedef GLfloat Matrix4x4[4][4];
void matrix4x4SetIdentity(Matrix4x4 matIdent4x4) {
	GLint row, col;
	for (row = 0; row < 4; row++)
		for (col = 0; col < 4; col++)    matIdent4x4[row][col] = (row == col);
}

//自定義平移函數
void translate3D(GLfloat tx, GLfloat ty, GLfloat tz) {
	Matrix4x4 matTransl3D;
	matrix4x4SetIdentity(matTransl3D);
	matTransl3D[0][3] = tx;
	matTransl3D[1][3] = ty;
	matTransl3D[2][3] = tz;
	for (int i = 0; i < 8; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			vertex_list[i][j] += matTransl3D[j][3];
		}
	}
}

//自定義旋轉函數
void rotate3D(GLfloat e, GLfloat rx, GLfloat ry, GLfloat rz)
{
	Matrix4x4 matRotate3D;
	matrix4x4SetIdentity(matRotate3D);
	if (rx == 1 && ry == 0 && rz == 0)
	{
		matRotate3D[0][0] = 1;
		matRotate3D[1][1] = cos(e);
		matRotate3D[1][2] = sin(e);
		matRotate3D[2][1] = -sin(e);
		matRotate3D[2][2] = cos(e);
		for (int i = 0; i < 8; i++)
		{
			vertex_list[i][0] = matRotate3D[0][0] * vertex_list[i][0];
			vertex_list[i][1] = matRotate3D[1][1] * vertex_list[i][1] + matRotate3D[1][2] * vertex_list[i][2];
			vertex_list[i][2] = matRotate3D[2][1] * vertex_list[i][1] + matRotate3D[2][2] * vertex_list[i][2];
		}
	}
	else if (rx == 0 && ry == 1 && rz == 0)
	{
		matRotate3D[0][0] = cos(e);
		matRotate3D[0][2] = -sin(e);
		matRotate3D[1][1] = 1;
		matRotate3D[2][0] = sin(e);
		matRotate3D[2][2] = cos(e);
		for (int i = 0; i < 8; i++)
		{
			vertex_list[i][0] = matRotate3D[0][0] * vertex_list[i][0] + matRotate3D[0][2] * vertex_list[i][2];
			vertex_list[i][1] = matRotate3D[1][1] * vertex_list[i][1];
			vertex_list[i][2] = matRotate3D[2][0] * vertex_list[i][0] + matRotate3D[2][2] * vertex_list[i][2];
		}
	}
	else if (rx == 0 && ry == 0 && rz == 1)
	{
		matRotate3D[0][0] = cos(e);
		matRotate3D[0][1] = -sin(e);
		matRotate3D[1][0] = sin(e);
		matRotate3D[1][1] = cos(e);
		matRotate3D[2][2] = 1;
		for (int i = 0; i < 8; i++)
		{
			vertex_list[i][0] = matRotate3D[0][0] * vertex_list[i][0] + matRotate3D[0][1] * vertex_list[i][1];
			vertex_list[i][1] = matRotate3D[1][0] * vertex_list[i][0] + matRotate3D[1][1] * vertex_list[i][1];
			vertex_list[i][2] = matRotate3D[2][2] * vertex_list[i][2];
		}
	}

	//double e = (180 * a) / PI;


}

//自定義縮放函數
void scale3D(GLfloat sx, GLfloat sy, GLfloat sz, wcPt3D fixedPt) {
	Matrix4x4 matScale3D;
	matrix4x4SetIdentity(matScale3D);
	matScale3D[0][0] = sx;
	matScale3D[0][3] = (1 - sx) * fixedPt.getx();
	matScale3D[1][1] = sy;
	matScale3D[1][3] = (1 - sy) * fixedPt.gety();
	matScale3D[2][2] = sz;
	matScale3D[2][3] = (1 - sz) * fixedPt.getz();
	for (int i = 0; i < 8; i++)
	{
		vertex_list[i][0] = matScale3D[0][0] * vertex_list[i][0] + matScale3D[0][3] * vertex_list[i][3];
		vertex_list[i][1] = matScale3D[1][1] * vertex_list[i][1] + matScale3D[1][3] * vertex_list[i][3];
		vertex_list[i][2] = matScale3D[2][2] * vertex_list[i][2] + matScale3D[2][3] * vertex_list[i][3];
	}
}

//繪製立方體
void DrawCube(void)
{
	int i, j;

	glBegin(GL_LINES);
	for (i = 0; i < 12; ++i) // 12 條線段
	{
		for (j = 0; j < 2; ++j) // 每條線段 2個頂點

		{
			glVertex3fv(vertex_list[index_list[i][j]]);
		}
	}
	glEnd();
}

void renderScene()
{

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_MODELVIEW);

	//獲取當前矩陣的單位矩陣,以後變化都基於這個座標。
	glLoadIdentity();

	//將當前矩陣壓入棧內。
	glPushMatrix();

	//平移
	translate3D((tx)*translate, (ty)*translate, 0);
	//旋轉
	rotate3D(-rx*rotate, 0, 1, 0);
	rotate3D(ry*rotate, 1, 0, 0);
	// 縮放
	scale3D(zoom, zoom, zoom, fixedPt);

	//畫筆顏色
	glColor3f(1, 1, 1);
	//畫立方體
	DrawCube();

	//輸出棧頂的矩陣
	glPopMatrix();
	//雙緩衝交換
	glutSwapBuffers();

	//移動變量初始化
	tx = 0;
	ty = 0;
	tz = 0;
	//旋轉變量初始化
	rx = 0;
	ry = 0;
	rz = 0;
	//縮放變量初始化
	zoom = 1;
}

void OnMouseMove(int x, int y)
{
	printf("x:%d,y:%d\n", x, y);
	if (LeftButtonIsDown == 1)
	{
		x1 = x;
		y11 = 500 - y;
		tx = x1 - x0;
		ty = y11 - y00;
		tz = 0;
	}

	if (RightButtonIsDown == 1)
	{
		x3 = x;
		y3 = 500 - y;
		rx = x3 - x2;
		ry = y3 - y2;
		rz = 0;
	}
}


void MouseFunc(int button, int state, int x, int y)
{
	if (button == GLUT_LEFT_BUTTON)
	{
		if (state == GLUT_DOWN)
		{
			if (LeftButtonIsDown == 0)
			{
				x0 = x;
				y00 = 500 - y;
				LeftButtonIsDown = 1;
			}
		}
		else
		{
			LeftButtonIsDown = 0;
		}
	}

	if (button == GLUT_RIGHT_BUTTON)
	{
		if (state == GLUT_DOWN)
		{
			if (RightButtonIsDown == 0)
			{
				x2 = x;
				y2 = 500 - y;
				RightButtonIsDown = 1;
			}
		}
		else
		{
			RightButtonIsDown = 0;
		}
	}

	if (button == GLUT_WHEEL_UP)
	{
		zoom += 0.01;
	}

	if (button == GLUT_WHEEL_DOWN)
	{
		zoom -= 0.01;
	}
}

void init()
{
	DrawCube();
}

void main(int argc, char **argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(500, 500);
	glutCreateWindow("GLDemo");

	init();
	glutMouseFunc(MouseFunc);
	glutMotionFunc(OnMouseMove);
	//func:在程序空閒的時候就會被調用的函數的函數名。 
	glutIdleFunc(renderScene);
	glutMainLoop();
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章