旋转后向右、向上和向前不正确

Incorrect right, up and forward after rotation

我正在使用 OpenGL 在我的游戏中添加一个矩阵处理程序,到目前为止大部分都可以工作,但我似乎不明白如何从旋转矩阵中正确提取右、上和前向量。我有以下代码:

glm::mat4 clsMatrixHandler::SetRotation( float a_Pitch, float a_Yaw, float a_Roll )
{
    glm::mat4 l_Rotx;
    glm::mat4 l_Roty;
    glm::mat4 l_Rotz;
    PitchYawRollToXYZMatrices( a_Pitch, a_Yaw, a_Roll, l_Rotx, l_Roty, l_Rotz );
    m_PitchYawRolls.clear( );
    m_PitchYawRolls.push_back( glm::vec3( a_Pitch, a_Yaw, a_Roll ) );
    m_RotationMatrix = l_Rotx * l_Roty * l_Rotz;
    m_Right = glm::vec3( m_RotationMatrix[ 0 ][ 0 ], m_RotationMatrix[ 1 ][ 0 ], m_RotationMatrix[ 2 ][ 0 ] );
    m_Up = glm::vec3( m_RotationMatrix[ 0 ][ 1 ], m_RotationMatrix[ 1 ][ 1 ], m_RotationMatrix[ 2 ][ 1 ] );
    m_Forward = glm::vec3( m_RotationMatrix[ 0 ][ 2 ], m_RotationMatrix[ 1 ][ 2 ], m_RotationMatrix[ 2 ][ 2 ] );
    return m_RotationMatrix;
}

void clsMatrixHandler::PitchYawRollToXYZMatrices( float a_Pitch, float a_Yaw, float a_Roll, glm::mat4& a_rX, glm::mat4& a_rY, glm::mat4& a_rZ )
{
    float l_cPitch = glm::cos( glm::radians( a_Pitch ) );
    float l_sPitch = glm::sin( glm::radians( a_Pitch ) );
    float l_cYaw = glm::cos( glm::radians( a_Yaw ) );
    float l_sYaw = glm::sin( glm::radians( a_Yaw ) );
    float l_cRoll = glm::cos( glm::radians( a_Roll ) );
    float l_sRoll = glm::sin( glm::radians( a_Roll ) );
    a_rX = {
        l_cPitch, -l_sPitch, 0.0f, 0.0f,
        l_sPitch,  l_cPitch, 0.0f, 0.0f,
        0.0f,      0.0f,     1.0f, 0.0f,
        0.0f,      0.0f,     0.0f, 1.0f
    };
    a_rY = {
        l_cYaw, 0.0f, -l_sYaw, 0.0f,
        0.0f,   1.0f,  0.0f,   0.0f,
        l_sYaw, 0.0f,  l_cYaw, 0.0f,
        0.0f,   0.0f,  0.0f,   1.0f
    };
    a_rZ = {
        1.0f, 0.0f,     0.0f,    0.0f,
        0.0f, l_cRoll, -l_sRoll, 0.0f,
        0.0f, l_sRoll,  l_cRoll, 0.0f,
        0.0f, 0.0f,     0.0f,    1.0f
    };
}

void clsMatrixHandler::Test()
{
    float l_Pitch = -90.0f;
    float l_Yaw = 0.0f;
    float l_Roll = 0.0f;
    glm::mat4 l_RotationMatrix = m_MatrixHandler.SetRotation( l_Pitch, l_Yaw, l_Roll );

    std::vector<glm::vec3> l_PYRs = m_MatrixHandler.GetPitchYawRolls( );
    OutputDebugStringA( ( "Pitch: " + std::to_string( l_PYRs[ l_PYRs.size( ) - 1 ].x ) + "\n" +
                          "Yaw: " + std::to_string( l_PYRs[ l_PYRs.size( ) - 1 ].y ) + "\n" +
                          "Roll: " + std::to_string( l_PYRs[ l_PYRs.size( ) - 1 ].z ) + "\n" ).c_str( ) );

    glm::vec4 l_Point = glm::vec4( 10, 0, 0, 0 );
    glm::vec4 l_PointInLocalSpace = l_RotationMatrix * glm::vec4( l_Point.x, l_Point.y, l_Point.z, 0 );

    OutputDebugStringA( ( "New Transformation Matrix: \n" +
                          std::to_string( l_RotationMatrix[ 0 ][ 0 ] ) + ", " + std::to_string( l_RotationMatrix[ 1 ][ 0 ] ) + ", " + std::to_string( l_RotationMatrix[ 2 ][ 0 ] ) + "\n" +
                          std::to_string( l_RotationMatrix[ 0 ][ 1 ] ) + ", " + std::to_string( l_RotationMatrix[ 1 ][ 1 ] ) + ", " + std::to_string( l_RotationMatrix[ 2 ][ 1 ] ) + "\n" +
                          std::to_string( l_RotationMatrix[ 0 ][ 2 ] ) + ", " + std::to_string( l_RotationMatrix[ 1 ][ 2 ] ) + ", " + std::to_string( l_RotationMatrix[ 2 ][ 2 ] ) + "\n"
                          ).c_str( ) );

    OutputDebugStringA( ( "New Point Position: \n" + std::to_string( l_PointInLocalSpace.x ) + ", " + std::to_string( l_PointInLocalSpace.y ) + ", " + std::to_string( l_PointInLocalSpace.z ) + "\n" ).c_str( ) );
}

输出:

Pitch: -90.000000
Yaw: 0.000000
Roll: 0.000000
New Transformation Matrix: 
-0.000000, -1.000000, 0.000000
1.000000, -0.000000, 0.000000
0.000000, 0.000000, 1.000000
New Point Position: 
-0.000000, 10.000000, 0.000000

据我所知矩阵中的第一、二、三行是右上前的,所以:

Right: 0.0, -1.0, 0.0
Up: 1.0, 0.0, 0.0
Forward: 0.0, 0.0, 1.0

此外,-90 的球距现在应该指向 (0.0, 1.0, 0.0) 的前方。

  1. 我怎么可能只是滚动而不是倾斜?
  2. 为什么矩阵乘以点得到正确的结果?

在您的代码中,a_rX 计算绕 z 轴的旋转,a_rZ 计算绕 x 轴的旋转。

要解决您的问题,推介必须是:

a_rX = {
    1.0f, 0.0f,      0.0f,     0.0f,
    0.0f, l_cPitch, -l_sPitch, 0.0f,
    0.0f, l_sPitch,  l_cPitch, 0.0f,      
    0.0f, 0.0f,      0.0f,     1.0f
};

滚动必须是:

a_rZ = {
    l_cRoll, -l_sRoll, 0.0f, 0.0f,
    l_sRoll,  l_cRoll, 0.0f, 0.0f,
    0.0f,     0.0f,    1.0f, 0.0f,
    0.0f,     0.0f,    0.0f, 1.0f
};