简体   繁体   中英

3D First Person Camera strafing at angle

I have a simple camera class working in directx 11 allowing moving forward and rotating left and right. I'm trying to implement strafing into it but having some problems.

The strafing works when there's no camera rotation, so when the camera starts at 0, 0, 0. But after rotating the camera in either direction it seems to strafe at an angle or inverted or just some odd stuff.

Here is a video uploaded to Dropbox showing this behavior. https://dl.dropboxusercontent.com/u/2873587/IncorrectStrafing.mp4

And here is my camera class. I have a hunch that it's related to the calculation for camera position. I tried various different calculations in strafe and they all seem to follow the same pattern and same behavior. Also the m_camera_rotation represents the Y rotation, as pitching isn't implemented yet.

#include "camera.h"


camera::camera(float x, float y, float z, float initial_rotation) {
m_x = x;
m_y = y;
m_z = z;
m_camera_rotation = initial_rotation;

updateDXZ();
}


camera::~camera(void)
{
}

void camera::updateDXZ() {
m_dx = sin(m_camera_rotation * (XM_PI/180.0));
m_dz = cos(m_camera_rotation * (XM_PI/180.0));
}

void camera::Rotate(float amount) {
m_camera_rotation += amount;

updateDXZ();
}

void camera::Forward(float step) {
m_x += step * m_dx;
m_z += step * m_dz;
}

void camera::strafe(float amount) {
float yaw = (XM_PI/180.0) * m_camera_rotation;

m_x += cosf( yaw ) * amount;
m_z += sinf( yaw ) * amount;
}

XMMATRIX camera::getViewMatrix() {
updatePosition();

return XMMatrixLookAtLH(m_position, m_lookat, m_up);
}

void camera::updatePosition() {
m_position = XMVectorSet(m_x, m_y, m_z, 0.0);
m_lookat = XMVectorSet(m_x + m_dx, m_y, m_z + m_dz, 0.0);
m_up = XMVectorSet(0.0, 1.0, 0.0, 0.0);
}

With my many hours of frustration implementing camera systems Id suggest its something to do with your view matrix not being ortho-normalized. Thats a fancy way of saying - the three vectors represented in the matrix are not kept to the length of 1 (normalized) and also not orthogonal (at 90 degrees to each other).

The 3x3 part of a view matrix representing rotation represents 3 vectors that describe the current x,y and z axes of your view at any given time. Due to rounding off errors caused by the imprecision of float values these three vectors can stretch, shrink and diverge to cause all manner of headaches.

So a general strategy is re-orthonormalize every few frames if rotating and also another thing - when strafing or moving back/forward change the position using the current value of your view/lookat vector for back/forward and right vector for strafing.

eg

//deltaTime for all of these examples is the amount of time elapsed since the last  
//frame of your game loop - this ensures smooth movement, or you could fix your   
//timestep -  Glen Fielder did a great article on that please google for it!

void MoveForward(float deltaTime)
{
  position += (deltaTime * lookAtVector); 
}

void MoveBackwards(float deltaTime)
{
  position -= (deltaTime * lookAtVector);
}

void StrafeLeft(float deltaTime)
{
  position -= (deltaTime * rightVector);
}

//do something similar for StrafeRight but use a +=

Anyway for the rotations just rotate the view and right vectors, maybe re-write your class as follows

class Camera
{
  Vector3 rightVec,lookVec,position;

  void Rotate(float deltaTime)
}

You get the idea? Thats a rough example just to get you thinking.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM