• All submissions to this site are governed by Second Life Project Contribution Agreement. By submitting patches and other information using this site, you acknowledge that you have read, understood, and agreed to those terms.
MAINTENANCE ANNOUNCEMENT - JIRA will undergo maintenance starting 1:00am PDT through 3:00am on Saturday 2010.03.20. Please do not enter issues during this time as the system maybe restarted.
Issue Details (XML | Word | Printable)

Key: SVC-1047
Type: Bug Bug
Status: Resolved Resolved
Resolution: Won't Finish
Priority: Normal Normal
Assignee: Babbage Linden
Reporter: catherine pfeffer
Votes: 0
Watchers: 3
Operations

If you were logged in you would be able to see more operations.
2. Second Life Service - SVC

Quaternion multiplication works in reverse order in LSL as in maths

Created: 08/Dec/07 01:12 AM   Updated: 29/Oct/09 01:36 PM
Component/s: Scripts
Affects Version/s: 1.18.3
Fix Version/s: None

Time Tracking:
Not Specified

File Attachments: 1. Text File llquaternion.cpp.patch (0.9 kB)
2. File quaternions.lsl (0.9 kB)

Issue Links:
Relates
 

Source Version: 1.18.4
Linden Lab Issue ID: DEV-7373
Patch attached: Patch attached


 Description  « Hide
What you would write
R . S
in maths (R ans S being quaternions) is written
S * R
in LSL.

See attached script for a demonstration.

I'm not sure this is a bug, perharps it's just a documentation issue. And if it is a bug, I don't see how to fix it without breaking hundreds of scripts.



 All   Comments   Work Log   Change History      Sort Order: Ascending order - Click to sort in descending order
Lex Neva added a comment - 08/Dec/07 05:04 AM
Hmm... I'll preface this by saying that my only experience with quaternions is with LSL, although I'm pretty good at using them in LSL. In your code, you're treating the S parameter of each quat as the first term (a and e), but it's actually the last term. LSL quaternions are <x, y, z, s>. Will that possibly be throwing off your math?

catherine pfeffer added a comment - 08/Dec/07 06:52 AM
This is intentional, Lex.

In maths, the "real" part (a and e, in the example script), is the first coordinate. In LSL, it's the last coordinate S. See for example the wikipedia article about quaternions, or even LSL portal's page : http://wiki.secondlife.com/wiki/Quaternion, in which you will retreive the formulas used in the script.


catherine pfeffer added a comment - 08/Dec/07 09:18 PM
Copying Strife Onizuka's impressions, as they might contribute to the debate:

It's probably an artifact of LSL having the operator operands reversed and they forgot to reverse them to not match the execution order. For that to make sence you need to know that in most systems when you do (a * b), a is put on the stack before b. In LSO, b is put on the stack before a. If a and b are functions, b is executed before a. Meaning, LSL uses right to left parsing execution.


Lex Neva added a comment - 08/Dec/07 09:54 PM
Ah, I see. Scratch what I said, then. Either way, you're right: there'd be no way to fix this without breaking very many scripts... hundreds is a huge underestimate. I'd estimate hundreds of thousands at least.

Strife Onizuka added a comment - 08/Dec/07 10:05 PM
I concur, fixing it would be a bad thing.

catherine pfeffer added a comment - 08/Dec/07 10:10 PM
Yes. But is there at least a procedure to:
  • confirm the bug on the server side
  • make the lindens aware of it
  • document the bug ?

(Lex: hundreds of thousands? are there really so many people doing explicit quaternion multiplication in their scripts?)


Lex Neva added a comment - 08/Dec/07 10:44 PM
Good point... I suppose I was thinking more along the lines of any rotation math, including a vector multiplied by a rotation, but that wouldn't trigger this. Even still, I'm pretty sure there's more of this than you might think there is. Plus, this would break my brain, since, as I said, my only experience with rotation quats is in SL... I'd have to relearn the order of multiplication. I wish someone'd told me before now that LSL gets it backward.

As to your question about procedure, you're in the right place for that. This is like SVC-93... it's a good idea to document the math error even if they won't necessarily fix it because of all of the existing content.


catherine pfeffer added a comment - 08/Dec/07 11:22 PM
The "multiplication" of a vector by a quaternion cannot be in the reverse order in comparaison with maths because ... this operation simply does not exist in maths .

What exists in maths in the "conjugation". When you write in LSL
V1 = V * R;
that would be written in maths
V1 = R . V . R*
where R* is the "conjugated" of R. So there is hardly any confusion possible between LSL and maths here.

Going back to the procedure, yes, I suppose that all I can do now is sit down and wait for the eyes of a math-capable Linden to drop on this bug report. Not a very exciting way to solve problems... .


Seifert Surface added a comment - 09/Dec/07 12:11 AM
Here's a comment I found in the source code which may shed some light on the issue:

// SJB: This code is correct for a logicly stored (non-transposed) matrix;
// Our matrices are stored transposed, OpenGL style, so this generates the
// INVERSE quaternion (-x, -y, -z, w)!
// Because we use similar logic in LLQuaternion::getMatrix3,
// we are internally consistant so everything works OK

(This is in \indra\llmath\m3math.cpp).

So, it seems that the ordering is to do with OpenGL.

