0
点赞
收藏
分享

微信扫一扫

杭电计算机图形学:制作一个长方体几何变换的动画

凌得涂 2022-04-01 阅读 45
c++

实验内容:
自己编写包含平移、旋转、缩放这三种基本变换的程序(并非调用已有函数)。

我的想法:
其实上,这三种变换本质上是点的变换。
拿旋转来讲,我们只需要把一个4x4的单位矩阵变换成下面这样的矩阵(图),对应坐标值改变一下就好了,然后乘以每个点的坐标矩阵,(本质上呢就是每个点都做这样的变换),最后将变换后的24个点放在一个新的数组中,再画出来就ok了。

平移:在这里插入图片描述
旋转:
在这里插入图片描述
缩放:
在这里插入图片描述
代码:

#include<GL/glut.h>
#include<stdlib.h>
#include<math.h>

GLfloat sx = 2;
GLfloat sy = 2;
GLfloat sz = 2;
GLfloat tx = 0, ty = 0, tz = 0;
GLfloat angle1 = 60;
typedef GLfloat M4[4][4];
M4 mat2;
class pt3D {
public:
	GLfloat x, y, z;
};
pt3D pivot = { 5.0,1.0,1.0 };
pt3D scale = { 0.0,1.0,0.0 };
pt3D verts[] = {
	{ -1.0,0.0,0.0 }, { 1.0,0.0,0.0 }, { 1.0,1.0,0.0 }, { -1.0,1.0,0.0 },//下面
	{ -1.0,0.0,0.0 }, { 1.0,0.0,0.0 }, { 1.0,0.0,2.0 },{-1.0,0.0,2.0},//左面
    { 1.0,0.0,0.0 }, { 1.0,1.0,0.0 },{ 1.0,1.0,2.0 },{1.0,0.0,2.0},//前面
	{ 1.0,1.0,0.0 }, { -1.0,1.0,0.0 },{ -1.0,1.0,2.0 },{1.0,1.0,2.0},//右面
	{ -1.0,0.0,0.0 }, { -1.0,1.0,0.0 },{ -1.0,1.0,2.0 },{-1.0,0.0,2.0},//后面
	{ -1.0,0.0,2.0 }, { -1.0,1.0,2.0 },{ 1.0,1.0,2.0 },{1.0,0.0,2.0}//上面
};//长方体共有六个面,画一个面需要四个点,一共需要24个点
pt3D resultVerts[24];//存放变换后的矩阵,即最新的点坐标
class color {
public:
	GLfloat r, g, b;
};
color colors[] = {
	{ 1.0, 1.0, 0.0 }, { 0.0, 1.0, 0.0 }, { 0.0, 0.0, 1.0 }, { 1.0, 0.0, 1.0 },{1.0,3.0,0.0},{0.0,1.0,6.0}
};

void init()
{
	glClearColor(1.0, 1.0, 1.0, 0.0);//我们刷新屏幕时,刷新的颜色
	glOrtho(-5.0, 5.0, -5.0, 5.0, -5.0, 5.0);//我们把-5到5的范围改大,显示就会x轴方向变小
	glMatrixMode(GL_PROJECTION);
	//告诉计算机,接下来我要对PROJECTION(投影)进行操作了
	//其它参数还有:MODELVIEW模型;TEXTURE纹理
}

//矩阵初始化
void SetIdentity(M4 identitymatrix4x4) {//单位矩阵
	GLint col, row;//其实就是int
	for (row = 0; row < 4; row++) {
		for (col = 0; col < 4; col++) {
			identitymatrix4x4[row][col] = (row == col);
		}
	}
}

//矩阵乘法
void matMultiply(M4 m1, M4 m2)
{
	GLint row, col;
	M4 matTemp;
	for (row = 0; row < 4; row++) {
		for (col = 0; col < 4; col++) {
			matTemp[row][col] = m1[row][0] * m2[0][col] + m1[row][1] * m2[1][col] + m1[row][2] * m2[2][col] + m1[row][3] * m2[3][col];
		}
	}
	for (row = 0; row < 4; row++) {
		for (col = 0; col < 4; col++) {
			m2[row][col] = matTemp[row][col];
		}
		//最终矩阵相乘的结果存在m2中
	}
}

//平移
void Translate3D(GLfloat tx, GLfloat ty, GLfloat tz)
{
	M4 matrixTranslate3D;//平移需要的第一个矩阵A
	SetIdentity(matrixTranslate3D);
	matrixTranslate3D[0][3] = tx;//沿x轴平移的单位
	matrixTranslate3D[1][3] = ty;
	matrixTranslate3D[2][3] = tz;
	//然后做矩阵乘法就好了
	//这一步的主要目的不是乘,是为了把结果存在矩阵mat2里面
	matMultiply(matrixTranslate3D, mat2);
}

