Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

quaternion_exponential.inl appears to incorrectly calculate exp(q) #988

Open
Cazadorro opened this issue Jan 6, 2020 · 0 comments
Open

Comments

@Cazadorro
Copy link

Cazadorro commented Jan 6, 2020

Looking through the quaternion_exponential.inl file I found the following code for exp(quaternion).

template<typename T, qualifier Q>
GLM_FUNC_QUALIFIER qua<T, Q> exp(qua<T, Q> const& q)
{
	vec<3, T, Q> u(q.x, q.y, q.z);
	T const Angle = glm::length(u);
	if (Angle < epsilon<T>())
		return qua<T, Q>();

	vec<3, T, Q> const v(u / Angle);
	return qua<T, Q>(cos(Angle), sin(Angle) * v);
}

This does not appear to be the correct implementation for exponentiating quaternions. Using this stackexchange answer it appears like this function is missing a step. In the answer, the poster explains that exp(quat) works by:

  • z = a+v = a + a*i + b*j + c*k, in otherwords a is the real part of the quaternion (or w), and v is the ijk/vector part of the quaternion, and z is the original quaternion.

  • therefore exp(z) = exp(a + v) or exp(a)*exp(v).

  • exp(v) = cos(||v||) + v*sin(||v||)/(||v||), which is a bit like eulers formula but for quaternions.

  • therefore exp(z) = exp(a)*(cos(||v||) + v*sin(||v||)/(||v||)).

Notice the extra exp(a) term. While the above function accounts for exp(v), it does not multiply with exp(a) for the final result. I believe the correct formulation of the function is actually:

template<typename T, qualifier Q>
GLM_FUNC_QUALIFIER qua<T, Q> exp(qua<T, Q> const& q)
{
	vec<3, T, Q> u(q.x, q.y, q.z);
            T const exp_w = exp(q.w); //edited
	T const Angle = glm::length(u);
	if (Angle < epsilon<T>())
		return qua<T, Q>();

	vec<3, T, Q> const v(u / Angle);
	return qua<T, Q>(exp_w * cos(Angle), exp_w * sin(Angle) * v); //edited
}

The only time the older function would have been correct is if q.w was zero, which I don't believe is typical, even when dealing with normalized quaternions.

The issue with this is that there are actually a fair amount of situations where exponentiating a quaternion only deal with the imaginary quaternion, where people create a quaternion with an zero w component. This won't break their code, but has the potential to make it slower across linker boundaries or any situation where the compiler can't figure out that the user put zero in for w so it can't optimize out the multiplication. But at the same time, this function is just straight up wrong for quaternions in general. I'm not sure if it is worth creating a separate function ie glm::exp_imag_quat or type glm::imag_quat for this situation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants