0

我接受了某人的建议,但它没有按我的预期工作:

    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) 旋转的。

4

2 回答 2

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()这来自一个由近 50k 行代码组成的中型到大型项目。在这里展示每一个工件都太大了,所以请不要问,因为这个引擎中的所有东西都是集成在一起的。我只是展示了用于进行旋转运动的基本数学运算,无论是通过按键还是鼠标移动来调用。

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

编辑

哦,我还注意到您正在使用DirectX's ::CreateFromYawPitchRoll()创建旋转矩阵;这没关系,但您需要小心使用标准欧拉角的旋转。如果您开始同时进行超过一个度数的旋转;您最终会遇到 Gimbal Lock。避免在 3D 旋转中使用 Gimbal Lock Problems;最好使用Quaternions数学对他们来说有点难以理解,它们的概念并不难理解,但使用它们实际上很容易并且在计算上也非常有效。许多数学库都包含它们;DirectX 的数学库应该如此,开源也应该如此GLM广泛用于 OpenGL 和 GLSL 的数学库。如果您不确定 Gimbal Lock 和 Quaternions,您可以进行 Google 搜索以查找这些主题;有很多关于他们的信息。高级 3D... 嗯哼... 4D 数学不是很有趣吗?

于 2017-06-25T06:17:09.737 回答
0

您说它从世界原点的角度旋转,例如“如果您停留在旋转木马的边缘并且正在看中心”

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

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

这是负责任的

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

我认为应该是在旋转后应用位置的修复在 OpenGl 中,您将在模型矩阵上应用旋转

glm::mat4 MVPmatrix = 投影 * 视图 * 模型;

您可以旋转视图或模型矩阵并获得 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/

于 2017-06-27T14:04:07.533 回答