Personally, I haven't used quaternions outside of LSL either, but the whole subject of rotations (and more generally, much of math) is rife with inconsistencies between different conventions. At least in this case it isn't that hard to convert back and forth as and when needed.


catherine pfeffer added a comment - 09/Dec/07 12:53 AM - edited
I think the code you are pointing at is irrelevant with respect to quaternion multiplication. It has to do with conversion between 3x3 matrices and quaternions.

The "real" code seems to be in linden/indra/llmath/llquat.cpp. Look at this:

// Does NOT renormalize the result
LLQuaternion operator*(const LLQuaternion &a, const LLQuaternion &b)
{
// LLQuaternion::mMultCount++;

LLQuaternion q(
b.mQ[3] * a.mQ[0] + b.mQ[0] * a.mQ[3] + b.mQ[1] * a.mQ[2] - b.mQ[2] * a.mQ[1],
b.mQ[3] * a.mQ[1] + b.mQ[1] * a.mQ[3] + b.mQ[2] * a.mQ[0] - b.mQ[0] * a.mQ[2],
b.mQ[3] * a.mQ[2] + b.mQ[2] * a.mQ[3] + b.mQ[0] * a.mQ[1] - b.mQ[1] * a.mQ[0],
b.mQ[3] * a.mQ[3] - b.mQ[0] * a.mQ[0] - b.mQ[1] * a.mQ[1] - b.mQ[2] * a.mQ[2]
);
return q;
}

Now if you replace
< a.mQ[0], a.mQ[1], a.mQ[2], a.mQ[3]
with
<f, g, h, e>
and
< b.mQ[0], b.mQ[1], b.mQ[2], b.mQ[3]
with
<b, c, d, a>
it gives
< a * f + b * e + c * h - d * g,
a * g + c * e + d * f - b * h,
a * h + d * e + b * g - c * f,
a * e - b * f - c * g - d * h >
i.e. the same formulas as used in the attached script.

That means that
operator *(R, S)
is the same as multiply(S, R)

If I am not wrong, the problem is not in LSL evaluation order of expressions, but simply in the formulas used in llquat.cpp source code.

That not only gives us the location of guilty code, that also gives us a patch ... if we want to fix that. See debate above.


Seifert Surface added a comment - 09/Dec/07 02:44 AM
Yes, of course it isn't to do with quaternion multiplication, but it may tell us why the multiplication is the opposite way round from that which you expect. That is, quaternions are multiplied this way round because the matrices are also multiplied this way round, because of some convention used by OpenGL.

The conventions of OpenGL are a given for LL, and they had the choice to flip things the other way round so that quaternions would multiply the other way around, but chose not to, so as to be consistent with the way their matrices multiply.

I can certainly see the appeal of a system of conversions so that a * b gives the same result, whether a and b are matrices or quaternions.

And yes, I don't think there would be any way to reasonably fix it at this point. I think anyone who would notice this inconsistency with other conventions about quaternions would also be well equipped to get around the issue, no? Perhaps a note on the LSL wiki would save those people some time.


Lex Neva added a comment - 09/Dec/07 03:30 AM
It may also be the case that catherine is the first person to ever notice this

catherine pfeffer added a comment - 09/Dec/07 07:04 AM - edited
Seifert, we already have three hypotheses about the nature of this bug:
  • Strife Onizuka: it is due to LSL evaluation order
  • Seifert Surface: it lies in the conversion to OpenGL structures
  • Catherine Pfeffer: it resides in implementation of quaternion multiplication

Since the problem happens on simulator side, no one here is able to say which hypothesis is correct, because we have no access to the simulators. That is the reason why we need so bad to have a Linden look at this report...

I have attached a patch to what I believe is the problem. You will notice that is merly an inversion of quaternions a and b in computations. Very straightforward.

About my being the first person to notice it: yes. But one must be fairly paranoid to imagine that basic mathematical operators are not correctly implemented in a 3D environment. In fact I fell on this problem by chance, by trying to do manually a conjugation. I had been surprised to see that I had to use R* . V. R and not R . V. R* as you can read in every math book. I tried almost any explanation before someone pointed me to the fact that multiplication of quaternions could not work as expected. And even there I did not believe him, I did this verification just to be sure...

There are many ways to solve the problem. One is to acknowledge that LSL multiplication is not the same as mathematical one in the documentation. Another one is to define a "correct" operator, for example '%'. Yet another one is to define a variable CORRECT_QUATERNION_MULTIPLICATION in "correct" scripts. And there are perharps even more ways to solve this.


Babbage Linden added a comment - 30/Apr/08 06:47 AM
"Fixing" quaternion multiplication would silently change LSL in a way that may break existing content. We can only safely remove support for broken behaviour from the compiler and add support for new fixed behaviour, so that scripts relying on the old behaviour fail to recompile and must be explicitly changed to use the new behaviour.

catherine pfeffer added a comment - 30/Apr/08 08:15 AM
Indeed.

One way to achieve that would be to create a second operator with the correct behaviour : for example % (percent) operator or . (dot) operator. We would document that * works the reverse way and should be avoided if possible.

I vote in favour of such a solution, the most smooth and painless possible for existing scripts.


Sigma Avro added a comment - 29/Oct/09 01:36 PM
Yes a . operator or : in the right order (R:S) and S*R as deprecated option would be much more consistent with math and tensor notations