实验内容:
自己编写包含平移、旋转、缩放这三种基本变换的程序(并非调用已有函数)。
我的想法:
其实上,这三种变换本质上是点的变换。
拿旋转来讲,我们只需要把一个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
大家可以去看一下这篇文章哦,很棒,我只是照猫画虎罢了(第一次发博客,有错误请大家多多指正,谢谢~)