I have so far used these tutorials abovebelow however I have a bug which I cannot work out how to fix.
// Quaternion Normalize Method.
Quaternion<TValue> normalize() const {
TValue magnitude = getMagnitude();
auto normalizedValues = array<TValue, 4>();
for (int i = 0; i < 4; i++){
normalizedValues[i] = m_values[i] / magnitude;
}
return Vector<dimensions, TValue>(normalizedValues);
}
// Quaternion multiplication method.
Quaternion<TValue>& operator*=(const Quaternion<TValue>& rhs) {
float x, y, z, w;
x = m_values[W] * rhs[X] + m_values[X] * rhs[W] + m_values[Y] * rhs[Z] - m_values[Z] * rhs[Y];
y = m_values[W] * rhs[Y] - m_values[X] * rhs[Z] + m_values[Y] * rhs[W] + m_values[Z] * rhs[X];
z = m_values[W] * rhs[Z] + m_values[X] * rhs[Y] - m_values[Y] * rhs[X] + m_values[Z] * rhs[W];
w = m_values[W] * rhs[W] - m_values[X] * rhs[X] - m_values[Y] * rhs[Y] - m_values[Z] * rhs[Z];
m_values[X] = x;
m_values[Y] = y;
m_values[Z] = z;
m_values[W] = w;
return *this;
};
Quaternion<TValue> conjugate() const{
return Quaternion({ { -m_values[X], -m_values[Y], -m_values[Z], m_values[W] } });
};
// Quaternion rotation method
static Quaternion<TValue> rotation(Vector<3, TValue> axis, TValue angle){
float x, y, z, w;
TValue halfTheta = angle / 2.0f;
TValue sinHalfTheta = sin(halfTheta);
return Quaternion<TValue>({ {
axis[X] * sinHalfTheta,
axis[Y] * sinHalfTheta,
axis[Z] * sinHalfTheta,
cos(halfTheta) } });
};
// Vector rotate method
Vector<dimensions, TValue> rotate(const Vector<3, TValue> axis, float angle){
Quaternion<TValue> R = Quaternion<TValue>::rotation(axis, angle);
Quaternion<TValue> V = (*this);
Vector<dimensions, TValue> result = R * V * R.conjugate();
return result;
}
// Camera rotate method.
void Camera::rotate(Vector<3,float> axis, float angle){
setLookAt(m_target.rotate(axis, angle), m_up.rotate(axis, angle));
}
// Camera setLookAt method.
void Camera::setLookAt(Vector<3, float> target, Vector<3, float> up){
Vector<3, float> newUp = up.normalize();
Vector<3, float> newTarget = target.normalize();
if (newUp != m_up || newTarget != m_target){
m_up = newUp;
m_target = newTarget;
m_right = (m_up * m_target).normalize();
m_up = m_target * m_right;
m_uvn = Matrix<4, float>::identity();
m_uvn[0][0] = m_right[Dimensions::X];
m_uvn[1][0] = m_right[Dimensions::Y];
m_uvn[2][0] = m_right[Dimensions::Z];
m_uvn[0][1] = m_up[Dimensions::X];
m_uvn[1][1] = m_up[Dimensions::Y];
m_uvn[2][1] = m_up[Dimensions::Z];
m_uvn[0][2] = m_target[Dimensions::X];
m_uvn[1][2] = m_target[Dimensions::Y];
m_uvn[2][2] = m_target[Dimensions::Z];
setViewMatrix(m_uvn * m_translation);
}
};
// Taken from game update method.
Vector<2, double> offset = getMousePosition() - m_screenCentre;
if (offset.getMagnitudeSquared() > 0.00001){
float dy = offset[Dimensions::X] * (3.1415),
dx = offset[Dimensions::Y] * (3.1415);
m_camera.rotate(Vector<3, float>({ { 0, -1, 0 } }), dy);
m_camera.rotate(Vector<3, float>(m_camera.getXAxis()), dx);
setMousePosition(m_screenCentre);
}