Original Post
I have implemented a camera class into my engine, but it turns out that the code I have written is very buggy. My movement and turning-speed seem to accelerate with every new step.. like.. in the beginning, it is as slow as it should be, but after a few frames of moving/rotating, I have lightning movement and rotation all of the sudden (values seem to accumulate). I need help with the code. I have probably done something wrong.
/*!
@file Camera.cs
@brief Defines camera view.
@version 1.0
*/
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using EdenEngine.Core;
namespace EdenEngine.Graphics
{
/// <summary>
/// Interface for the game view.
/// </summary>
public sealed class Camera
{
/// <summary>
/// Camera position.
/// </summary>
private Vector3 m_vec3Position;
/// <summary>
/// Horizontal rotation.
/// </summary>
private float m_fHorizontalRotation = MathHelper.PiOver2;
/// <summary>
/// Vertical rotation.
/// </summary>
private float m_fVerticalRotation = -MathHelper.PiOver2 / 10.0f;
/// <summary>
/// Rotation speed.
/// </summary>
private const float m_fRotationSpeed = 0.0008f;
/// <summary>
/// Movement speed.
/// </summary>
private const float m_fMovementSpeed = 0.03f;
/// <summary>
/// View matrix.
/// </summary>
private Matrix m_matView;
/// <summary>
/// Projection matrix.
/// </summary>
private Matrix m_matProjection;
/// <summary>
/// Reflection matrix.
/// </summary>
private Matrix m_matReflection;
/// <summary>
/// Camera instance.
/// </summary>
private static Camera s_instance = new Camera();
/// <summary>
/// Gets Camera instance.
/// </summary>
public static Camera Instance
{
get { return s_instance; }
}
/// <summary>
/// Gets view matrix.
/// </summary>
public Matrix View
{
get { return m_matView; }
}
/// <summary>
/// Gets projection matrix.
/// </summary>
public Matrix Projection
{
get { return m_matProjection; }
}
/// <summary>
/// Gets reflection matrix.
/// </summary>
public Matrix Reflection
{
get { return m_matReflection; }
}
/// <summary>
/// Gets camera position.
/// </summary>
public Vector3 Position
{
get { return m_vec3Position; }
}
/// <summary>
/// Constructor.
/// </summary>
private Camera
(
)
{
}
/// <summary>
/// Initializes camera.
/// </summary>
/// <param name="fFOV">Desired field of view angle.</param>
public void Initialize
(
ViewerProperties properties
)
{
// Set camera position.
m_vec3Position = properties.StartPosition;
// Create view matrix.
UpdateView();
// Create projection matrix.
m_matProjection = Matrix.CreatePerspectiveFieldOfView
(
properties.FieldOfViewAngle,
Renderer.Instance.Device.Viewport.AspectRatio,
0.3f,
properties.ViewDistance
);
}
/// <summary>
/// Updates view and creates view matrix.
/// </summary>
private void UpdateView
(
)
{
// Create camera rotation matrix.
Matrix cam_rot =
Matrix.CreateRotationX(m_fVerticalRotation) * Matrix.CreateRotationY(m_fHorizontalRotation);
// Declare original target and up vectors.
Vector3 cam_orig_target = new Vector3(0, 0, -1);
Vector3 cam_orig_up = new Vector3(0, 1, 0);
// Calculate rotated and final target vectors.
Vector3 cam_rot_target = Vector3.Transform(cam_orig_target, cam_rot);
Vector3 cam_fin_target = m_vec3Position + cam_rot_target;
// Calculate rotated up vector.
Vector3 cam_rot_up = Vector3.Transform(cam_orig_up, cam_rot);
// Create view matrix.
m_matView = Matrix.CreateLookAt(m_vec3Position, cam_fin_target, cam_rot_up);
// Calculate reflection matrix.
//
Vector3 refl_campos = m_vec3Position;
refl_campos.Y = -m_vec3Position.Y + Environment.Instance.WaterHeight * 2;
Vector3 refl_targetpos = cam_fin_target;
refl_targetpos.Y = -cam_fin_target.Y + Environment.Instance.WaterHeight * 2;
Vector3 cam_right = Vector3.Transform(new Vector3(1, 0, 0), cam_rot);
Vector3 inv_up = Vector3.Cross(cam_right, refl_targetpos - refl_campos);
m_matReflection = Matrix.CreateLookAt(refl_campos, refl_targetpos, inv_up);
//
}
public void Update
(
float fDeltaTime
)
{
// Check for rotation.
if (InputManager.Instance.MouseHasMoved() == true)
{
// Rotate camera.
Rotate(fDeltaTime);
}
// Check for movement.
Vector3 move_vec = new Vector3(0, 0, 0);
if (InputManager.Instance.KeyIsPressed(Keys.W))
{
move_vec += new Vector3(0, 0, -1);
}
if (InputManager.Instance.KeyIsPressed(Keys.S))
{
move_vec += new Vector3(0, 0, 1);
}
if (InputManager.Instance.KeyIsPressed(Keys.D))
{
move_vec += new Vector3(1, 0, 0);
}
if (InputManager.Instance.KeyIsPressed(Keys.A))
{
move_vec += new Vector3(-1, 0, 0);
}
Move(move_vec * fDeltaTime);
}
/// <summary>
/// Moves camera view.
/// </summary>
/// <param name="vec3Dir">Direction to move in.</param>
private void Move
(
Vector3 vec3Dir
)
{
Matrix cam_rot =
Matrix.CreateRotationX(m_fVerticalRotation) * Matrix.CreateRotationY(m_fHorizontalRotation);
Vector3 rot_vec = Vector3.Transform(vec3Dir, cam_rot);
m_vec3Position += m_fMovementSpeed * rot_vec;
UpdateView();
}
/// <summary>
/// Rotates camera view.
/// </summary>
/// <param name="fDeltaTime">Time passed since last frame.</param>
private void Rotate
(
float fDeltaTime
)
{
// Calculate rotation.
m_fHorizontalRotation -= m_fRotationSpeed * InputManager.Instance.GetMouseDelta().X * fDeltaTime;
m_fVerticalRotation -= m_fRotationSpeed * InputManager.Instance.GetMouseDelta().Y * fDeltaTime;
// Re-center mouse.
InputManager.Instance.CenterMouse();
// Update view.
UpdateView();
}
}
}