DirectX Matrix: преобразование относительно направления взгляда (как в FPS)

Я воспользовался чьим-то советом, но он не сработал, как я хотел:

    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 Tool Kit. Модель отрисована отлично, движение вперед, назад, влево, вправо работает как камера FPS, но вращение происходит по всему миру (0, 0).

0

Решение

Ниже приведен фрагмент старого игрового движка, использующего OpenGL вместо Direct X. Возможно, вам придется скорректировать управляемость системы координат, но основные принципы все еще применяются. При работе с движением в трехмерной среде; движение, которое испытывают либо камера, игрок или объекты мира, должно осуществляться через 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() что я не собираюсь показывать здесь. Это идет от среднего до крупного проекта, который состоит из почти 50 тысяч строк кода. Здесь можно отобразить каждую рабочую деталь, поэтому не спрашивайте, потому что все в этом движке объединено. Я только что показал основную математику, которая используется для выполнения вращательного движения, если оно вызывается нажатием клавиши или движением мыши.

Теперь вы должны помнить это, потому что это важно. Фактические расчеты, которые вы видите исходя из Player класс, который выполняет ротацию, которую вы не сможете использовать напрямую. Если управляемость системы координат отличается от используемой здесь; вам придется использовать соответствующие функции триггера для соответствующих элементов координатной оси с соответствующими знаками для правильности вычислений. При изменении направления руки меняется и подразумеваемая ось вращения, а также начальное направление вращения. Разве 3D Math Fun?

РЕДАКТИРОВАТЬ

О, я также заметил, что вы используете DirectX's ::CreateFromYawPitchRoll() создать свою матрицу вращения; это нормально, но вы должны быть осторожны с вращениями, использующими стандартные углы Эйлера. Если вы начинаете делать повороты одновременно более чем на один градус; вы в конечном итоге испытаете Gimbal Lock. Избегать использования проблем блокировки карданного подвеса в 3D поворотах; лучше использовать Quaternions Математика для них немного сложнее понять, понятия о том, чем они являются, не слишком сложны для понимания, но их использование на самом деле довольно просто и также очень эффективно для вычислений. Многие математические библиотеки содержат их; Математическая библиотека DirectX должна, как и Open Source GLM математическая библиотека, которая широко используется с OpenGL & GLSL. Если вы не уверены в Gimbal Lock и Quaternions, вы можете выполнить поиск в Google, чтобы найти эти темы; Есть много информации о них. Разве Advanced 3D … ага … 4D Math Fun?

0

Другие решения

Вы говорите, что он вращается с точки зрения мирового происхождения, например, «если вы остаетесь на краю карусели и смотрите в центр»

Я думаю, вы хотите, чтобы ваш объект вращался из своего собственного центра.

Решение состоит в том, что вы должны повернуть ваш объект и затем применить свою матрицу положения.

это ответственно

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

исправление, я думаю, должно состоять в том, чтобы применить положение после поворота
В OpenGl вы примените вращение к модели Matrice

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/

0

По вопросам рекламы [email protected]