Actually wait, I forgot @vurtun send me a link yesterday: https://gist.github.com/vurtun/82f65d6f88127d2e779949e61c2283e4

**1 div and 3 muls vs 7 muls**,

They are as fast or maybe slightly faster than quaternions, please stop answering that made up by Ginger Bill issue, there are real problems with Gibbs vectors to solve than this.

They are as fast or maybe slightly faster than quaternions, please stop answering that made up by Ginger Bill issue, there are real problems with Gibbs vectors to solve than this.

Benchmark for transforming a lot of vectors against the same quaternion or gibbs rotation: https://gist.github.com/mmozeiko/3d415e0e4783e7ab35b8a2eb1fcaec40

GCC 7.1.0 with "-ffast-math -O3":

MSVC2017 with "/fp:fast /Ox /Ot":

Using unique q/g per every vector trasnformation (so q and g are arrays with COUNT elements) doesn't change the timings much.

GCC 7.1.0 with "-ffast-math -O3":

1 2 | quats = 108.15msec gibbs = 137.24msec |

MSVC2017 with "/fp:fast /Ox /Ot":

1 2 | quats = 240.48msec gibbs = 257.08msec |

Using unique q/g per every vector trasnformation (so q and g are arrays with COUNT elements) doesn't change the timings much.

Edited by Mārtiņš Možeiko
on

Try removing `if (unlikely(dot==1.0f)) return (v3){0,0,0}; /* a == b */`

GCC:

MSVC:

MSVC shows worse numbers than GCC here because it decides to not inline qrot/grot functions. If I force inlining with " /Dinline=__forceinline /fp:fast /Ox /Ot" the results are:

1 2 | quats = 107.97msec gibbs = 118.78msec |

MSVC:

1 2 | quats = 240.22msec gibbs = 222.37msec |

MSVC shows worse numbers than GCC here because it decides to not inline qrot/grot functions. If I force inlining with " /Dinline=__forceinline /fp:fast /Ox /Ot" the results are:

1 2 | quats = 114.57msec gibbs = 158.63msec |

Edited by Mārtiņš Možeiko
on

Yeah, seeing same results on MSVC2017,

with "/fp:fast /Ox /Ot":

with "/Dinline=__forceinline /fp:fast /Ox /Ot":

with "/Dinline=__forceinline /fp:fast /Ox /Ot /arch:AVX2":

with "/fp:fast /Ox /Ot":

1 2 | quats = 252.16msec gibbs = 207.01msec |

with "/Dinline=__forceinline /fp:fast /Ox /Ot":

1 2 | quats = 122.35msec gibbs = 205.53msec |

with "/Dinline=__forceinline /fp:fast /Ox /Ot /arch:AVX2":

1 2 | quats = 94.28msec gibbs = 177.75msec |

Edited by Procedural
on

mmozeiko, what's the license of your perf test code? Can I add it to my repo under public domain?

Yes you can, I don't mind. WTFPL license :)

The real deal breaker for me is interpolation: while Gibbs vectors **can** interpolate just like quaternions, the error gets progressively worse as angle between the interpolated vectors approaches 180°.

For 45° the error is just 1°, from 45° to 90° the maximum error is 8°, from 90° to 135° is where it starts to break: 35° difference, from 135° to 180° it just becomes unusable. The error resembles an exponential curve or a parabola or something like that, I guess in theory one can find a way to weight 0.0 to 1.0 lerp's `t` values.

The code from the first post is updated.

I also added an example of compressing and restoring quaternions from Gibbs vectors: the orientation stays the same, but for a >180° quaternion Gibbs vector flips the axis and rotates to the same place from the opposite direction so that its angle stays under 180° :) If you don't care from which direction rotation happened and just want to rotate points to the same position, this can give you the same result compressed to 3 values.

For 45° the error is just 1°, from 45° to 90° the maximum error is 8°, from 90° to 135° is where it starts to break: 35° difference, from 135° to 180° it just becomes unusable. The error resembles an exponential curve or a parabola or something like that, I guess in theory one can find a way to weight 0.0 to 1.0 lerp's `t` values.

The code from the first post is updated.

I also added an example of compressing and restoring quaternions from Gibbs vectors: the orientation stays the same, but for a >180° quaternion Gibbs vector flips the axis and rotates to the same place from the opposite direction so that its angle stays under 180° :) If you don't care from which direction rotation happened and just want to rotate points to the same position, this can give you the same result compressed to 3 values.

Edited by Procedural
on

mmozeiko, thank you! I mentioned you in repo's commit.

Here I plotted 9 correct weight values for Gibbs vector to interpolate from 0° to 180° exactly like quaternion, tried to fit a parabola between them but failed, maybe someone smarter than me will figure it out eventually :)

Generally speaking, you do not want to use the exponential map for anything that isn't a differential rotation. It is properly the "angular velocity" vector, and behaves as it should for the operations one would want to perform there, so it makes some sense to use it thusly.

I do not know of any other scenario where you would prefer it over quaternions. Quaternions are better at just about everything, including interpolation, blending, joint behavior, orientation, and rotation.