//实现每个点的平移,旋转,缩放
void TransformVerts3D()
{
	GLint k;
	for (k = 0; k < 24; k++) {
		resultVerts[k].x = mat2[0][0] * verts[k].x + mat2[0][1] * verts[k].y + mat2[0][2] * verts[k].z + mat2[0][3];
		resultVerts[k].y = mat2[1][0] * verts[k].x + mat2[1][1] * verts[k].y + mat2[1][2] * verts[k].z + mat2[1][3];
		resultVerts[k].z = mat2[2][0] * verts[k].x + mat2[2][1] * verts[k].y + mat2[2][2] * verts[k].z + mat2[2][3];
	}
}

//仅对X轴旋转
void Rotate3D(pt3D pivotPt, GLfloat theta)
{
	M4 matrixRotate3D1;
	SetIdentity(matrixRotate3D1);
	matrixRotate3D1[1][1] = cos(theta);
	matrixRotate3D1[1][2] = sin(theta);
	matrixRotate3D1[2][1] = -sin(theta);
	matrixRotate3D1[2][2] = cos(theta);

	matMultiply(matrixRotate3D1, mat2);
}

//缩放
void scale3D(GLfloat sx, GLfloat sy, GLfloat sz, pt3D fixedPt)
{
	M4 matScale3D;
	SetIdentity(matScale3D);
	matScale3D[0][0] = sx;
	matScale3D[0][3] = (1 - sx) * fixedPt.x;
	matScale3D[1][1] = sy;
	matScale3D[1][3] = (1 - sy) * fixedPt.y;
	matScale3D[2][2] = sz;
	matScale3D[2][3] = (1 - sz) * fixedPt.z;
	matMultiply(matScale3D, mat2);
}

//画一个长方体
void Draw(pt3D* mat)
{
	int j;
	for (int i = 0; i < 6; i++) {//六个面
		glColor3f(colors[i].r, colors[i].g, colors[i].b);
		for (j = i * 4; j < i * 4 + 4; j++) {
			glVertex3f(mat[j].x, mat[j].y, mat[j].z);
		}
	}
}

void DisplayFunc()
{
	//GL_COLOR_BUFFER_BIT把窗口清除为当前颜色;GL_DEPTH_BUFFER_BIT清除深度缓冲区
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	//为了方便看旋转变化,我们画一下坐标轴
	glBegin(GL_LINES);
	glColor3f(0.0, 1.0, 0.0);//绿色
	glVertex3f(0, 0, 0);
	glVertex3f(4, 0, 0);//x轴
	glColor3f(1.0, 0.0, 0.0);//红色
	glVertex3f(0, 0, 0);
	glVertex3f(0, 4, 0);//y轴
	glColor3f(0.0, 0.0, 1.0);//蓝色
	glVertex3f(0, 0, 0);
	glVertex3f(0, 0, 4);
	glEnd();

	glRotatef(45, 0, 1, 0);

	glLoadIdentity();// 恢复初始坐标系
	SetIdentity(mat2);//矩阵初始化
	Translate3D(tx, ty, tz);
	TransformVerts3D();

	scale3D(sx, sy, sz, scale);
	TransformVerts3D();

	Rotate3D(pivot, angle1);
	TransformVerts3D();
	glRotatef(45,0,1,0);
	glRotatef(45, 0, 0, 1);

	glBegin(GL_QUADS);
	Draw(resultVerts);
	glEnd();
	glFlush();
}

void processSpecialKeys(int key, int x, int y)
{
	switch (key) {
	case GLUT_KEY_UP:ty -= 0.1; break;
	case GLUT_KEY_DOWN:ty += 0.1; break;
	case GLUT_KEY_LEFT:tx -= 0.1; break;
	case GLUT_KEY_RIGHT:tx += 0.1; break;
	case GLUT_KEY_PAGE_UP:sx += 0.1, sy += 0.1; sz += 0.1; break;
	case GLUT_KEY_PAGE_DOWN:sx -= 0.1, sy -= 0.1, sz -= 0.1; break;//PAGE_UP和PAGE_DOWN这两个键控制缩放
	case GLUT_KEY_HOME:angle1 += 50; break;//转50下转回原点
	case GLUT_KEY_END:tx = 4; ty = 0.5; tz = 0; angle1 = 60;break;//回到原始状态
	default:break;
	}
	DisplayFunc();
}

void main(int argc, char* argv[])
{
	//这个函数用来初始化 GLUT 库,这个函数从 main 函数获取其两个参数
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);//SINGLE单缓存,建立RGBA模式的窗口
	glutInitWindowPosition(50, 50);
	glutInitWindowSize(600, 600);
	glutCreateWindow("3DCuboid");

	init();
	glutDisplayFunc(DisplayFunc);//回调函数
	glutSpecialFunc(processSpecialKeys);//键盘
	glutMainLoop();//使程序进入事件处理循环。该函数必须是main主函数的最后一条语句。
}

参考博客:https://blog.csdn.net/qq_34376715/article/details/80494449
大家可以去看一下这篇文章哦,很棒,我只是照猫画虎罢了(第一次发博客,有错误请大家多多指正,谢谢~)

举报

相关推荐

0 条评论