计算机图形学-实验4-掌握几何变换的原理

来源:互联网 发布:软件用户手册英文模板 编辑:程序博客网 时间:2024/06/06 06:55

实验四: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();}


1 0
原创粉丝点击