OpenGL | OpenGL矩阵操作(视图模型矩阵下)

在opengl场景中一般存在多种矩阵变换操作,而控制这些操作的命令主要用到glMatrixMode函数。

模型视图矩阵是在对物体进行缩放或者从不同的视角观察物体的时候所调用的。主要涉及到三个函数:

glTranslate、glRotate、glScale。

一、平移glTranslatef

1.glTranslatef介绍

void WINAPI glTranslatef(
   GLfloat x,
   GLfloat y,
   GLfloat z
);
  • 沿X轴正方向平移x个单位(x是有符号数)

  • 沿Y轴正方向平移y个单位(y是有符号数)

  • 沿Z轴正方向平移z个单位(z是有符号数)

2.glTranslatef应用

众所周知:当我们利用OpenGL绘制图形时,glVertex3f第三个参数>=0的话屏幕就绘制不出效果。如下方代码:

void Draw()
{
    glClearColor(1, 1, 1, 1.0f);  //白色背景
    glClear(GL_COLOR_BUFFER_BIT);
    //绘制独立的三角形
    glBegin(GL_TRIANGLES);        //注意是逆时针绘制
    glColor4ub(0, 0, 255, 255);   //蓝
    glVertex3f(-0.2f, -0.2f, 0.0f);

    glColor4ub(255, 0, 0, 255);   //红
    glVertex3f(0.2f, -0.2f, 0.0f);

    glColor4ub(0, 255, 0, 255);   //绿
    glVertex3f(0.0f, 0.2f, 0.0f);
    glEnd();
}

所以要想获得正确的绘制效果,除了改glVertex3f的第三个参数为负数,我们还可以用矩阵转换的方式实现。

void Init()
{
    glMatrixMode(GL_PROJECTION);//将当前矩阵指定为投影矩阵,对投影矩阵操作
    gluPerspective(50.0f, 800.0f / 600.0f, 0.1f, 1000.0f);//创建一个对称的透视投影矩阵,并且用这个矩阵乘以当前矩阵
    glMatrixMode(GL_MODELVIEW); //将当前矩阵指定为模型视图矩阵,对模型视图矩阵操作
    glLoadIdentity();           //把矩阵设为单位矩阵
    glTranslatef(0, 0, - 1.5f);//此时ModedlViewMatrix就可以让之后的所有数据都带上一个-1.5的Z方向的偏移
}

二、旋转glRotatef

1.glRotatef介绍

void WINAPI glRotatef(
   GLfloat angle,
   GLfloat x,
   GLfloat y,
   GLfloat z
);

glRotatef函数针对上一个矩阵,使该矩阵以点(0,0,0)到点(x,y,z)为轴,逆时针旋转angle度。

2.glRotatef应用

void Init()
{
    glMatrixMode(GL_PROJECTION);     //将当前矩阵指定为投影矩阵,对投影矩阵操作
    gluPerspective(50.0f, 800.0f / 600.0f, 0.1f, 1000.0f);//创建一个对称的透视投影矩阵,并且用这个矩阵乘以当前矩阵
    glMatrixMode(GL_MODELVIEW);      //将当前矩阵指定为模型视图矩阵,对模型视图矩阵操作
    glLoadIdentity();                //把矩阵设为单位矩阵
    glRotatef(30, 0, 0, 1);         //此时ModedlViewMatrix就可以让之后的所有数据都绕(0,0,1)旋转30度
}

三、缩放glScalef

1.glScalef介绍

void WINAPI glScalef(
   GLfloat x,
   GLfloat y,
   GLfloat z
);

glScalef 函数沿 xyz 轴生成常规缩放。

2.glScalef应用

以第三个参数来分析:

(1)当glVertex3f的第三个参数为0,通过glTranslatef来进行矩阵平移时,在使用glScalef后绘制画面上会有图形缩放的效果。

void Init()
{
    glMatrixMode(GL_PROJECTION);     //将当前矩阵指定为投影矩阵,对投影矩阵操作
    gluPerspective(50.0f, 800.0f / 600.0f, 0.1f, 1000.0f);//创建一个对称的透视投影矩阵,并且用这个矩阵乘以当前矩阵
    glMatrixMode(GL_MODELVIEW);      //将当前矩阵指定为模型视图矩阵,对模型视图矩阵操作
    glLoadIdentity();                //把矩阵设为单位矩阵

    glTranslatef(0, 0, - 1.5f);    //平移

    glScalef(0.1f, 0.1f, 0.1f);
}

void Draw()
{
    glClearColor(1, 1, 1, 1.0f);  //白色背景
    glClear(GL_COLOR_BUFFER_BIT);

    //绘制独立的三角形
    glBegin(GL_TRIANGLES);        //注意是逆时针绘制
    glColor4ub(0, 0, 255, 255);   //蓝
    glVertex3f(-0.2f, -0.2f, 0.0f);

    glColor4ub(255, 0, 0, 255);   //红
    glVertex3f(0.2f, -0.2f, 0.0f);

    glColor4ub(0, 255, 0, 255);   //绿
    glVertex3f(0.0f, 0.2f, 0.0f);
    glEnd();
}

