0

I took someone's advice but it did not work as I intended:

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

This is the code for my update:

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;
        }
    }
}

The movement works perfectly fine but the rotation is iffy. It rotates around the world origin not like an FPS camera. Any help?

I am using DirectX 11 with DirectX Tool Kit. The model rendered fine, movement forward, backwards, left, right works like an FPS camera but it is rotation the around the world origin(0, 0).

2 Answers2

0

Here is a snippet of an older Game Engine using OpenGL instead of Direct X. You may have to adjust for the handedness of the coordinate system but the basic principles still apply. When working with movement in a 3D environment; the movement that either the camera, player or world objects experience should be done through a switch statement instead of a bunch of if else statements.

Take a look at this snippet for rotational motion done within an OpenGL Game Engine.

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
}

Where all of the declared local and member variables that begin with m_v3... are Vector3 objects. Vector3 objects has a x,y,z components and all of the available math that can be done to vectors and Action is an enumerated type.

And this function is called within my Scene class.

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 );
    }
}

And also in 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.
}

This is also tied into the GameOGL class that works with the messageHandler() that I'm not going to show here. This is coming from a medium to large scale project that consists of nearly 50k lines of code. It is to large to display every working piece here so please don't ask because everything in this engine is integrated together. I just was showing the basic math that is used for doing rotational movement, either if it is invoked by a key press or mouse movement.

Now you have to remember this because it is important. The actual calculations that you see coming from the Player class that does the rotations you may not be able to use directly. If the handedness of the coordinate system is different than the one used here; you will have to use the appropriate trig functions to the appropriate coordinate axis members with the proper signs for the calculations to be correct. When the handedness changes so does the axis of rotation that is being implied as well as the initial direction of the rotation. Isn't 3D Math Fun?

EDIT

Oh I also noticed that you are using DirectX's ::CreateFromYawPitchRoll() to create your rotation matrix; this is okay but you need to be careful with rotations that use standard Euler Angles. If you begin to do rotations in more than one degree of motion at the same time; you will end up experiencing Gimbal Lock. To avoid using Gimbal Lock Problems within 3D rotations; it is better to use Quaternions The math to them is a little harder to take in, the concepts of what they are isn't too hard to understand, but using them is actually quite easy and is also very efficient on calculations. Many math libraries contain them; DirectX's math library should and so does the Open Source GLM math library that is used widely with OpenGL & GLSL. If you are unsure of Gimbal Lock and Quaternions you can do a Google search to look up those topics; there is plenty of information out there about them. Isn't Advanced 3D... eh hem... 4D Math Fun?

Francis Cugler
  • 7,788
  • 2
  • 28
  • 59
0

You say it rotates from the world origin point of view, like "if you stay on the edge of a carousel and you were looking at the center"

I think you want your object to rotate from it's own center.

The solution is that you should rotate your object and then apply your position matrix.

this is responsable

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

the fix I think should be to apply the position after the rotation In OpenGl you would apply the rotation on the Model matrice

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

you can rotate the view or the model matrices and obtain 2 differents results.

I am not aware of your code and DirectX in general but maybe you should invert the 2

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

have a look http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/

Paltoquet
  • 1,184
  • 1
  • 10
  • 18