计算机图形学-三维物体的平移、旋转、防缩

要求

  1. 利用OpenGL函数画一个三维物体;
  2. 利用鼠标或键盘控制三维物体在屏幕上移动、旋转和放缩
    (1)移动:不能直接调用OpenGL几何变换函数,运用齐次坐标,采用矩阵相乘的方式自己编程实现;
    (2)旋转、放缩可以调用OpenGL函数

使用工具:

  1. Visual Studio C++控制台
  2. opengl

效果图:

计算机图形学-三维物体的平移、旋转、防缩_第1张图片
计算机图形学-三维物体的平移、旋转、防缩_第2张图片

实现步骤:

1.基本三维物体绘制:旋转坐标系,用线条表示出x轴、y轴和z轴,然后画出基本的三维物体,调整旋转系数查看三维物体是否绘制成功,如图1所示;
2. 平移功能:运用其次坐标,矩阵相乘及代码,实现平移功能;
3. 旋转和缩放功能:使用OpenGL函数glRotatef和glScalef实现;
4.键盘设置:UP、DOWN、LEFT和RIGHT分别控制物体的上、下、左和右移动,PAGE_UP 和PAGE_DOWN分别控制物体在y轴方向的放大和缩小,INSERT控制物体围绕y轴旋转,END让物体回到初始状态。

知识点:

  1. 矩阵相乘遵循的规则
    M x N x K = (M X N) x K = M x (N x K)
    M x N 不等于 N x M
  2. 平移矩阵设置计算机图形学-三维物体的平移、旋转、防缩_第3张图片
    计算机图形学-三维物体的平移、旋转、防缩_第4张图片
  3. 旋转矩阵设置计算机图形学-三维物体的平移、旋转、防缩_第5张图片
    计算机图形学-三维物体的平移、旋转、防缩_第6张图片
  4. 缩放矩阵设置计算机图形学-三维物体的平移、旋转、防缩_第7张图片
    计算机图形学-三维物体的平移、旋转、防缩_第8张图片

部分功能代码:

/* 矩阵初始化,正对角线上设为1,其余为0 */
void Matrix4x4SetIdentity(Matrix4x4 matIdent4x4)
{
    GLint row, col;

    for (row = 0; row < 4; row++)
        for (col = 0; col < 4; col++)
            matIdent4x4[row][col] = (row == col);
}

/* 两个矩阵相乘,结果存储到矩阵m2;
   如果只是使用矩阵实现平移,可以省去这个步骤,
   若是要用矩阵全部实现平移、旋转、缩放,则需要一个中间矩阵,最后将某点的中间矩阵与原坐标矩阵进行相乘,得出新的点坐标
*/
void Matrix4x4PreMultiply(Matrix4x4 m1, Matrix4x4 m2)
{
    GLint row, col;
    Matrix4x4 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];
}

/* 平移 */
void Translate3D(GLfloat tx, GLfloat ty, GLfloat tz)
{
    Matrix4x4 matTransl;
    Matrix4x4SetIdentity(matTransl);
    matTransl[0][3] = tx;
    matTransl[1][3] = ty;
    matTransl[2][3] = tz;
    Matrix4x4PreMultiply(matTransl, matComposite);
}

/*
旋转,全方位旋转
 */
void rotate3D (wcPt3D p1, wcPt3D p2, GLfloat radianAngle)
{
   Matrix4x4 matQuatRot;
   float axisVectLength = sqrt ((p2.x - p1.x) * (p2.x - p1.x) +
                        (p2.y - p1.y) * (p2.y - p1.y) +
                        (p2.z - p1.z) * (p2.z - p1.z));
   float cosA = cosf (radianAngle);
   float oneC = 1 - cosA;
   float sinA = sinf (radianAngle);
   float ux = (p2.x - p1.x) / axisVectLength;
   float uy = (p2.y - p1.y) / axisVectLength;
   float uz = (p2.z - p1.z) / axisVectLength;

   translate3D (-p1.x, -p1.y, -p1.z);

   matrix4x4SetIdentity (matQuatRot);

   matQuatRot [0][0] = ux*ux*oneC + cosA;
   matQuatRot [0][1] = ux*uy*oneC - uz*sinA;
   matQuatRot [0][2] = ux*uz*oneC + uy*sinA;
   matQuatRot [1][0] = uy*ux*oneC + uz*sinA;
   matQuatRot [1][1] = uy*uy*oneC + cosA;
   matQuatRot [1][2] = uy*uz*oneC - ux*sinA;
   matQuatRot [2][0] = uz*ux*oneC - uy*sinA;
   matQuatRot [2][1] = uz*uy*oneC + ux*sinA;
   matQuatRot [2][2] = uz*uz*oneC + cosA;

   matrix4x4PreMultiply (matQuatRot, matComposite);
   translate3D (p1.x, p1.y, p1.z);
}
//仅对X轴旋转
void Rotate3Dx(wcPt3D pivotPt, GLfloat theta)
{
    Matrix4x4 matRot;

    /*  Initialize rotation matrix to identity.  */
    Matrix4x4SetIdentity(matRot);

    matRot[1][1] = cos(theta);
    matRot[1][2] = sin(theta);
    matRot[2][1] = -sin(theta);
    matRot[2][2] = cos(theta);

    Matrix4x4PreMultiply(matRot, matComposite);
}
//仅对Y轴旋转
void Rotate3Dy(wcPt3D pivotPt, GLfloat theta)
{
    Matrix4x4 matRot;

    /*  Initialize rotation matrix to identity.  */
    Matrix4x4SetIdentity(matRot);

    matRot[0][0] = cos(theta);
    matRot[0][2] = sin(theta);
    matRot[2][0] = -sin(theta);
    matRot[2][2] = cos(theta);

    Matrix4x4PreMultiply(matRot, matComposite);
}

