Quantcast
Channel: GameDev.net
Viewing all articles
Browse latest Browse all 17825

Help with Quaternion Based Mouse Movement (FPS Camera)

$
0
0
Hi there! I'm really struggling here trying to wrap my brain around these different kinds of math involving Quaternions, Matrices, Vectors and whatnot. But right now, I'm just trying to create an FPS style camera using Quaternions. I'm using GLM as my math library with OpenGL. Don't let the naming in the code I show fool you, as I just can't stand the abbreviated vec3, quat, mat4, and whatnot, so I'm typedeffing them. Right now I seem to have mouse rotation mostly working, but the more I move the mouse, the more it seems like the triangle on the screen, rolls. I am normalizing the Quaternion, so I'm not sure what's going on here. All the places I've looked about mouse input seemed to have a lot of spaghetti looking code, so I don't know if I'm doing this quite right. Translating mouse delta values to rotations isn't quite clear to me. This is the triangle before I move the mouse: And here it is after I move the mouse around a little bit: Now to dive in the code. This is currently my Camera's update function void Camera::Update() { if ( g_pInput->IsButtonPressed( "Forward" ) ) { SetPosition( GetPosition() + m_vForward * 0.01f * g_pEngine->GetDeltaTime() ); } else if ( g_pInput->IsButtonPressed( "Backward" ) ) { SetPosition( GetPosition() + -m_vForward * 0.01f * g_pEngine->GetDeltaTime() ); } if ( g_pInput->IsButtonPressed( "Left" ) ) { Vector3f m_vLeft = glm::cross( m_vUp, m_vForward ); SetPosition( GetPosition() + m_vLeft * 0.01f * g_pEngine->GetDeltaTime() ); } else if ( g_pInput->IsButtonPressed( "Right" ) ) { Vector3f m_vRight = glm::cross( m_vForward, m_vUp ); SetPosition( GetPosition() + m_vRight * 0.01f * g_pEngine->GetDeltaTime() ); } m_flFrameYaw = 0.02f * g_pInput->GetMouseDeltaX() * g_pEngine->GetDeltaTime(); m_flFramePitch = 0.02f * g_pInput->GetMouseDeltaY() * g_pEngine->GetDeltaTime(); Quaternion qFrame = Quaternion( Vector3f( m_flFramePitch, m_flFrameYaw, m_flFrameRoll ) ); m_flFramePitch = 0.0f; m_flFrameYaw = 0.0f; m_flFrameRoll = 0.0f; m_qRotation = qFrame * m_qRotation; m_qRotation = glm::normalize( m_qRotation ); Matrix4f mat4Rotate = glm::toMat4( m_qRotation ); Matrix4f mat4Translate = glm::translate( GetPosition() ); m_mat4ViewMatrix = mat4Rotate * mat4Translate; } My input code at the start of the function is a bit old as I was just using glm's lookat function before, but now I want update my position based on the Quaternion rotation. So one of my questions is, how do I translate the Quaternion rotation into a Vector representing a direction? I'm guessing that's what I want to do so when I press the "forward" button I move some amount + a forward direction Vector. My other question is am I doing the mouse rotation wrong? For the sake of transparency, here's my Input class definitions, the relevant part being the Update() Input::Input() { m_pCurrentKeyboardState = nullptr; m_pOldKeyboardState = nullptr; } Input::~Input() { if ( m_pCurrentKeyboardState ) delete m_pOldKeyboardState; } bool Input::Init() { m_pCurrentKeyboardState = SDL_GetKeyboardState( &m_iNumKeys ); m_pOldKeyboardState = new Uint8[ m_iNumKeys ]; // TODO: Create config file with dynamic button mapping m_mapButtons[ "Forward" ] = SDL_SCANCODE_W; m_mapButtons[ "Backward" ] = SDL_SCANCODE_S; m_mapButtons[ "Left" ] = SDL_SCANCODE_A; m_mapButtons[ "Right" ] = SDL_SCANCODE_D; m_mapButtons[ "Jump" ] = SDL_SCANCODE_SPACE; m_mapButtons[ "Quit" ] = SDL_SCANCODE_ESCAPE; m_mapButtons[ "TurnLeft" ] = SDL_SCANCODE_LEFT; m_mapButtons[ "TurnRight" ] = SDL_SCANCODE_RIGHT; return true; } // May want to do checks to see if a button name is valid bool Input::IsButtonPressed( const std::string &strButtonName ) { return ( m_pCurrentKeyboardState[ m_mapButtons[ strButtonName ] ] == 1 ); } bool Input::IsButtonReleased( const std::string &strButtonName ) { return !IsButtonPressed( strButtonName ); } bool Input::IsButtonJustPressed( const std::string &strButtonName ) { return ( m_pCurrentKeyboardState[ m_mapButtons[ strButtonName ] ] == 1 && m_pOldKeyboardState[ m_mapButtons[ strButtonName ] ] == 0 ); } bool Input::IsButtonJustReleased( const std::string &strButtonName ) { return ( m_pCurrentKeyboardState[ m_mapButtons[ strButtonName ] ] == 0 && m_pOldKeyboardState[ m_mapButtons[ strButtonName ] ] == 1 ); } void Input::Update() { m_flMouseDeltaX = 0.0f; m_flMouseDeltaY = 0.0f; // Note: We allocate the old keyboard state in the Init function // Also no need to call SDL_GetKeyboardState as the state ponter is updated when events are processed, hence SDL_PumpEvents() std::memcpy( m_pOldKeyboardState, m_pCurrentKeyboardState, sizeof( Uint8 ) * m_iNumKeys ); SDL_PumpEvents(); while ( SDL_PollEvent( &m_event ) ) { switch ( m_event.type ) { case SDL_MOUSEMOTION: m_flMouseDeltaX = ( float ) m_event.motion.xrel; m_flMouseDeltaY = ( float ) m_event.motion.yrel; break; } } } As you can see I'm using SDL, SDL 2.0.5 to be exact. Ideally I would like to calculate the mouse delta values without polling events like that, but whatever works I guess. Lastly, I think it's worth mentioning how I compute the model matrix. This is currently done using Vectors, but I would like to do it with Quaternions for consistency sake. inline Matrix4f GetModelMatrix() const { Matrix4f posMatrix = glm::translate( m_vPosition ); Matrix4f rotXMatrix = glm::rotate( m_vRotation.x, Vector3f( 1.0f, 0.0f, 0.0f ) ); Matrix4f rotYMatrix = glm::rotate( m_vRotation.y, Vector3f( 0.0f, 1.0f, 0.0f ) ); Matrix4f rotZMatrix = glm::rotate( m_vRotation.z, Vector3f( 0.0f, 0.0f, 1.0f ) ); Matrix4f scaleMatrix = glm::scale( m_vScale ); Matrix4f rotMatrix = rotZMatrix * rotYMatrix * rotXMatrix; return posMatrix * rotMatrix * scaleMatrix; } I've already thrown a lot of code up, so I guess I'll leave it at that for now. If there's nothing that anybody finds particularly wrong, I can show stuff like the shader code and whatnot. However I'm sure that's okay. Any help is greatly appreciated though.

Viewing all articles
Browse latest Browse all 17825

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>