10
$\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$
8
  • 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$ Sep 20, 2014 at 18:21
  • $\begingroup$ BTW, this is almost certainly an appropriate question for math.se $\endgroup$ Sep 20, 2014 at 18:21
  • $\begingroup$ It can be assumed that all quaternions are normalized. $\endgroup$
    – Kent
    Sep 20, 2014 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$ Sep 20, 2014 at 18:56
  • $\begingroup$ Normalized quaternion used to represent angular velocity. $\endgroup$
    – Kent
    Sep 20, 2014 at 20:33

2 Answers 2

8
$\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$
4
$\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$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .