c++ - How to correctly implement a quaternion camera in modern opengl? -
i trying create uvn quaternion based camera in opengl, having used variety of tutorials listed below, , having read on quaternions , axis angle rotation. left peculiar bug cannot seem fix.
basically camera seems work fine until camera rotated approx 45 degrees +z @ point tilting camera or down seems tilt camera around target axis, turning vector.
by time camera faces along -z tilting or down gives illusion of opposite, tilts down , down tilts up.
i have seen other implementations suggesting use of non uvn system quaternions accumulated 1 describes current orientation delta arbitrary start angle. sounds great can't seem work out how implement this, conversion view matrix.
elsewhere on read splitting rotation 2 quaternions represent yaw , pitch separately i'm not convinced cause of problem since in context, correct me if wrong understanding order in apply 2 rotations not matter.
relevant source code snippets:
quarternion operations
quaternion<tvalue> conjugate() const{ return quaternion({ { -m_values[x], -m_values[y], -m_values[z], m_values[w] } }); }; quaternion<tvalue>& operator*=(const quaternion<tvalue>& rhs) { tvalue x, y, z, w; w = rhs[w] * m_values[w] - rhs[x] * m_values[x] - rhs[y] * m_values[y] - rhs[z] * m_values[z]; x = rhs[w] * m_values[x] + rhs[x] * m_values[w] - rhs[y] * m_values[z] + rhs[z] * m_values[y]; y = rhs[w] * m_values[y] + rhs[x] * m_values[z] + rhs[y] * m_values[w] - rhs[z] * m_values[x]; z = rhs[w] * m_values[z] - rhs[x] * m_values[y] + rhs[y] * m_values[x] + rhs[z] * m_values[w]; m_values[x] = x; m_values[y] = y; m_values[z] = z; m_values[w] = w; return *this; }; 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 rotation operation
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 methods
camera::camera(vector<2, int> windowsize, float fov, float near, float far): m_uvn(matrix<4, float>::identity()), m_translation(matrix<4, float>::identity()), m_ar(windowsize[dimensions::x] / (float)windowsize[dimensions::y]), m_fov(fov), m_near(near), m_far(far), m_position(), m_forward({ { 0, 0, 1 } }), m_up({ { 0, 1, 0 } }) { setviewmatrix(matrix<4, float>::identity()); setprojectionmatrix(matrix<4, float>::perspective(m_ar, m_near, m_far, m_fov)); }; matrix<4, float> camera::getvpmatrix() const{ return m_vp; }; const vector<3, float> camera::globaly = vector<3, float>({ { 0, 1, 0 } }); void camera::setprojectionmatrix(const matrix<4, float> p){ m_projection = p; m_vp = m_projection * m_view; }; void camera::setviewmatrix(const matrix<4, float> v){ m_view = v; m_vp = m_projection * m_view; }; void camera::settranslationmatrix(const matrix<4, float> t){ m_translation = t; setviewmatrix(m_uvn * m_translation); } void camera::setposition(vector<3, float> position){ if (position != m_position){ m_position = position; settranslationmatrix(matrix<4, float>::translation(-position)); } }; void camera::moveforward(float ammount){ setposition(m_position + (m_forward * ammount)); } void camera::moveright(float ammount){ setposition(m_position + (getright() * ammount)); } void camera::moveup(float ammount){ setposition(m_position + (m_up * ammount)); } void camera::setlookat(vector<3, float> target, vector<3, float> up){ vector<3, float> newup = up.normalize(); vector<3, float> newforward = target.normalize(); if (newup != m_up || newforward != m_forward){ m_up = newup; m_forward = newforward; vector<3, float> newleft = getleft(); m_up = newleft * m_forward; m_uvn = generateuvn(); setviewmatrix(m_uvn * m_translation); } }; void camera::rotatex(float angle){ vector<3, float> haxis = (globaly * m_forward).normalize(); m_forward = m_forward.rotate(haxis, angle).normalize(); m_up = (m_forward * haxis).normalize(); m_uvn = generateuvn(); setviewmatrix(m_translation * m_uvn); } void camera::rotatey(float angle){ vector<3, float> haxis = (globaly * m_forward).normalize(); m_forward = m_forward.rotate(globaly, angle).normalize(); m_up = (m_forward * haxis).normalize(); m_uvn = generateuvn(); setviewmatrix(m_translation * m_uvn); } vector<3, float> camera::getright(){ return (m_forward * m_up).normalize(); } vector <3, float> camera::getleft(){ return (m_up * m_forward).normalize(); } };
i guessing problem in either implementation of quaternion or way using it, due complex nature of system cannot seem pin down problem further that. due weird bugs being experienced unsure if there wrong way trying implement camera?
tutorials
- https://www.youtube.com/watch?v=1aw1pdu33pi
- http://www.gamedev.net/page/resources/_/technical/math-and-physics/a-simple-quaternion-based-camera-r1997
quarternion/vector math
Comments
Post a Comment