矩阵求逆计算的实现

矩阵求逆计算的实现

 

         学习计算机图形学,那么就应该了解计算机图形学的一些基础知识,比如说向量、矩阵、欧拉角以及四元数。其中矩阵尤其是4×4的矩阵在其中是比较重要的一部分了。因为它包含的信息多,一个4×4的矩阵可以表示平移(translation)、旋转(rotation)、缩放(scaling)以及错切(shearing)以及它们组合后的变换(transform)。其中平移、旋转是刚体转换、在三维程序中较常使用,而缩放以及错切由于改变了三维模型的形状,在实际开发中较少使用。为了表示三维图形的逆变换,引入了逆矩阵的概念。逆矩阵使得一些效果比如公告板效果的实现成为了可能。

         在上大学本科的时候,我们了解到了求矩阵的逆的方法主要有两种,第一是通过计算让其成为倒三角矩阵,然后计算其逆矩阵;另外一种方法是将矩阵和单位矩阵从左至右拼接起来,通过运算让单位矩阵移至左边,那么该矩阵的逆就到了右边了。矩阵的逆也有可能不存在,因为它的行列式值有可能为0,这种情况是无法求出矩阵的逆的。

         实际开发中,我们采用广泛使用的矩阵求逆算法:高斯 - 约旦法。有关高斯 - 约旦法的原理我也不甚了解,但是介绍高斯 - 约旦法的代码还是很多的,网上一搜就有一大堆。如果大家感兴趣这种算法的话,那么可以去到维基百科以及它提到的文献寻个究竟。

         这里我也给出自己对于这种方法的实现。这里将代码贴出来,以便日后进行查阅,同时也能够方便需要同行们。

/*---------------------------------------------------------------------------*/
bool Matrix44F::Invert( void )
{
    // 使用全选主元高斯 - 约旦法
    quint32 is[4];
    quint32 js[4];
    float det = 1.0f;
    int f = 1;
#define MATRIX( row, col ) m[row * 4 + col]
    for ( quint32 k = 0; k < 4; k++ )
    {
        // 第一步,全选主元
        float max = 0.0f;
        for ( quint32 i = k; i < 4; ++i )
        {
            for ( quint32 j = k; j < 4; ++j )
            {
                const float f = fabsf( MATRIX( i, j ) );
                if ( f > max )
                {
                    max = f;
                    is[k] = i;
                    js[k] = j;
                }
            }
        }

        if ( fabsf( max ) < 0.0001f ) return false;// 不能求逆
        if ( is[k] != k )
        {
            f = -f;
            qSwap( MATRIX( k, 0 ), MATRIX( is[k], 0 ) );
            qSwap( MATRIX( k, 1 ), MATRIX( is[k], 1 ) );
            qSwap( MATRIX( k, 2 ), MATRIX( is[k], 2 ) );
            qSwap( MATRIX( k, 3 ), MATRIX( is[k], 3 ) );
        }
        if ( js[k] != k )
        {
            f = -f;
            qSwap( MATRIX( 0, k ), MATRIX( 0, js[k] ) );
            qSwap( MATRIX( 1, k ), MATRIX( 1, js[k] ) );
            qSwap( MATRIX( 2, k ), MATRIX( 2, js[k] ) );
            qSwap( MATRIX( 3, k ), MATRIX( 3, js[k] ) );
        }

        // 计算行列值
        det *= MATRIX( k, k );

        // 计算逆矩阵(第二步)
        MATRIX( k, k ) = 1.0f / MATRIX( k, k );

        // 第三步
        for ( quint32 j = 0; j < 4; ++j )
        {
            if ( j != k ) MATRIX( k, j ) *= MATRIX( k, k );
        }

        // 第四步
        for ( quint32 i = 0; i < 4; ++i )
        {
            if ( i != k )
            {
                for ( quint32 j = 0; j < 4; ++j )
                {
                    if ( j != k )
                        MATRIX( i, j ) = MATRIX( i, j ) -
                                MATRIX( i, k ) * MATRIX( k, j );
                }
            }
        }

        // 第五步
        for ( quint32 i = 0; i < 4; ++i )
        {
            if ( i != k ) MATRIX( i, k ) *= -MATRIX( k, k );
        }
    }

    for ( qint32 k = 3; k >= 0; --k )
    {
        if ( js[k] != quint32( k ) )
        {
            qSwap( MATRIX( k, 0 ), MATRIX( js[k], 0 ) );
            qSwap( MATRIX( k, 1 ), MATRIX( js[k], 1 ) );
            qSwap( MATRIX( k, 2 ), MATRIX( js[k], 2 ) );
            qSwap( MATRIX( k, 3 ), MATRIX( js[k], 3 ) );
        }
        if ( is[k] != quint32( k ) )
        {
            qSwap( MATRIX( 0, k ), MATRIX( 0, is[k] ) );
            qSwap( MATRIX( 1, k ), MATRIX( 1, is[k] ) );
            qSwap( MATRIX( 2, k ), MATRIX( 2, is[k] ) );
            qSwap( MATRIX( 3, k ), MATRIX( 3, is[k] ) );
        }
    }

    float value = det * f;
    Q_UNUSED( value );
#undef MATRIX
    return true;// 可以求逆
}

你可能感兴趣的:(OpenGL,图形学)