DirectX Matrix:相对于面向方向的变换(如在FPS中)

时间:2017-06-25 05:38:01

标签: c++ matrix directx directx-11 directxtk

我接受了某人的建议,但它并没有像我预期的那样工作:

    M=inverse(inverse(M)*rotation_matrix);

这是我的更新代码:

void TestApp::Update(float dt) {
    DirectX::SimpleMath::Matrix rotation =
    Matrix::CreateFromYawPitchRoll(rot.y, rot.x, 0.0f); //Rotation Matrix
    DirectX::SimpleMath::Matrix position = 
    Matrix::CreateTranslation(pos); //Postion Matrix

    m_view = 
    DirectX::XMMatrixInverse(nullptr, DirectX::XMMatrixMultiply( 
    DirectX::XMMatrixInverse(nullptr, position), rotation)); //This uses the advice
//m_view is the Camera/View Matrix

for (int i = 0; i < 256; ++i) {
    if (GetAsyncKeyState(i)) {
        if (i == 87) { // W
            pos.z += dt * playerSpeed; //Move Forward

            continue;

        }
        else if (i == 68) { //D
            pos.x -= dt * playerSpeed; //Move Right
            continue;

        }
        else if(i == 83){//S
            pos.z -= dt * playerSpeed; //Move Backwards
            continue;

        }
        else if (i == 65) { // A
            pos.x += dt * playerSpeed; //Move Left
            continue;

        }

        else if (i == VK_NUMPAD8) {
            rot.x -= dt; 
            continue;
        }
        else if (i == VK_NUMPAD4) {
            rot.y += dt;
        }
        else if (i == VK_NUMPAD5) {
            rot.x += dt;
            continue;
        }
        else if (i == VK_NUMPAD6) {
            rot.y -= dt;
        }
    }
}

运动完美无瑕,但旋转效果不佳。它围绕世界起源旋转,而不像FPS相机。有什么帮助吗?

我正在使用DirectX 11和DirectX工具包。模型呈现精细,向前,向后,向左,向右移动就像一个FPS相机,但它是围绕世界原点旋转(0,0)。

2 个答案:

答案 0 :(得分:0)

以下是使用OpenGL而不是Direct X的旧游戏引擎的片段。您可能需要调整坐标系的灵活性,但基本原则仍然适用。在3D环境中进行移动时;相机,玩家或世界物体经历的运动应该通过switch语句而不是一堆if else语句来完成。

看一下这个片段,了解在OpenGL游戏引擎中完成的旋转运动。

void Player::move( Action action, float fDeltaTime ) {
    v3LookDirection = m_v3LookCenter - m_v3Position;

    switch( action ) {
        case MOVING_FORWARD: {
            // ... code here ...
        }
        case MOVING_BACK: {
            // ... code here ...
        }
        case MOVING_RIGHT: {
            // ... code here ...
        }
        case MOVING_LEFT: {
            // ... code here ...
        }
        case LOOKING_LEFT: {        
            /*float fSin = -sin( fDeltaTime * m_fAngularSpeed );
            float fCos =  cos( fDeltaTime * m_fAngularSpeed );

            m_v3LookCenter.m_fX = m_v3Position.m_fX + (-fSin * v3LookDirection.m_fZ + fCos * v3LookDirection.m_fX );
            m_v3LookCenter.m_fZ = m_v3Position.m_fZ + ( fCos * v3LookDirection.m_fZ + fSin * v3LookDirection.m_fX );
            break;*/

            // Third Person
            float fSin = sin( fDeltaTime * m_fAngularSpeed );
            float fCos = -cos( fDeltaTime * m_fAngularSpeed );

            m_v3Position.m_fX = m_v3LookCenter.m_fX + (-fSin * v3LookDirection.m_fZ + fCos * v3LookDirection.m_fX );
            m_v3Position.m_fZ = m_v3LookCenter.m_fZ + ( fCos * v3LookDirection.m_fZ + fSin * v3LookDirection.m_fX );
            break;
        }
        case LOOKING_RIGHT: {
            /*float fSin = sin( fDeltaTime * m_fAngularSpeed );
            float fCos = cos( fDeltaTime * m_fAngularSpeed );

            m_v3LookCenter.m_fX = m_v3Position.m_fX + (-fSin * v3LookDirection.m_fZ + fCos * v3LookDirection.m_fX );
            m_v3LookCenter.m_fZ = m_v3Position.m_fZ + ( fCos * v3LookDirection.m_fZ + fSin * v3LookDirection.m_fX );
            break;*/

            // Third Person
            float fSin = -sin( fDeltaTime * m_fAngularSpeed );
            float fCos = -cos( fDeltaTime * m_fAngularSpeed );

            m_v3Position.m_fX = m_v3LookCenter.m_fX + (-fSin * v3LookDirection.m_fZ + fCos * v3LookDirection.m_fX );
            m_v3Position.m_fZ = m_v3LookCenter.m_fZ + ( fCos * v3LookDirection.m_fZ + fSin * v3LookDirection.m_fX );
            break;
        }
        case LOOKING_UP: {
            m_v3LookCenter.m_fY -= fDeltaTime * m_fAngularSpeed * m_MouseLookState;

            // Check Maximum Values
            if ( m_v3LookCenter.m_fY > (m_v3Position.m_fY + m_fMaxUp ) ) {
                m_v3LookCenter.m_fY = m_v3Position.m_fY + m_fMaxUp;
            } else if ( m_v3LookCenter.m_fY < (m_v3Position.m_fY - m_fMaxDown) ) {
                m_v3LookCenter.m_fY = m_v3Position.m_fY - m_fMaxDown;
            }
            break;
        }
    } // switch
}

所有以m_v3...开头的声明的本地和成员变量都是Vector3对象。 Vector3对象有一个x,y,z个组件,可以对向量进行所有可用的数学运算,Action是一个枚举类型。

此函数在我的Scene类中调用。

void Scene::playerAction( float fMouseXDelta, float fMouseYDelta ) {
    if ( fMouseXDelta != 0.0f ) {
        m_player.move( LOOKING_RIGHT, fMouseXDelta );
    }

    if ( fMouseYDelta != 0.0f ) {
         m_player.move( LOOKING_UP, fMouseYDelta );
    }
}

还有Scene::update()

void Scene::update() {
    UserSettings* pUserSettings = UserSettings::get();
    AudioManager* pAudio = AudioManager::getAudio();

    bool bPlayerMoving = false;

    // Movement
    if ( pUserSettings->isAction( MOVING_FORWARD ) ) {
        m_player.move( MOVING_FORWARD, GameOGL::getPhysicsTimeStep() );
        bPlayerMoving = true;
    }

    if ( pUserSettings->isAction( MOVING_BACK ) ) {
        m_player.move( MOVING_BACK, GameOGL::getPhysicsTimeStep() );
        bPlayerMoving = true;
    }

    if ( pUserSettings->isAction( MOVING_LEFT ) ) {
        m_player.move( MOVING_LEFT, GameOGL::getPhysicsTimeStep() );
        bPlayerMoving = true;
    }

    if ( pUserSettings->isAction( MOVING_RIGHT ) ) {
        m_player.move( MOVING_RIGHT, GameOGL::getPhysicsTimeStep() );
        bPlayerMoving = true;
    }    

    if ( bPlayerMoving && !m_bPlayerWalking ) {
        pAudio->setLooping( AUDIO_FOOTSTEPS, true );
        pAudio->play( AUDIO_FOOTSTEPS );
        m_bPlayerWalking = true;
    }
    else if ( !bPlayerMoving && m_bPlayerWalking ) {
        pAudio->stop( AUDIO_FOOTSTEPS );
        m_bPlayerWalking = false;
    }

    // Bunch more code here.
}

这也与GameOGL类相关联,该messageHandler()类与Player一起使用,我将不会在此处显示。这是一个由大约5万行代码组成的中型到大型项目。这里显示每个工件都很大,所以请不要问,因为这个引擎中的所有东西都集成在一起。我正在展示用于进行旋转运动的基本数学运算,无论是通过按键还是鼠标移动来调用。

现在你必须记住这一点,因为它很重要。您看到来自执行轮换的DirectX's类的实际计算可能无法直接使用。如果坐标系的手性不同于此处使用的坐标系;您必须使用适当的三角函数到适当的坐标轴成员,并使用适当的符号进行计算才能正确。当旋向性改变时,所暗示的旋转轴以及旋转的初始方向也改变。不是3D数学乐趣吗?

修改

哦我也注意到你正在使用::CreateFromYawPitchRoll() Quaternions来创建旋转矩阵;这没关系,但你需要注意使用标准欧拉角的旋转。如果你开始同时以超过一个运动程度进行旋转;你最终会体验到万向节锁。避免在3D旋转中使用万向节锁定问题;最好使用GLM对它们的数学有点难以理解,它们的概念并不难理解,但使用它们实际上非常简单,并且计算效率也很高。许多数学库包含它们; DirectX的数学库以及开放源代码{{1}}数学库应该与OpenGL&amp; GLSL。如果您不确定Gimbal Lock和Quaternions,您可以通过Google搜索来查找这些主题;那里有很多关于他们的信息。不是高级3D ......呃下摆...... 4D数学乐趣?

答案 1 :(得分:0)

你说它从世界原点来看是旋转的,就像“如果你留在旋转木马的边缘而你正在看中心”

我认为你希望你的物体从它自己的中心旋转。

解决方案是你应该旋转你的对象,然后应用你的位置矩阵。

这是负责任的

m_view = 
    DirectX::XMMatrixInverse(nullptr, DirectX::XMMatrixMultiply( 
    DirectX::XMMatrixInverse(nullptr, position), rotation))

我认为修复应该是在旋转后应用位置 在OpenGl中,您可以在Model matrice上应用旋转

glm :: mat4 MVPmatrix = projection * view * model;

您可以旋转视图或模型矩阵,并获得2个不同的结果。

我一般都不知道你的代码和DirectX,但也许你应该反转2

m_view = 
        DirectX::XMMatrixInverse(nullptr, DirectX::XMMatrixMultiply( 
        DirectX::XMMatrixInverse(nullptr, rotation), position))

看看http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/