Created
October 27, 2013 11:16
-
-
Save anunyin/7180565 to your computer and use it in GitHub Desktop.
Unity Rotation API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void Entity::SetRotation(const glm::quat& rotation) | |
{ | |
m_Rotation = rotation; | |
// The const values are the world forward & world up respectively (in this case, a left-handed coordinate system). | |
m_Forward = glm::rotate(m_Rotation, glm::vec3(0.0f, 0.0f, 1.0f)); | |
m_Up = glm::rotate(m_Rotation, glm::vec3(0.0f, 1.0f, 0.0f); | |
} | |
void Entity::SetEuler(const glm::vec3& rotation) | |
{ | |
m_Rotation = glm::quat(rotation); | |
m_Forward = glm::rotate(m_Rotation, glm::vec3(0.0f, 0.0f, 1.0f)); | |
m_Up = glm::rotate(m_Rotation, glm::vec3(0.0f, 1.0f, 0.0f)); | |
} | |
void Entity::SetRotationAxis(const float angle, const glm::vec3& axis) | |
{ | |
m_Rotation = glm::rotate(glm::quat(), angle, axis); | |
m_Forward = glm::rotate(m_Rotation, glm::vec3(0.0f, 0.0f, 1.0f)); | |
m_Up = glm::rotate(m_Rotation, glm::vec3(0.0f, 1.0f, 0.0f)); | |
} | |
void Entity::SetForward(const glm::vec3& forward) | |
{ | |
m_Forward = glm::normalize(forward); | |
// Get the vector that's orthogonal to the supplied forward vector & the world up. | |
m_Up = glm::cross(m_Forward, glm::vec3(0.0f, 1.0f, 0.0f)); | |
// Get the vector that's orthogonal to the supplied forward and the previously calculated to assure that there's a 90 degree angle between the forward & up. | |
// As a side note, glm actually does this internally when constructing a lookAt matrix. So if you're keeping an external forward/up state, it might not | |
// actually be true to the value glm is constructing a matrix from, unless you do this. | |
m_Up = glm::normalize(glm::cross(m_Forward, m_Up)); | |
// Where GetRight() returns the cross product of the Up and Forward vector. | |
glm::vec3 right = GetRight(); | |
// Source: http://www.gamedev.net/topic/613595-quaternion-lookrotationlookat-up/#entry4876913 | |
float w = sqrtf(1.0f + right.x + m_Up.y + m_Forward.z) * 0.5f; | |
float w4recip = 1.0f / (4.0f * w); | |
float x = (m_Up.z - m_Forward.y) * w4recip; | |
float y = (m_Forward.x - right.z) * w4recip; | |
float z = (right.y - m_Up.x) * w4recip; | |
m_Rotation = glm::quat(w, x, y, z); | |
} | |
void Entity::SetUp(const glm::vec3& up) | |
{ | |
// The same as setting forward, but reverse the calculated vector. | |
// There's some oddity with this: | |
// For example: | |
// 1) Set the forward vector. | |
// 2) Look at the resulting calculated up vector. | |
// 3) Set the up vector to the value found in 2) | |
// 3) Look at the resulting calculated forward vector. | |
// I don't know why this happens, but this also happens in Unity's API. I haven't investigated much because | |
// this is only here for consistency in API. It's rarely practical to set the up vector itself, and even when | |
// you do you'd probably never expect it to have some determinable relationship with a reverse calculated forward vector. | |
m_Up = glm::normalize(up); | |
m_Forward = glm::cross(m_Up, glm::vec3(0.0f, 0.0f, 1.0f)); | |
m_Forward = glm::normalize(glm::cross(m_Forward, m_Up)); | |
glm::vec3 right = GetRight(); | |
float w = sqrtf(1.0f + right.x + m_Up.y + m_Forward.z) * 0.5f; | |
float w4recip = 1.0f / (4.0f * w); | |
float x = (m_Up.z - m_Forward.y) * w4recip; | |
float y = (m_Forward.x - right.z) * w4recip; | |
float z = (right.y - m_Up.x) * w4recip; | |
m_Rotation = glm::quat(w, x, y, z); | |
} | |
// And obviously you'd want getter functions. They're mostly self-explanatory since you have a quaternion, forward, and up vector held in variables. | |
// To convert a quaternion to euler angles, use glm::eulerAngles(quaternion) | |
// | |
// As of glm 0.9.4.6 there is a bug with glm::eulerAngles that makes it return degrees (despite quaternions being constructed from radians). | |
// You can call glm::radians(quaternion) to get the expected value. Or you can define the macro GLM_FORCE_RADIANS before including | |
// glm/glm.hpp to make all glm angle values be expressed in radians |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment