OpenGL 入门10

来源:互联网 发布:linux mv覆盖目录非空 编辑:程序博客网 时间:2024/05/17 23:09

原帖地址:
http://ogldev.atspace.co.uk/www/tutorial11/tutorial11.html
http://blog.csdn.net/cordova/article/details/52571920

复合变换

在之前的教程中,我们已经学会了如何使用变换矩阵来移动场景中的物体,如何缩放你的物体到合适的大小,以及旋转物体到合适的角度。不过我们每次都只进行了一种操作。通过让顶点与各个变换矩阵相乘来得到最终的位置,缩放或旋转角度。
M3*(M2*(M1*v)) = V

通过乘法的结合律,我们可以将M3,M2,M1相乘的结果再乘以v,进而得到与上式相同的结果。
N = M3*M2*M1
N*v = V
这意味这我们可以一次性的计算出N,然后在把这个N传给shader中的uniform variable。我们的顶点是从乘以矩阵M1开始的,然后依次从右向左乘以M2,M3。在3D图形之中,我们通常会先缩放物体,然后旋转物体最后再移动物体。对最终的物体进行相机变换以及投影到2D屏幕的计算,得到的绘制结果。如果我们对一个物体先执行旋转操作,在执行移动操作的话,如图:
这里写图片描述

如果先移动,再旋转的话,结果如下:
这里写图片描述
正如上图中看到的那样,如果我们先对一个物体移动之后在旋转的话,将会很难去设定他的位置,因为我们的旋转是以原点为参照点的,如果最后异步是旋转,因为物体已经原理原点了,这次的旋转操作将会促使物体发生移动,也就是说这个操作既有旋转又有移动,这就会变得很难操控。通过先旋转在移动的方式,我们保存了这两种操作的独立性。

代码

#define ToRadian(x) ((x) * M_PI / 180.0f)#define ToDegree(x) ((x) * 180.0f / M_PI)

定义了两个宏,用来完成度和弧度之间的转换。

inline Matrix4f operator*(const Matrix4f& Right) const{    Matrix4f Ret;    for (unsigned int i = 0 ; i < 4 ; i++) {       for (unsigned int j = 0 ; j < 4 ; j++) {           Ret.m[i][j] = m[i][0] * Right.m[0][j] +                         m[i][1] * Right.m[1][j] +                         m[i][2] * Right.m[2][j] +                         m[i][3] * Right.m[3][j];       }    }    return Ret;}

我们重载了*运算符,用来完成矩阵的乘法运算。

class Pipeline{    public:       Pipeline() { ... }       void Scale(float ScaleX, float ScaleY, float ScaleZ) { ... }       void WorldPos(float x, float y, float z) { ... }       void Rotate(float RotateX, float RotateY, float RotateZ) { ... }       const Matrix4f* GetTrans();    private:       Vector3f m_scale;       Vector3f m_worldPos;       Vector3f m_rotateInfo;       Matrix4f m_transformation;};

定义一个叫做Pipeline的类用来管理我们的缩放矩阵,平移矩阵以及旋转矩阵,m_transformation代表我们的各个变换矩阵相乘后的结果。记得m_transformation = m_worldPos*m_rotateInfo*m_scale,相乘的顺序很重要。

const Matrix4f* Pipeline::GetTrans(){    Matrix4f ScaleTrans, RotateTrans, TranslationTrans;    InitScaleTransform(ScaleTrans);    InitRotateTransform(RotateTrans);    InitTranslationTransform(TranslationTrans);    m_transformation = TranslationTrans * RotateTrans * ScaleTrans;    return &m_transformation;}

用于获取我们的变换矩阵的函数。

Pipeline p;p.Scale(sinf(Scale * 0.1f), sinf(Scale * 0.1f), sinf(Scale * 0.1f));p.WorldPos(sinf(Scale), 0.0f, 0.0f);p.Rotate(sinf(Scale) * 90.0f, sinf(Scale) * 90.0f, sinf(Scale) * 90.0f);glUniformMatrix4fv(gWorldLocation, 1, GL_TRUE, (const GLfloat*)p.GetTrans());

我们定义了一个Pipeline类型的p变量,这个变量的缩放矩阵,平移矩阵以及旋转矩阵传入的参数都包括Scale变量,所以每一帧这些矩阵都在变化,也就是说每一帧我们传给vertex shader的矩阵都不一样,这就会导致我们渲染出来的图形出现动画。

0 0