/*缩放*/
void scale3D (Gfloat sx, GLfloat sy, GLfloat sz, wcPt3D fixedPt)
{
   Matrix4x4 matScale3D;
   matrix4x4SetIdentity (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;
   matrix4x4PreMultiply (matScale3D, matComposite);
}

实例代码:

#include 
#include
#include

GLsizei winWidth = 600, winHeight = 600;
GLint nVerts = 12;//点的个数
GLfloat tx=0, ty=1, tz=3;//存储要平移的距离
GLfloat angle = 60;//旋转角度
GLfloat scale = 2.0;//缩放比例
typedef GLfloat M4[4][4];
M4 matComposite;
class pt3D { public: GLfloat x, y, z; };
pt3D verts[] = {
        { 0.0, 1.0, 0.0 }, { -1.0, -1.0, 1.0 }, { 1.0, -1.0, 1.0 },
        { 0.0, 1.0, 0.0 }, { 1.0, -1.0, 1.0 }, { 1.0, -1.0, -1.0 },
        { 0.0, 1.0, 0.0 }, { 1.0, -1.0, -1.0 }, { -1.0, -1.0, -1.0 },
        { 0.0, 1.0, 0.0 }, { -1.0, -1.0, -1.0 }, { -1.0, -1.0, 1.0 }
};//存放三维物体的各个点坐标,由于有4个三角形面,所以有12个点,设置顶点一致就好,拼接三角形,底面不做绘制
pt3D resultVerts[12];//存放变换后的矩阵,即最新的点坐标
class color { public: GLfloat r, g, b; };
color colors[] = {
        { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }, { 0.0, 0.0, 1.0 }, { 1.0, 1.0, 0.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);
    glMatrixMode(GL_PROJECTION);
}
void m4SetIdentity(M4 matIdentity4x4)
{
    GLint col, row;
    for (row = 0; row < 4; row++){
        for (col = 0; col < 4; col++){
            matIdentity4x4[row][col] = (row == col);
        }
    }
}
void m4PreMultiply(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];
        }
    }
}
void translate3D(GLfloat tx, GLfloat ty, GLfloat tz)
{
    M4 matTranslate3D;
    m4SetIdentity(matTranslate3D);
    matTranslate3D[0][3] = tx;
    matTranslate3D[1][3] = ty;
    matTranslate3D[2][3] = tz;
    m4PreMultiply(matTranslate3D, matComposite);
}
void transformVerts3D()
{
    GLint k;
    for (k = 0; k < nVerts; k++){
        resultVerts[k].x = matComposite[0][0] * verts[k].x + matComposite[0][1] * verts[k].y + matComposite[0][2] * verts[k].z + matComposite[0][3];
        resultVerts[k].y = matComposite[1][0] * verts[k].x + matComposite[1][1] * verts[k].y + matComposite[1][2] * verts[k].z + matComposite[1][3];
        resultVerts[k].z = matComposite[2][0] * verts[k].x + matComposite[2][0] * verts[k].y + matComposite[2][2] * verts[k].z + matComposite[2][3];
    }
}

//画一个三棱锥,每个面设不同的颜色
void draw(pt3D *mat)
{
    int j;
    for (int i = 0; i < 4; i++) {
        glColor3f(colors[i].r, colors[i].g, colors[i].b);
        for (j = i * 3; j < i * 3 + 3; j++) {
            glVertex3f(mat[j].x, mat[j].y, mat[j].z);
        }
    }
}
void displayFunc()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);          
    glRotatef(30, 0.0f, 1.0f, 0.0f); 
    glBegin(GL_LINES);//画坐标轴,可以省略,主要是为了看旋转变化
    glColor3f(1.0, 0.0, 0.0);//y轴红色
    glVertex3f(0, 0, 0);
    glVertex3f(0, 4, 0);
    glColor3f(0.0, 1.0, 0.0);
    glVertex3f(0, 0, 0);
    glVertex3f(4, 0, 0);//x轴绿色
    glColor3f(0.0, 0.0, 1.0);
    glVertex3f(0, 0, 0);
    glVertex3f(0, 0, 3);//z轴蓝色
    glEnd();
    glBegin(GL_TRIANGLES);                          // 绘制三角形      
    draw(verts);
    glEnd();
    glLoadIdentity();//不可以省略,否则后面对其它三维物体的变换也会发生在上面已经绘制的物体中
    GLfloat scaleBack = 1 / scale;
    glRotatef(angle, 0.0, 1.0, 0.0);
    glScalef(1.0, scale, 1.0);
    //GLfloat tx = 0, ty = 1.0, tz = 3;
    m4SetIdentity(matComposite);
    translate3D(tx, ty, tz);
    transformVerts3D();
    glBegin(GL_TRIANGLES);     
    draw(resultVerts);
    glEnd();
    glScalef(1.0, scaleBack, 1.0);
    glLoadIdentity();
    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:tz += 0.1;break;
    case GLUT_KEY_RIGHT:tz -= 0.1;break;
    case GLUT_KEY_PAGE_UP:scale += 0.1;break;
    case GLUT_KEY_PAGE_DOWN:scale -= 0.1;break;
    case GLUT_KEY_INSERT:angle += 10;break;
    case GLUT_KEY_END:tx = 0; ty = 1; tz = 3; angle = 60; scale = 2; break;//回到原始状态
    default:break;
    }
    displayFunc();
}
void main(int argc, char ** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowPosition(50, 50);
    glutInitWindowSize(winWidth, winHeight);
    glutCreateWindow("3D");
    init();
    glutDisplayFunc(displayFunc);
    glutSpecialFunc(processSpecialKeys);
    glutMainLoop();
}

你可能感兴趣的:(opengl)