Quaternion Quaternion::RotationBetween(Vector3 aStart, Vector3 aEnd) { glm::vec3 start = glm::normalize(aStart.Raw()); glm::vec3 end = glm::normalize(aEnd.Raw()); float cosTheta = glm::dot(start, end); glm::vec3 rotationAxis; if (cosTheta < -1 + 0.001f) { rotationAxis = glm::cross(Vector3::Forward(), start); if (glm::length2(rotationAxis) < 0.01f) { rotationAxis = glm::cross(Vector3::Right(), start); } rotationAxis = glm::normalize(rotationAxis); return glm::angleAxis(180.0f, rotationAxis); } rotationAxis = glm::cross(start, end); float s = glm::sqrt( (1 + cosTheta) * 2.0f); float invs = 1 / s; return glm::quat(s * 0.5f, rotationAxis.x * invs, rotationAxis.y * invs, rotationAxis.z * invs); }
Quaternion Quaternion::LookRotation(const Vector3 & aLookDirection, const Vector3 & aDesiredUp) { glm::quat quat1 = RotationBetween(Vector3::Forward(), aLookDirection).Raw(); glm::vec3 desiredUp = aDesiredUp.Raw(); glm::vec3 right = glm::cross(aLookDirection, desiredUp); desiredUp = glm::cross(right, aLookDirection); glm::vec3 newUp = quat1 * Vector3::Up().Raw(); glm::quat quat2 = RotationBetween(newUp, desiredUp); return quat2 * quat1; }