Hacker News new | past | comments | ask | show | jobs | submit login

Quaternions are automatically orthogonal, whereas matrices can shear and therefore may accumulate floating point distortions under repeated opreations.[0]

Think of matrices as computational instructions, which are straightforward but lossy, while quaternions are the canonical "lossless representations".

The sweet spot for using quaternions is to use them as intermediate representations of rotation operations, then "compile" them down to a matrix once you are gonna apply it to a vector.

    ijkl_as_matrix = {
        (ll+ii)-(jj+kk), (ij+ji)-(lk+kl), (ki+ik)+(lj+jl),
        (ij+ji)+(lk+kl), (ll+jj)-(kk+ii), (jk+kj)-(li+il),
        (ki+ik)-(lj+jl), (jk+kj)+(li+il), (ll+kk)-(ii+jj),
    };
(Keep in mind that unnormalized quaternion has uniform scaling, so if your quats are unnormalized then your matrix will also apply a scale factor of dot(q,q), so you should divide your final vertex coords by that factor.)

---

[0] For an example, see https://old.reddit.com/gdd8op




Does leaving them unnormalized affect their numerical accuracy? A few sources [0] [1] suggest renormalizing often, but I'm not sure whether it's just dogmatic or if it's actually necessary. It definitely seems less involved than re-orthogonalizing matrices, in any case.

(Luckily, for my project, I'm not particularly worried about error, since the only thing being rotated frequently is the camera, and microscopic scaling and shearing won't affect the result much. I measured the error in the basis vectors over time to make sure, and it just seems to be O(sqrt(t)) random-walk noise, not anything that compounds on itself.)

[0] https://www.tobynorris.com/work/prog/csharp/quatview/help/or...

[1] https://stackoverflow.com/a/12934750


As I mentioned, unnormalized quaternions just adds an extra uniform scaling, so it’s just a matter of dividing the final vertex by qq* to remove the scaling.

EDIT: I guess if you use a shitty overzealously reduced version of the quaternion formula then you absolutely need to normalize it constantly, because the reduced formula assumed three degrees of freedom (completely defeating the purpose of using quats in the first place), normalization is then to solve a problem that you caused. But if you use a proper formula then my recommendation is actually that you never normalize your quats, instead only un-scale your vertex at the end.


I get what you mean, but it seems misleading to cite floating point issues with matrices and call quats lossless. Matrices are not inherently imprecise, they have floating point error when you use floating point numbers to represent them, and the same is absolutely true for quats too.

A better word than lossless is perhaps ‘overspecified’ when referring to a 3x3 matrix being used to represent a rotation or orientation. A 3x3 matrix has redundant information in that case (however a matrix is more general and more powerful than a quat). But axis-angle is 4D like a quat too, and more intuitive than a quaternion. Actually normalized-axis-angle (with no scaling) can beat normalized quats, because axis-angle can be a 3D value and quats cannot. Same goes for Euler angles too. In general, if your quats are implemented with floats then applying quat transforms will introduce unwanted floating point scaling that may accumulate under repeated operations (and if you compile to a matrix first then you also have the matrix problem you mentioned).


1. In this application, floating point drift affect matrices far more than quats.

Drifts in quats results in a drifted value of rotation + uniform scaling, but will never introduce deformation.

Drifts in matrices may result in total mutilation of your coordinates.

The overdetermined nature of matrices with respect to orthogonal transforms means that you lose information about which values constitute the authoritative state, whereas it is by definition impossible for a quat not to be orthogonal even when perturbed with significant error.

As an analogy, think of matrices as retained-mode GUI while quats are immediate-mode.

2. Axis angle is just the logarithm of [unit]quats (non-unit quat adds an additional scalar to the axis-angle components).

If you want to compose rotations sequentially, you'll still need to take the exponential of axis-angle to turn it into quats.

You can author initial state in axis angles as an authoritative declaration of what you meant for the orientation to be, but composing them still invariably requires you to un-logarithm them back to quats, hence what I said about "intermediate representation"

3. I said compile to a matrix at the very end when transforming the final vertices, entirely sidestepping the problem of repeated operations since you're only "baking" it for the final transformation onto vertices.


As someone not at all really familiar with maths/3D stuff, your comment gives me some relief that should I want to do any for hobby projects, I can use quaternions to avoid accumulating floating point errors.




Consider applying for YC's Summer 2025 batch! Applications are open till May 13

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: