2017-06-25 5 views
0

J'ai pris les conseils de quelqu'un, mais ça n'a pas comme je voulais:DirectX Matrix: transformer par rapport à face direction (comme dans un FPS)

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

Voici le code pour ma mise à jour:

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

Le mouvement fonctionne parfaitement bien mais la rotation est incertaine. Il tourne autour de l'origine du monde pas comme un appareil photo FPS. De l'aide? J'utilise DirectX 11 avec DirectX Tool Kit. Le modèle rendu bien, le mouvement en avant, en arrière, à gauche, à droite fonctionne comme un appareil photo FPS mais c'est la rotation autour de l'origine du monde (0, 0).

Répondre

0

Voici un extrait d'un moteur de jeu plus ancien utilisant OpenGL au lieu de Direct X. Il se peut que vous deviez ajuster la rectitude du système de coordonnées, mais les principes de base s'appliquent toujours. Lorsque vous travaillez avec un mouvement dans un environnement 3D; le mouvement que la caméra, le joueur ou les objets du monde expérimentent doit être fait par une instruction switch au lieu d'un groupe d'instructions if else. Jetez un oeil à cet extrait pour le mouvement de rotation effectué dans un moteur de jeu 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 
} 

Lorsque toutes les variables locales et membres déclarés qui commencent par m_v3... sont des objets Vector3. Les objets Vector3 ont un x,y,z composants et tous les maths disponibles qui peuvent être faits aux vecteurs et Action est un type énuméré. Cette fonction est appelée dans la classe 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); 
    } 
} 

Et aussi dans 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. 
} 

Ceci est également lié à la classe GameOGL qui fonctionne avec le messageHandler() que je ne vais pas montrer ici. Cela vient d'un projet de moyenne à grande échelle qui consiste en près de 50k lignes de code. Il est trop grand pour afficher toutes les pièces ici, donc ne demandez pas parce que tout ce qui est dans ce moteur est intégré. Je montrais juste le calcul de base qui est utilisé pour faire un mouvement de rotation, soit s'il est invoqué par une pression de touche ou un mouvement de souris.

Maintenant, vous devez vous en souvenir parce que c'est important. Les calculs réels que vous voyez proviennent de la classe Player qui effectue les rotations que vous ne pouvez pas utiliser directement. Si la rectitude du système de coordonnées est différente de celle utilisée ici; vous devrez utiliser les fonctions trigonométriques appropriées pour les membres de l'axe de coordonnées appropriés avec les signes appropriés pour que les calculs soient corrects. Lorsque la rectitude change, l'axe de rotation implicite ainsi que la direction initiale de la rotation changent. Est-ce que 3D Math Fun n'est pas?

EDIT

Oh j'ai aussi remarqué que vous utilisez DirectX's::CreateFromYawPitchRoll() pour créer votre matrice de rotation; C'est correct mais vous devez faire attention aux rotations qui utilisent des Angles Euler standard. Si vous commencez à faire des rotations dans plus d'un degré de mouvement en même temps; vous finirez par expérimenter Lock Card.Pour éviter d'utiliser des problèmes de verrouillage de cardan dans les rotations 3D; Il est préférable d'utiliser Quaternions Le calcul est un peu plus difficile à comprendre, les concepts de ce qu'ils sont ne sont pas trop difficiles à comprendre, mais leur utilisation est en fait assez facile et est également très efficace sur les calculs. De nombreuses bibliothèques de mathématiques les contiennent; La bibliothèque mathématique de DirectX devrait l'être ainsi que la bibliothèque mathématique Open Source GLM qui est largement utilisée avec OpenGL & GLSL. Si vous n'êtes pas sûr de Gimbal Lock et Quaternions, vous pouvez faire une recherche Google pour rechercher ces sujets; il y a beaucoup d'informations à leur sujet. Est-ce pas Advanced 3D ... hein hem ... 4D Math Fun?

0

Vous dites qu'il tourne du point de vue de l'origine du monde, comme « si vous restez sur le bord d'un carrousel et que vous recherchez au centre »

Je pense que vous voulez que votre objet à tourner à partir de son propre centre. La solution est que vous devez faire pivoter votre objet, puis appliquer votre matrice de position.

c'est responsable

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

le correctif Je pense que devrait être d'appliquer la position après la rotation Dans OpenGl vous appliqueriez la rotation sur le modèle matrice

GLM :: mat4 MVPmatrix = projection * vue * modèle;

Vous pouvez faire pivoter la vue ou les matrices de modèle et obtenir 2 résultats différents.

Je ne suis pas au courant de votre code et DirectX en général, mais peut-être vous devriez inverser le 2

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

un coup d'oeil http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/