⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mgcmatrix3.cpp

📁 《3D游戏引擎设计》的源码
💻 CPP
📖 第 1 页 / 共 4 页
字号:

    // guarantee that orthogonal matrix has determinant 1 (no reflections)
    MgcReal fDet = kQ[0][0]*kQ[1][1]*kQ[2][2] + kQ[0][1]*kQ[1][2]*kQ[2][0] +
        kQ[0][2]*kQ[1][0]*kQ[2][1] - kQ[0][2]*kQ[1][1]*kQ[2][0] -
        kQ[0][1]*kQ[1][0]*kQ[2][2] - kQ[0][0]*kQ[1][2]*kQ[2][1];

    if ( fDet < 0.0 )
    {
        for (int iRow = 0; iRow < 3; iRow++)
            for (int iCol = 0; iCol < 3; iCol++)
                kQ[iRow][iCol] = -kQ[iRow][iCol];
    }

    // build "right" matrix R
    MgcMatrix3 kR;
    kR[0][0] = kQ[0][0]*m_aafEntry[0][0] + kQ[1][0]*m_aafEntry[1][0] +
        kQ[2][0]*m_aafEntry[2][0];
    kR[0][1] = kQ[0][0]*m_aafEntry[0][1] + kQ[1][0]*m_aafEntry[1][1] +
        kQ[2][0]*m_aafEntry[2][1];
    kR[1][1] = kQ[0][1]*m_aafEntry[0][1] + kQ[1][1]*m_aafEntry[1][1] +
        kQ[2][1]*m_aafEntry[2][1];
    kR[0][2] = kQ[0][0]*m_aafEntry[0][2] + kQ[1][0]*m_aafEntry[1][2] +
        kQ[2][0]*m_aafEntry[2][2];
    kR[1][2] = kQ[0][1]*m_aafEntry[0][2] + kQ[1][1]*m_aafEntry[1][2] +
        kQ[2][1]*m_aafEntry[2][2];
    kR[2][2] = kQ[0][2]*m_aafEntry[0][2] + kQ[1][2]*m_aafEntry[1][2] +
        kQ[2][2]*m_aafEntry[2][2];

    // the scaling component
    kD[0] = kR[0][0];
    kD[1] = kR[1][1];
    kD[2] = kR[2][2];

    // the shear component
    MgcReal fInvD0 = 1.0/kD[0];
    kU[0] = kR[0][1]*fInvD0;
    kU[1] = kR[0][2]*fInvD0;
    kU[2] = kR[1][2]/kD[1];
}
//----------------------------------------------------------------------------
MgcReal MgcMatrix3::MaxCubicRoot (MgcReal afCoeff[3])
{
    // Spectral norm is for A^T*A, so characteristic polynomial
    // P(x) = c[0]+c[1]*x+c[2]*x^2+x^3 has three positive real roots.
    // This yields the assertions c[0] < 0 and c[2]*c[2] >= 3*c[1].

    // quick out for uniform scale (triple root)
    const MgcReal fOneThird = 1.0/3.0;
    const MgcReal fEpsilon = 1e-06;
    MgcReal fDiscr = afCoeff[2]*afCoeff[2] - 3.0*afCoeff[1];
    if ( fDiscr <= fEpsilon )
        return -fOneThird*afCoeff[2];

    // Compute an upper bound on roots of P(x).  This assumes that A^T*A
    // has been scaled by its largest entry.
    MgcReal fX = 1.0;
    MgcReal fPoly = afCoeff[0]+fX*(afCoeff[1]+fX*(afCoeff[2]+fX));
    if ( fPoly < 0.0 )
    {
        // uses a matrix norm to find an upper bound on maximum root
        fX = MgcMath::Abs(afCoeff[0]);
        MgcReal fTmp = 1.0+MgcMath::Abs(afCoeff[1]);
        if ( fTmp > fX )
            fX = fTmp;
        fTmp = 1.0+MgcMath::Abs(afCoeff[2]);
        if ( fTmp > fX )
            fX = fTmp;
    }

    // Newton's method to find root
    MgcReal fTwoC2 = 2.0*afCoeff[2];
    for (int i = 0; i < 16; i++)
    {
        fPoly = afCoeff[0]+fX*(afCoeff[1]+fX*(afCoeff[2]+fX));
        if ( MgcMath::Abs(fPoly) <= fEpsilon )
            return fX;

        MgcReal fDeriv = afCoeff[1]+fX*(fTwoC2+3.0*fX);
        fX -= fPoly/fDeriv;
    }

    return fX;
}
//----------------------------------------------------------------------------
MgcReal MgcMatrix3::SpectralNorm () const
{
    MgcMatrix3 kP;
    int iRow, iCol;
    MgcReal fPmax = 0.0;
    for (iRow = 0; iRow < 3; iRow++)
    {
        for (iCol = 0; iCol < 3; iCol++)
        {
            kP[iRow][iCol] = 0.0;
            for (int iMid = 0; iMid < 3; iMid++)
            {
                kP[iRow][iCol] +=
                    m_aafEntry[iMid][iRow]*m_aafEntry[iMid][iCol];
            }
            if ( kP[iRow][iCol] > fPmax )
                fPmax = kP[iRow][iCol];
        }
    }

    MgcReal fInvPmax = 1.0/fPmax;
    for (iRow = 0; iRow < 3; iRow++)
    {
        for (iCol = 0; iCol < 3; iCol++)
            kP[iRow][iCol] *= fInvPmax;
    }

    MgcReal afCoeff[3];
    afCoeff[0] = -(kP[0][0]*(kP[1][1]*kP[2][2]-kP[1][2]*kP[2][1]) +
        kP[0][1]*(kP[2][0]*kP[1][2]-kP[1][0]*kP[2][2]) +
        kP[0][2]*(kP[1][0]*kP[2][1]-kP[2][0]*kP[1][1]));
    afCoeff[1] = kP[0][0]*kP[1][1]-kP[0][1]*kP[1][0] +
        kP[0][0]*kP[2][2]-kP[0][2]*kP[2][0] +
        kP[1][1]*kP[2][2]-kP[1][2]*kP[2][1];
    afCoeff[2] = -(kP[0][0]+kP[1][1]+kP[2][2]);

    MgcReal fRoot = MaxCubicRoot(afCoeff);
    MgcReal fNorm = MgcMath::Sqrt(fPmax*fRoot);
    return fNorm;
}
//----------------------------------------------------------------------------
void MgcMatrix3::ToAxisAngle (MgcVector3& rkAxis, MgcReal& rfRadians) const
{
    // Let (x,y,z) be the unit-length axis and let A be an angle of rotation.
    // The rotation matrix is R = I + sin(A)*P + (1-cos(A))*P^2 where
    // I is the identity and
    //
    //       +-        -+
    //   P = |  0 -z +y |
    //       | +z  0 -x |
    //       | -y +x  0 |
    //       +-        -+
    //
    // If A > 0, R represents a counterclockwise rotation about the axis in
    // the sense of looking from the tip of the axis vector towards the
    // origin.  Some algebra will show that
    //
    //   cos(A) = (trace(R)-1)/2  and  R - R^t = 2*sin(A)*P
    //
    // In the event that A = pi, R-R^t = 0 which prevents us from extracting
    // the axis through P.  Instead note that R = I+2*P^2 when A = pi, so
    // P^2 = (R-I)/2.  The diagonal entries of P^2 are x^2-1, y^2-1, and
    // z^2-1.  We can solve these for axis (x,y,z).  Because the angle is pi,
    // it does not matter which sign you choose on the square roots.

    MgcReal fTrace = m_aafEntry[0][0] + m_aafEntry[1][1] + m_aafEntry[2][2];
    MgcReal fCos = 0.5*(fTrace-1.0);
    rfRadians = MgcMath::ACos(fCos);  // in [0,PI]

    if ( rfRadians > 0.0 )
    {
        if ( rfRadians < MgcMath::PI )
        {
            rkAxis.x = m_aafEntry[2][1]-m_aafEntry[1][2];
            rkAxis.y = m_aafEntry[0][2]-m_aafEntry[2][0];
            rkAxis.z = m_aafEntry[1][0]-m_aafEntry[0][1];
            rkAxis.Unitize();
        }
        else
        {
            // angle is PI
            float fHalfInverse;
            if ( m_aafEntry[0][0] >= m_aafEntry[1][1] )
            {
                // r00 >= r11
                if ( m_aafEntry[0][0] >= m_aafEntry[2][2] )
                {
                    // r00 is maximum diagonal term
                    rkAxis.x = 0.5*MgcMath::Sqrt(m_aafEntry[0][0] -
                        m_aafEntry[1][1] - m_aafEntry[2][2] + 1.0);
                    fHalfInverse = 0.5/rkAxis.x;
                    rkAxis.y = fHalfInverse*m_aafEntry[0][1];
                    rkAxis.z = fHalfInverse*m_aafEntry[0][2];
                }
                else
                {
                    // r22 is maximum diagonal term
                    rkAxis.z = 0.5*MgcMath::Sqrt(m_aafEntry[2][2] -
                        m_aafEntry[0][0] - m_aafEntry[1][1] + 1.0);
                    fHalfInverse = 0.5/rkAxis.z;
                    rkAxis.x = fHalfInverse*m_aafEntry[0][2];
                    rkAxis.y = fHalfInverse*m_aafEntry[1][2];
                }
            }
            else
            {
                // r11 > r00
                if ( m_aafEntry[1][1] >= m_aafEntry[2][2] )
                {
                    // r11 is maximum diagonal term
                    rkAxis.y = 0.5*MgcMath::Sqrt(m_aafEntry[1][1] -
                        m_aafEntry[0][0] - m_aafEntry[2][2] + 1.0);
                    fHalfInverse  = 0.5/rkAxis.y;
                    rkAxis.x = fHalfInverse*m_aafEntry[0][1];
                    rkAxis.z = fHalfInverse*m_aafEntry[1][2];
                }
                else
                {
                    // r22 is maximum diagonal term
                    rkAxis.z = 0.5*MgcMath::Sqrt(m_aafEntry[2][2] -
                        m_aafEntry[0][0] - m_aafEntry[1][1] + 1.0);
                    fHalfInverse = 0.5/rkAxis.z;
                    rkAxis.x = fHalfInverse*m_aafEntry[0][2];
                    rkAxis.y = fHalfInverse*m_aafEntry[1][2];
                }
            }
        }
    }
    else
    {
        // The angle is 0 and the matrix is the identity.  Any axis will
        // work, so just use the x-axis.
        rkAxis.x = 1.0;
        rkAxis.y = 0.0;
        rkAxis.z = 0.0;
    }
}
//----------------------------------------------------------------------------
void MgcMatrix3::FromAxisAngle (const MgcVector3& rkAxis, MgcReal fRadians)
{
    MgcReal fCos = MgcMath::Cos(fRadians);
    MgcReal fSin = MgcMath::Sin(fRadians);
    MgcReal fOneMinusCos = 1.0-fCos;
    MgcReal fX2 = rkAxis.x*rkAxis.x;
    MgcReal fY2 = rkAxis.y*rkAxis.y;
    MgcReal fZ2 = rkAxis.z*rkAxis.z;
    MgcReal fXYM = rkAxis.x*rkAxis.y*fOneMinusCos;
    MgcReal fXZM = rkAxis.x*rkAxis.z*fOneMinusCos;
    MgcReal fYZM = rkAxis.y*rkAxis.z*fOneMinusCos;
    MgcReal fXSin = rkAxis.x*fSin;
    MgcReal fYSin = rkAxis.y*fSin;
    MgcReal fZSin = rkAxis.z*fSin;
    
    m_aafEntry[0][0] = fX2*fOneMinusCos+fCos;
    m_aafEntry[0][1] = fXYM-fZSin;
    m_aafEntry[0][2] = fXZM+fYSin;
    m_aafEntry[1][0] = fXYM+fZSin;
    m_aafEntry[1][1] = fY2*fOneMinusCos+fCos;
    m_aafEntry[1][2] = fYZM-fXSin;
    m_aafEntry[2][0] = fXZM-fYSin;
    m_aafEntry[2][1] = fYZM+fXSin;
    m_aafEntry[2][2] = fZ2*fOneMinusCos+fCos;
}
//----------------------------------------------------------------------------
MgcReal MgcMatrix3::ExtractAngle (int i0) const
{
    int i1 = (i0 + 1) % 3;
    int i2 = (i0 + 2) % 3;

    if ( MgcMath::Abs(m_aafEntry[i1][i0]) < MgcMath::Abs(m_aafEntry[i2][i0]) )
        return -MgcMath::ATan2(m_aafEntry[i1][i2],m_aafEntry[i1][i1]);
    else
        return MgcMath::ATan2(m_aafEntry[i2][i1],m_aafEntry[i2][i2]);
}
//----------------------------------------------------------------------------
bool MgcMatrix3::ToEulerAnglesXYZ (float& rfYAngle, float& rfPAngle,
    float& rfRAngle)
{
    // rot =  cy*cz          -cy*sz           sy
    //        cz*sx*sy+cx*sz  cx*cz-sx*sy*sz -cy*sx
    //       -cx*cz*sy+sx*sz  cz*sx+cx*sy*sz  cx*cy

    rfPAngle = MgcMath::ASin(m_aafEntry[0][2]);
    if ( rfPAngle < MgcMath::HALF_PI )
    {
        if ( rfPAngle > -MgcMath::HALF_PI )
        {
            rfYAngle = MgcMath::ATan2(-m_aafEntry[1][2],m_aafEntry[2][2]);
            rfRAngle = MgcMath::ATan2(-m_aafEntry[0][1],m_aafEntry[0][0]);
            return true;
        }
        else
        {
            // WARNING.  Not a unique solution.
            float fRmY = MgcMath::ATan2(m_aafEntry[1][0],m_aafEntry[1][1]);
            rfRAngle = 0.0;  // any angle works
            rfYAngle = rfRAngle - fRmY;
            return false;
        }
    }
    else
    {
        // WARNING.  Not a unique solution.
        float fRpY = MgcMath::ATan2(m_aafEntry[1][0],m_aafEntry[1][1]);
        rfRAngle = 0.0;  // any angle works
        rfYAngle = fRpY - rfRAngle;
        return false;
    }
}
//----------------------------------------------------------------------------
bool MgcMatrix3::ToEulerAnglesXZY (float& rfYAngle, float& rfPAngle,
    float& rfRAngle)
{
    // rot =  cy*cz          -sz              cz*sy
    //        sx*sy+cx*cy*sz  cx*cz          -cy*sx+cx*sy*sz
    //       -cx*sy+cy*sx*sz  cz*sx           cx*cy+sx*sy*sz

    rfPAngle = MgcMath::ASin(-m_aafEntry[0][1]);
    if ( rfPAngle < MgcMath::HALF_PI )
    {
        if ( rfPAngle > -MgcMath::HALF_PI )
        {
            rfYAngle = MgcMath::ATan2(m_aafEntry[2][1],m_aafEntry[1][1]);
            rfRAngle = MgcMath::ATan2(m_aafEntry[0][2],m_aafEntry[0][0]);
            return true;
        }
        else
        {
            // WARNING.  Not a unique solution.
            float fRmY = MgcMath::ATan2(-m_aafEntry[2][0],m_aafEntry[2][2]);
            rfRAngle = 0.0;  // any angle works
            rfYAngle = rfRAngle - fRmY;
            return false;
        }
    }
    else
    {
        // WARNING.  Not a unique solution.
        float fRpY = MgcMath::ATan2(-m_aafEntry[2][0],m_aafEntry[2][2]);
        rfRAngle = 0.0;  // any angle works
        rfYAngle = fRpY - rfRAngle;
        return false;
    }
}
//----------------------------------------------------------------------------
bool MgcMatrix3::ToEulerAnglesYXZ (float& rfYAngle, float& rfPAngle,
    float& rfRAngle)
{
    // rot =  cy*cz+sx*sy*sz  cz*sx*sy-cy*sz  cx*sy
    //        cx*sz           cx*cz          -sx
    //       -cz*sy+cy*sx*sz  cy*cz*sx+sy*sz  cx*cy

    rfPAngle = MgcMath::ASin(-m_aafEntry[1][2]);
    if ( rfPAngle < MgcMath::HALF_PI )
    {
        if ( rfPAngle > -MgcMath::HALF_PI )
        {
            rfYAngle = MgcMath::ATan2(m_aafEntry[0][2],m_aafEntry[2][2]);
            rfRAngle = MgcMath::ATan2(m_aafEntry[1][0],m_aafEntry[1][1]);
            return true;
        }
        else
        {
            // WARNING.  Not a unique solution.
            float fRmY = MgcMath::ATan2(-m_aafEntry[0][1],m_aafEntry[0][0]);
            rfRAngle = 0.0;  // any angle works
            rfYAngle = rfRAngle - fRmY;
            return false;
        }
    }
    else
    {
        // WARNING.  Not a unique solution.
        float fRpY = MgcMath::ATan2(-m_aafEntry[0][1],m_aafEntry[0][0]);
        rfRAngle = 0.0;  // any angle works
        rfYAngle = fRpY - rfRAngle;
        return false;
    }
}
//----------------------------------------------------------------------------
bool MgcMatrix3::ToEulerAnglesYZX (float& rfYAngle, float& rfPAngle,
    float& rfRAngle)
{
    // rot =  cy*cz           sx*sy-cx*cy*sz  cx*sy+cy*sx*sz
    //        sz              cx*cz          -cz*sx
    //       -cz*sy           cy*sx+cx*sy*sz  cx*cy-sx*sy*sz

    rfPAngle = MgcMath::ASin(m_aafEntry[1][0]);
    if ( rfPAngle < MgcMath::HALF_PI )
    {
        if ( rfPAngle > -MgcMath::HALF_PI )
        {
            rfYAngle = MgcMath::ATan2(-m_aafEntry[2][0],m_aafEntry[0][0]);
            rfRAngle = MgcMath::ATan2(-m_aafEntry[1][2],m_aafEntry[1][1]);
            return true;
        }
        else
        {
            // WARNING.  Not a unique solution.
            float fRmY = MgcMath::ATan2(m_aafEntry[2][1],m_aafEntry[2][2]);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -