Consider my following (abstracted) C# w/ SharpDX code:
class Game
{
Camera _camera = new Camera();
private void Window_KeyDown(object sender, KeyEventArgs e)
{
// Roll
if (e.KeyCode == Keys.Home)
{
_camera.TurnRoll(-0.05f);
}
else if (e.KeyCode == Keys.End)
{
_camera.TurnRoll(0.05f);
}
// Other rotation / movement works...
}
}
class Camera
{
private Vector3 _position;
private Vector3 _rotation;
private Vector3 _right;
private Vector3 _up;
private Vector3 _forward;
private Matrix _view;
public Camera()
{
_right = Vector3.Right;
_up = Vector3.Up;
_forward = Vector3.ForwardLH;
UpdateViewMatrix();
}
public void TurnRoll(float roll)
{
// Relative rotation
_rotation.Z += roll;
UpdateViewMatrix();
}
private void UpdateViewMatrix()
{
Matrix cameraRotationMatrix = Matrix.RotationYawPitchRoll(_rotation.Y, _rotation.X, _rotation.Z);
Vector3 cameraTarget = Vector3.TransformCoordinate(Vector3.ForwardLH, cameraRotationMatrix);
cameraTarget = cameraTarget.Normalize();
cameraTarget += _position;
// I bet the problem lies in and/or after this line
Matrix rotateYTempMatrix = Matrix.RotationY(_rotation.Y);
_right = Vector3.TransformCoordinate(Vector3.Right, rotateYTempMatrix);
_up = Vector3.TransformCoordinate(Vector3.Up, rotateYTempMatrix);
_forward = Vector3.TransformCoordinate(Vector3.ForwardLH, rotateYTempMatrix);
_view = Matrix.LookAtLH(_position, cameraTarget, _up);
}
}
My problem: Even when pressing the Home and End keys, the camera roll visibly stays untouched. I have trouble correcting my UpdateViewMatrix function, and I bet that the error is in there. I'm a bit lost with the maths here and my tries to use another rotation matrix to update the _up vector all failed or created other problems.
Can anybody clear my math mind up and help me correct this method?
EDIT: Solved with the help of winged's answer below. I edited the code to be
private void UpdateViewMatrix()
{
Matrix rotation = Matrix.RotationYawPitchRoll(_rotation.Y, _rotation.X, _rotation.Z);
_forward = Vector3.TransformCoordinate(Vector3.ForwardLH, rotation);
_forward += _position;
_up = Vector3.TransformCoordinate(Vector3.Up, rotation);
_view = Matrix.LookAtLH(_position, _forward, _up);
}
However, this is still not completely correct. The camera rolls now, which solves this question. But if it is rolled and I try to yaw it, the yaw happens like as if the camera is non-rolled and moves along the default Y-axis :/. Especially when looking downwards 90 degrees this causes something like gimble-lock to happen (or IS it gimble lock?) because rolling and yawing the camera has the same effect then.
EDIT2: I completely replaced my rotation with quaternions. I don't know why people think these are "harder" or at least "different" to understand. This solution works perfectly.
public void Turn(Vector3 turning)
{
// Relative rotation
Quaternion delta = Quaternion.RotationYawPitchRoll(-turning.Y, -turning.X, -turning.Z);
_rotation = delta * _rotation;
_rotation.Normalize();
UpdateViewMatrix();
}
public void TurnRoll(float roll)
{
Turn(new Vector3(0, 0, roll));
}
private void UpdateViewMatrix()
{
Matrix view = Matrix.RotationQuaternion(_rotation);
Matrix translation = Matrix.Translation(-_position.X, -_position.Y, -_position.Z);
_view = translation * view;
}