Skip to content

Instantly share code, notes, and snippets.

@anunyin
Created October 27, 2013 11:16
Show Gist options
  • Save anunyin/7180565 to your computer and use it in GitHub Desktop.
Save anunyin/7180565 to your computer and use it in GitHub Desktop.
Unity Rotation API
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