6
$\begingroup$

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

$\endgroup$
  • 1
    $\begingroup$ If you multiply the orientation by an angular velocity vector (which might be zero if the object is sitting still), then the new orientation could be the zero vector, which seems very wrong. In many systems like this, the angular velocity is a pure-vector quaternion (i.e., the real part is zero), and the update looks more like $q_{new} = q + q * \omega$, which is an euler integration of the differential equation $\dot{q} = q\omega$; you usually need to renormalize $q$ after each such update. So I guess I'm asking "Can you give a little more information about how things are represented?" $\endgroup$ – John Hughes Sep 20 '14 at 18:21
  • $\begingroup$ BTW, this is almost certainly an appropriate question for math.se $\endgroup$ – John Hughes Sep 20 '14 at 18:21
  • $\begingroup$ It can be assumed that all quaternions are normalized. $\endgroup$ – Kent Sep 20 '14 at 18:51
  • $\begingroup$ I don't think that makes sense. What's a normalized "angular velocity"? In particular, if an object is not rotation, what is its angular velocity vector? $\endgroup$ – John Hughes Sep 20 '14 at 18:56
  • $\begingroup$ Normalized quaternion used to represent angular velocity. $\endgroup$ – Kent Sep 20 '14 at 20:33
5
$\begingroup$
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.

$\endgroup$
1
$\begingroup$

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;
}
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.