Browse Source

Merge pull request #659 from CaptainCarrot/QuatLookAt

Added a quaternion-based "Look At" function #659
Christophe 8 years ago
parent
commit
a61483b34a
3 changed files with 80 additions and 0 deletions
  1. 28 0
      glm/gtx/quaternion.hpp
  2. 34 0
      glm/gtx/quaternion.inl
  3. 18 0
      test/gtx/gtx_quaternion.cpp

+ 28 - 0
glm/gtx/quaternion.hpp

@@ -177,6 +177,34 @@ namespace glm
 		vec<3, T, P> const & orig, 
 		vec<3, T, P> const & orig, 
 		vec<3, T, P> const & dest);
 		vec<3, T, P> const & dest);
 
 
+	/// Build a look at quaternion based on the default handedness.
+	///
+	/// @param direction Desired direction of the camera.
+	/// @param up Up vector, how the camera is oriented. Typically (0, 1, 0).
+	template<typename T, precision P>
+	GLM_FUNC_DECL tquat<T, P> quatLookAt(
+		tvec3<T, P> const & direction,
+		tvec3<T, P> const & up);
+
+	/// Build a right-handed look at quaternion.
+	///
+	/// @param direction Desired direction of the camera.
+	/// @param up Up vector, how the camera is oriented. Typically (0, 1, 0).
+	template<typename T, precision P>
+	GLM_FUNC_DECL tquat<T, P> quatLookAtRH(
+		tvec3<T, P> const & direction,
+		tvec3<T, P> const & up);
+
+	/// Build a left-handed look at quaternion.
+	///
+	/// @param eye Position of the camera
+	/// @param direction Desired direction onto which the +z-axis gets mapped
+	/// @param up Up vector, how the camera is oriented. Typically (0, 1, 0).
+	template<typename T, precision P>
+	GLM_FUNC_DECL tquat<T, P> quatLookAtLH(
+		tvec3<T, P> const & direction,
+		tvec3<T, P> const & up);
+	
 	/// Returns the squared length of x.
 	/// Returns the squared length of x.
 	/// 
 	/// 
 	/// @see gtx_quaternion
 	/// @see gtx_quaternion

+ 34 - 0
glm/gtx/quaternion.inl

@@ -208,5 +208,39 @@ namespace glm
 			rotationAxis.y * invs,
 			rotationAxis.y * invs,
 			rotationAxis.z * invs);
 			rotationAxis.z * invs);
 	}
 	}
+	
+	template<typename T, precision P>
+	GLM_FUNC_QUALIFIER tquat<T, P> quatLookAt(tvec3<T, P> const& direction, tvec3<T, P> const& up)
+	{
+#		if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED
+			return quatLookAtLH(direction, up);
+#		else
+			return quatLookAtRH(direction, up);
+# 		endif
+	}
+
+	template<typename T, precision P>
+	GLM_FUNC_QUALIFIER tquat<T, P> quatLookAtRH(tvec3<T, P> const& direction, tvec3<T, P> const& up)
+	{
+		tmat3x3<T, P> Result(uninitialize);
+
+		Result[2] = -normalize(direction);
+		Result[0] = normalize(cross(up, Result[2]));
+		Result[1] = cross(Result[2], Result[0]);
+
+		return quat_cast(Result);
+	}
+
+	template<typename T, precision P>
+	GLM_FUNC_QUALIFIER tquat<T, P> quatLookAtLH(tvec3<T, P> const& direction, tvec3<T, P> const& up)
+	{
+		tmat3x3<T, P> Result(uninitialize);
+
+		Result[2] = normalize(direction);
+		Result[0] = normalize(cross(up, Result[2]));
+		Result[1] = cross(Result[2], Result[0]);
+
+		return quat_cast(Result);
+	}
 
 
 }//namespace glm
 }//namespace glm

+ 18 - 0
test/gtx/gtx_quaternion.cpp

@@ -90,6 +90,23 @@ int test_log()
 	return Error;
 	return Error;
 }
 }
 
 
+int test_quat_lookAt()
+{
+	int Error(0);
+
+	glm::vec3 eye(0.0f);
+	glm::vec3 center(1.1f, -2.0f, 3.1416f);
+	glm::vec3 up = glm::vec3(-0.17f, 7.23f, -1.744f);
+
+	glm::quat test_quat = glm::quatLookAt(center - eye, up);
+	glm::quat test_mat = glm::conjugate(glm::quat_cast(glm::lookAt(eye, center, up)));
+
+	Error += static_cast<int>(glm::abs(glm::length(test_quat) - 1.0f) > glm::epsilon<float>());
+	Error += static_cast<int>(glm::min(glm::length(test_quat + (-test_mat)), glm::length(test_quat + test_mat)) > glm::epsilon<float>());
+
+	return Error;
+}
+
 int main()
 int main()
 {
 {
 	int Error = 0;
 	int Error = 0;
@@ -98,6 +115,7 @@ int main()
 	Error += test_rotation();
 	Error += test_rotation();
 	Error += test_quat_fastMix();
 	Error += test_quat_fastMix();
 	Error += test_quat_shortMix();
 	Error += test_quat_shortMix();
+	Error += test_quat_lookAt();
 
 
 	return Error;
 	return Error;
 }
 }