Unit Quaternion to a Scalar Power
I'm trying to modify a physics engine for efficiency. Currently, as objects move around the world, their orientation (a quaternion) is updated every frame, by multiplying by the rotation (another quaternion).
newOrientation = orientation*angularVelocity
This is not very efficient when the objects are far apart and the orientation is not required. What I would like to do is remember the time that orientation was last updated, and rotate only once for a given period of time.
This gives the formula:
newOrientation = orientation*(angularVelocity^timeSinceLastUpdate)
angularVelocity is a quaternion, while timeSinceLastUpdate is a scalar/real value.
What would the formula be to take a quaternion to a scalar power n?
Solution:
The full java class has been posted at:
https://github.com/Kent-H/blue3D/blob/master/Blue3D/src/blue3D/type/QuaternionF.java
Solution 1:
What would the formula be to take a quaternion to a scalar power n?
You'd need some elementary definitions for that.
Let $p=a+bi+cj+dk\in\mathbb{H}$ be a quaternion. Define, conjugacy (1), vector part (2), sign (3) and argument (4), as:
$$\overline{p}=a-bi-cj-dk\,\,\,\,\text{(1)}$$
$$\vec{u}=\frac{p-\overline{p}}{2}\,\,\,\,(2)$$
$$sgn(p)= \begin{cases} \frac{p}{|p|}, & \text{if $p\neq 0$ (3)} \\ 0, & \text{if $p=0$} \end{cases}$$
$$\arg(p)= \begin{cases} \arccos\left(\frac{a}{|p|}\right), & \text{if $p\neq 0$ (4)} \\ undefined, & \text{if $p=0$} \end{cases}$$
Exponential and logarithmic functions can now be defined, because $\mathbb{H}$ has a division algebra, so
$$\exp(p)=\exp(a)\cdot(\cos(|\vec{u}|)+sgn(\vec{u})\sin(|\vec{u}|))\,\,\,\,\text{(5)}$$
and
$$\ln(p)=\ln(|p|)+sgn(\vec{u})\arg(p)\,\,\,\,\text{(6)}$$
Your scalar power will now be:
$$q^n=\exp(n\ln(q))\,\,\,\,(7)$$
(7) now allows you to calculate directly.
Note that in this case, $n$ is a scalar, so $n\ln(q)=\ln(q)n$, so scalar powers in this case are unique modulo the branch you are working in.
Solution 2:
For anyone who's interested, here is the working (java) code.
The full class will soon be posted at:
https://github.com/Kent-H/blue3D/blob/master/Blue3D/src/blue3D/type/QuaternionF.java
/**
* sets this quaternion to this^n (for a rotation quaternion, this is equivalent to rotating this by itself n times)
* This should only work for unit quaternions.
* @param n power
* @return this
*/
public final Quaternion pow(float n){
ln().scale(n).exp();
return this;
}
public final QuaternionF exp() {
float r = (float) Math.sqrt(x*x+y*y+z*z);
float et = (float) Math.exp(w);
float s = r>=0.00001f? et*(float)Math.sin(r)/r: 0f;
w=et*(float)Math.cos(r);
x*=s;
y*=s;
z*=s;
return this;
}
public final QuaternionF ln() {
float r = (float) Math.sqrt(x*x+y*y+z*z);
float t = r>0.00001f? (float)Math.atan2(r,w)/r: 0.f;
w=0.5f*(float)Math.log(w*w+x*x+y*y+z*z);
x*=t;
y*=t;
z*=t;
return this;
}
public QuaternionF scale(float scale){
w*=scale;
x*=scale;
y*=scale;
z*=scale;
return this;
}