如上方代码:

注释glScalef(0.1f, 0.1f, 0.1f);时

添加glScalef(0.1f, 0.1f, 0.1f);时

(2)当glVertex3f的第三个参数不为0,且没有通过glTranslatef来进行矩阵平移时,由于glScalef影响了glVertex3f的第三个参数,点的绘制离摄像头近了,所以绘制后,在视觉效果上没有图形缩放的效果。如下方的代码:加上或者注释glScalef(0.1f, 0.1f, 0.1f);后画面效果不变。

void Init()
{
    glMatrixMode(GL_PROJECTION);     //将当前矩阵指定为投影矩阵,对投影矩阵操作
    gluPerspective(50.0f, 800.0f / 600.0f, 0.1f, 1000.0f);//创建一个对称的透视投影矩阵,并且用这个矩阵乘以当前矩阵
    glMatrixMode(GL_MODELVIEW);      //将当前矩阵指定为模型视图矩阵,对模型视图矩阵操作
    glLoadIdentity();                //把矩阵设为单位矩阵
    glScalef(0.1f, 0.1f, 0.1f);
}

void Draw()
{
    glClearColor(1, 1, 1, 1.0f);  //白色背景
    glClear(GL_COLOR_BUFFER_BIT);

    //绘制独立的三角形
    glBegin(GL_TRIANGLES);        //注意是逆时针绘制
    glColor4ub(0, 0, 255, 255);   //蓝
    glVertex3f(-0.2f, -0.2f, -1.5f);

    glColor4ub(255, 0, 0, 255);   //红
    glVertex3f(0.2f, -0.2f, -1.5f);

    glColor4ub(0, 255, 0, 255);   //绿
    glVertex3f(0.0f, 0.2f, -1.5f);
    glEnd();
}

四、压栈出栈

由于openGL只有一个坐标系,所以平常画物体,应该注意保存当前坐标系坐标,以便画完后返回。如下方代码:这样画A就不会影响其他部分了。

glPushMatrix()
//坐标变换。。。
//画好物体A
glPopMatrix();
//继续新的代码

1.glPushMatrix & glPopMatrix

对于矩阵的操作都是对于矩阵栈的栈顶来操作的。当前矩阵即为矩阵栈的栈顶元素,而对当前矩阵进行平移、旋转等的变换操作也同样是对栈顶矩阵的修改。所以我们在变换之前调用glPushMatrix()的话,就会把当前状态压入第二层,并且此时栈顶的矩阵也与第二层的相同。

当经过一系列的变换后,栈顶矩阵被修改,此时调用glPopMatrix()时,栈顶矩阵被弹出,且又会恢复为原来的状态。

2.举个栗子

(1)代码

void Init()
{
    glMatrixMode(GL_PROJECTION);     //将当前矩阵指定为投影矩阵,对投影矩阵操作
    gluPerspective(50.0f, 800.0f / 600.0f, 0.1f, 1000.0f);//创建一个对称的透视投影矩阵,并且用这个矩阵乘以当前矩阵
    glMatrixMode(GL_MODELVIEW);      //将当前矩阵指定为模型视图矩阵,对模型视图矩阵操作
    glLoadIdentity();                //把矩阵设为单位矩阵 
}

void Draw()
{
    glClearColor(1, 1, 1, 1.0f);  //白色背景
    glClear(GL_COLOR_BUFFER_BIT);

    glLoadIdentity();                //重置矩阵设为单位矩阵

     //glTranslatef使两个同位置的三角形分开
    glPushMatrix();
         glTranslatef(-0.4f, 0.0f, 0.0f);    //向左平移0.4个单位

         glBegin(GL_TRIANGLES);        //注意是逆时针绘制
         glColor4ub(0, 0, 255, 255);   //蓝
         glVertex3f(-0.2f, -0.2f, -1.0f);

         glColor4ub(255, 0, 0, 255);   //红
         glVertex3f(0.2f, -0.2f, -1.0f);

         glColor4ub(0, 255, 0, 255);   //绿
         glVertex3f(0.0f, 0.2f, -1.0f);
         glEnd();
    glPopMatrix();

    glPushMatrix();
         glTranslatef(0.4f, 0.0f, 0.0f);    //向右平移0.4个单位

         glBegin(GL_TRIANGLES);        //注意是逆时针绘制
         glColor4ub(0, 0, 255, 255);   //蓝
         glVertex3f(-0.2f, -0.2f, -1.0f);

         glColor4ub(255, 0, 0, 255);   //红
         glVertex3f(0.2f, -0.2f, -1.0f);

         glColor4ub(0, 255, 0, 255);   //绿
         glVertex3f(0.0f, 0.2f, -1.0f);
         glEnd();
    glPopMatrix();

(2)效果

五、注意

由于矩阵乘法不具有交换律的性质,所以对一个矩阵先旋转后平移和先平移后旋转这两种不同的操作产生的效果不同。(想想unity场景中对一个模型的操作)。

猜你喜欢

转载自blog.csdn.net/weixin_39766005/article/details/128892798