Although I infer that the goal of the OP was to gain computation/space efficiency going from 4 parameters to 3, but I would point out that it is actually not the case that the fourth parameter of a quaternion is redundant. It actually encodes important information, which is where in the 720 degree angle space you are. When you go from [x,y,z,w] to [x/w,y/w,z/w], not only have you destroyed the stability of the representation by introducing an unnecessary divide, but you have also destroyed knowledge of the proper signs. [-x,-y,-z,w] and [x,y,z,-w] both map to [-x/w,-y/w,-z/w], and there's no way to ever get back.

Since most orientations in games encode the offset from parent space of a joint, 720 degrees is actually the right number of degrees because it prevents angles near 360 from appearing similar, when in fact they are not (since the organic joints we care about in games cannot "rotate through 360 degrees").

Even if somehow you found that you could eek out a small performance win with Gibbs vectors due to the reduced parameter space, I would certainly not be willing to trade all the benefits of quaternions away for it. I think people often forget that quaternions encode a larger space of rotations than matrices or the exponential map, and contrary to perhaps the prevailing wisdom, it is valuable that they do so, even if you're not a theoretical physicist :P

- Casey

I do not know of any other scenario where you would prefer it over quaternions. Quaternions are better at just about everything, including interpolation, blending, joint behavior, orientation, and rotation.

Although I infer that the goal of the OP was to gain computation/space efficiency going from 4 parameters to 3, but I would point out that it is actually not the case that the fourth parameter of a quaternion is redundant. It actually encodes important information, which is where in the 720 degree angle space you are. When you go from [x,y,z,w] to [x/w,y/w,z/w], not only have you destroyed the stability of the representation by introducing an unnecessary divide, but you have also destroyed knowledge of the proper signs. [-x,-y,-z,w] and [x,y,z,-w] both map to [-x/w,-y/w,-z/w], and there's no way to ever get back.

Since most orientations in games encode the offset from parent space of a joint, 720 degrees is actually the right number of degrees because it prevents angles near 360 from appearing similar, when in fact they are not (since the organic joints we care about in games cannot "rotate through 360 degrees").

Even if somehow you found that you could eek out a small performance win with Gibbs vectors due to the reduced parameter space, I would certainly not be willing to trade all the benefits of quaternions away for it. I think people often forget that quaternions encode a larger space of rotations than matrices or the exponential map, and contrary to perhaps the prevailing wisdom, it is valuable that they do so, even if you're not a theoretical physicist :P

- Casey

cmuratori

When you go from [x,y,z,w] to [x/w,y/w,z/w], not only have you destroyed the stability of the representation by introducing an unnecessary divide,

The only difference between a Gibbs vector and a quaternion is divide, if divide is unnecessary then it would become just a regular quaternion, isn't it? :)

Also, "destroyed" is a strong word to apply here, it's as if saying a plane crashes every time it lands on the runway, technically it's true, realistically this crash is controlled and not going to fully "destroy" a plane. If you're in a certain safe zone of operations, you're not going to "destroy" Gibbs vector stability.

cmuratori

but you have also destroyed knowledge of the proper signs. [-x,-y,-z,w] and [x,y,z,-w] both map to [-x/w,-y/w,-z/w], and there's no way to ever get back.

Depends on what you mean by getting back, [-x,-y,-z,w] and [x,y,z,-w] result in the same position in 3D, if you don't care from which direction rotation should happen and just want to point a vector in a specific direction, then the job can be done with both quaternion and Gibbs vector.

The code from the first post is updated with direction example.

Proceduralcmuratori

When you go from [x,y,z,w] to [x/w,y/w,z/w], not only have you destroyed the stability of the representation by introducing an unnecessary divide,

The only difference between a Gibbs vector and a quaternion is divide, if divide is unnecessary then it would become just a regular quaternion, isn't it? :)

Also, "destroyed" is a strong word to apply here, it's as if saying a plane crashes every time it lands on the runway, technically it's true, realistically this crash is controlled and not going to fully "destroy" a plane. If you're in a certain safe zone of operations, you're not going to "destroy" Gibbs vector stability.

cmuratori

but you have also destroyed knowledge of the proper signs. [-x,-y,-z,w] and [x,y,z,-w] both map to [-x/w,-y/w,-z/w], and there's no way to ever get back.

Depends on what you mean by getting back, [-x,-y,-z,w] and [x,y,z,-w] result in the same position in 3D, if you don't care from which direction rotation should happen and just want to point a vector in a specific direction, then the job can be done with both quaternion and Gibbs vector.

The code from the first post is updated with direction example.

his point that more often than not you

ratchetfreak

his point that more often than not you do care about the direction of rotation. If you set the quaternions up properly from the start you don't ever need to test the sign of dot(q1, q2) the 2 quaternions will just be correct from the get go.

Not sure what you mean...

ratchetfreak, I can only guess you meant that you need to check dot(g1, g2) if the angle between the Gibbs vector approaches 180°? I already said Gibbs vector interpolation is currently a real deal breaker (while an immediate rotation is as correct as quaternion one), but one can find the right weights for an exponential-like curve I posted in the screenshot above, if you weight them right you'll be able to interpolate correctly, and given 181° rotation Gibbs vector wraps to 179° in the other direction, any interpolation will always be in between 180°...

Edited by Procedural
on