• 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.
Issue Details (XML | Word | Printable)

Key: SVC-93
Type: Bug Bug
Status: Open Open
Priority: Critical Critical
Assignee: Andrew Linden
Reporter: Lex Neva
Votes: 111
Watchers: 41
Operations

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

llSetPrimitiveParams PRIM_ROTATION and llSetRot incorrectly implemented for child prims

Created: 06/Apr/07 09:34 AM   Updated: Yesterday 08:44 PM
Return to search
Component/s: Scripts
Affects Version/s: 1.13.4
Fix Version/s: None

Issue Links:
Parent/Child
 
Relates
 

Linden Lab Issue ID: DEV-1178


 Description  « Hide
This bug has been around for at least a year. In short, llSetPrimitiveParams([PRIM_POSITION, ...]) and llSetRot in a child prim is implemented incorrectly, resulting in unexpected results. I've been able to determine the exact nature of the implementation bug and have reported this in the past, but nevertheless the issue remains. I believe this is because rotation math is tricky stuff, so not many people notice that anything is actually wrong.

In a child prim, it the rotation of a child prim is stored internally by SL as a rotation relative to the root prim of the link set. llSetLocalRot() sets this rotation verbatim. llSetRot() in a child prim should set the prim such that its world-relative rotation is equal to the argument passed.

Logically, the following should be a no-op in a child prim:

llSetLocalRot(llGetLocalRot());

It is, in fact. The following should also be a no-op in a child prim:

llSetRot(llGetRot());

It's not. The result is that the child prim rotates some amount every time the preceding line is run.

Since child prim rotations are stored as a rotation relative to the root prim, the following should be a pseudo-implementation of llSetRot() in a child prim:

llSetRot(rotation rot) {
        llSetLocalRot(rot/llGetRootRotation());
    }

The above code uses rotation division. In essence, this says, "tell me rot as a rotation relative to llGetRootRotation()". This is how quaternions work.

Through extensive testing, I've determined that it's actually implemented as the following:

llSetRot(rotation rot) {
        llSetLocalRot(rot * llGetRootRotation());
    }

That's right: the internal code that implements llSetRot() and PRIM_ROTATION for child prims uses a quaternion multiplication when it should use a division. I'm absolutely sure of this.

To work around this, normally it's enough to just avoid using llSetRot() in a child prim, and to get the same functionality by using llSetLocalRot() as I showed above. However, if it's critical that the rotation and position of a child prim are set at the same instant, the only possible way to do this is llSetPrimitiveParams([PRIM_POSITION, ..., PRIM_ROTATION, ...]);. This means that you have no choice but to use the buggy PRIM_ROTATION implementation.

If you must set a child prim to a world-relative rotation rot using PRIM_ROTATION (or llSetRot()), use this:

llSetPrimitiveParams([PRIM_ROTATION, (rot / llGetRootRotation) / llGetRootRotation);

If you must set a child prim to a local rotation rot using PRIM_ROTATION, use this:

llSetPrimitiveParams([PRIM_ROTATION, rot/llGetRootRotation]);

Furthermore, llGetRootRotation does not return a meaningful result for child prims in attachments.

Those examples both illustrate quaternion math that does not make sense. They only work because of the errant multiply operation carried out behind the scenes. Countless scripters in-world and in the forums have essentially stumbled upon these workarounds by doing various quaternion operations until the right thing happens[1]. I (and possibly others) worked out the actual problem and use the above workarounds routinely when I need to. Simply fixing PRIM_ROTATION will, unfortunately, break a lot of content. A new function, llSetRotCorrectly(), and a new operation, PRIM_ROTATION_CORRECT, will need to be implemented to fix this bug.

As nearly as I can tell, this bug has been around since llSetRot() was first implemented, and was carried on when llSetPrimitiveParams() was implemented.

[1] http://forums.secondlife.com/showpost.php?p=943944&postcount=2



 All   Comments   Change History      Sort Order: Ascending order - Click to sort in descending order
Lex Neva made changes - 06/Apr/07 09:35 AM
Field Original Value New Value
Link This issue is related to by MISC-104 [ MISC-104 ]
Lex Neva made changes - 06/Apr/07 09:38 AM
Description This bug has been around for at least a year. In short, llSetPrimitiveParams([PRIM_POSITION, ...]) and llSetRot in a child prim is implemented INCORRECTLY, resulting in unexpected results. I've been able to determine the exact nature of the implementation bug and have reported this in the past, but nevertheless the issue remains. I believe this is because rotation math is tricky stuff, so not many people notice that anything is actually wrong.

In a child prim, it the rotation of a child prim is stored internally by SL as a rotation relative to the root prim of the link set. llSetLocalRot() sets this rotation verbatim. llSetRot() in a child prim SHOULD set the prim such that its world-relative rotation is equal to the argument passed.

Logically, the following should be a no-op in a child prim:

llSetLocalRot(llGetLocalRot());

It is, in fact. The following should also be a no-op in a child prim:

llSetRot(llGetRot());

It's NOT. The result is that the child prim rotates some amount every time the preceding line is run.


Since child prim rotations are stored as a rotation relative to the root prim, the following should be a pseudo-implementation of llSetRot() in a child prim:

llSetRot(rotation rot) {
    llSetLocalRot(rot/llGetRootRotation());
}

The above code uses rotation division. In essence, this says, "tell me rot as a rotation relative to llGetRootRotation()". This is how quaternions work.

Through extensive testing, I've determined that it's actually implemented as the following:

llSetRot(rotation rot) {
   llSetLocalRot(rot * llGetRootRotation());
}

That's right: the internal code that implements llSetRot() and PRIM_ROTATION for child prims uses a quaternion multiplication when it should use a division. I'm absolutely sure of this.

To work around this, normally it's enough to just avoid using llSetRot() in a child prim, and to get the same functionality by using llSetLocalRot() as I showed above. However, if it's critical that the rotation and position of a child prim are set at the same instant, the only possible way to do this is llSetPrimitiveParams([PRIM_POSITION, ..., PRIM_ROTATION, ...]);. This means that you have no choice but to use the buggy PRIM_ROTATION implementation.

If you must set a child prim to a world-relative rotation "rot" using PRIM_ROTATION (or llSetRot()), use this:

    llSetPrimtiiveParams([PRIM_ROTATION, (rot / llGetRootRotation) / llGetRootRotation);

If you must set a child prim to a local rotation "rot" using PRIM_ROTATION, use this:

    llSetPrimitiveParams([PRIM_ROTATION, rot/llGetRootRotation]);



Those examples both illustrate quaternion math that does not make sense. They only work because of the errant multiply operation carried out behind the scenes. Countless scripters in-world and in the forums have essentially stumbled upon these workarounds by doing various quaternion operations until the right thing happens[1]. I (and possibly others) worked out the actual problem and use the above workarounds routinely when I need to. SImply fixing PRIM_ROTATION will, unfortunately, break a lot of content. A new function, llSetRotCorrectly(), and a new operation, PRIM_ROTATION_CORRECT, will need to be implemented to fix this bug.

As nearly as I can tell, this bug has been around since llSetRot() was first implemented, and was carried on when llSetPrimitiveParams() was implemented.

[1] http://forums.secondlife.com/showpost.php?p=943944&postcount=2
This bug has been around for at least a year. In short, llSetPrimitiveParams([PRIM_POSITION, ...]) and llSetRot in a child prim is implemented INCORRECTLY, resulting in unexpected results. I've been able to determine the exact nature of the implementation bug and have reported this in the past, but nevertheless the issue remains. I believe this is because rotation math is tricky stuff, so not many people notice that anything is actually wrong.

In a child prim, it the rotation of a child prim is stored internally by SL as a rotation relative to the root prim of the link set. llSetLocalRot() sets this rotation verbatim. llSetRot() in a child prim SHOULD set the prim such that its world-relative rotation is equal to the argument passed.

Logically, the following should be a no-op in a child prim:

{code}
llSetLocalRot(llGetLocalRot());
{code}

It is, in fact. The following should also be a no-op in a child prim:

llSetRot(llGetRot());

It's NOT. The result is that the child prim rotates some amount every time the preceding line is run.


Since child prim rotations are stored as a rotation relative to the root prim, the following should be a pseudo-implementation of llSetRot() in a child prim:

llSetRot(rotation rot) {
    llSetLocalRot(rot/llGetRootRotation());
}

The above code uses rotation division. In essence, this says, "tell me rot as a rotation relative to llGetRootRotation()". This is how quaternions work.

Through extensive testing, I've determined that it's actually implemented as the following:

llSetRot(rotation rot) {
   llSetLocalRot(rot * llGetRootRotation());
}

That's right: the internal code that implements llSetRot() and PRIM_ROTATION for child prims uses a quaternion multiplication when it should use a division. I'm absolutely sure of this.

To work around this, normally it's enough to just avoid using llSetRot() in a child prim, and to get the same functionality by using llSetLocalRot() as I showed above. However, if it's critical that the rotation and position of a child prim are set at the same instant, the only possible way to do this is llSetPrimitiveParams([PRIM_POSITION, ..., PRIM_ROTATION, ...]);. This means that you have no choice but to use the buggy PRIM_ROTATION implementation.

If you must set a child prim to a world-relative rotation "rot" using PRIM_ROTATION (or llSetRot()), use this:

    llSetPrimtiiveParams([PRIM_ROTATION, (rot / llGetRootRotation) / llGetRootRotation);

If you must set a child prim to a local rotation "rot" using PRIM_ROTATION, use this:

    llSetPrimitiveParams([PRIM_ROTATION, rot/llGetRootRotation]);



Those examples both illustrate quaternion math that does not make sense. They only work because of the errant multiply operation carried out behind the scenes. Countless scripters in-world and in the forums have essentially stumbled upon these workarounds by doing various quaternion operations until the right thing happens[1]. I (and possibly others) worked out the actual problem and use the above workarounds routinely when I need to. SImply fixing PRIM_ROTATION will, unfortunately, break a lot of content. A new function, llSetRotCorrectly(), and a new operation, PRIM_ROTATION_CORRECT, will need to be implemented to fix this bug.

As nearly as I can tell, this bug has been around since llSetRot() was first implemented, and was carried on when llSetPrimitiveParams() was implemented.

[1] http://forums.secondlife.com/showpost.php?p=943944&postcount=2
Lex Neva made changes - 06/Apr/07 09:39 AM
Description This bug has been around for at least a year. In short, llSetPrimitiveParams([PRIM_POSITION, ...]) and llSetRot in a child prim is implemented INCORRECTLY, resulting in unexpected results. I've been able to determine the exact nature of the implementation bug and have reported this in the past, but nevertheless the issue remains. I believe this is because rotation math is tricky stuff, so not many people notice that anything is actually wrong.

In a child prim, it the rotation of a child prim is stored internally by SL as a rotation relative to the root prim of the link set. llSetLocalRot() sets this rotation verbatim. llSetRot() in a child prim SHOULD set the prim such that its world-relative rotation is equal to the argument passed.

Logically, the following should be a no-op in a child prim:

{code}
llSetLocalRot(llGetLocalRot());
{code}

It is, in fact. The following should also be a no-op in a child prim:

llSetRot(llGetRot());

It's NOT. The result is that the child prim rotates some amount every time the preceding line is run.


Since child prim rotations are stored as a rotation relative to the root prim, the following should be a pseudo-implementation of llSetRot() in a child prim:

llSetRot(rotation rot) {
    llSetLocalRot(rot/llGetRootRotation());
}

The above code uses rotation division. In essence, this says, "tell me rot as a rotation relative to llGetRootRotation()". This is how quaternions work.

Through extensive testing, I've determined that it's actually implemented as the following:

llSetRot(rotation rot) {
   llSetLocalRot(rot * llGetRootRotation());
}

That's right: the internal code that implements llSetRot() and PRIM_ROTATION for child prims uses a quaternion multiplication when it should use a division. I'm absolutely sure of this.

To work around this, normally it's enough to just avoid using llSetRot() in a child prim, and to get the same functionality by using llSetLocalRot() as I showed above. However, if it's critical that the rotation and position of a child prim are set at the same instant, the only possible way to do this is llSetPrimitiveParams([PRIM_POSITION, ..., PRIM_ROTATION, ...]);. This means that you have no choice but to use the buggy PRIM_ROTATION implementation.

If you must set a child prim to a world-relative rotation "rot" using PRIM_ROTATION (or llSetRot()), use this:

    llSetPrimtiiveParams([PRIM_ROTATION, (rot / llGetRootRotation) / llGetRootRotation);

If you must set a child prim to a local rotation "rot" using PRIM_ROTATION, use this:

    llSetPrimitiveParams([PRIM_ROTATION, rot/llGetRootRotation]);



Those examples both illustrate quaternion math that does not make sense. They only work because of the errant multiply operation carried out behind the scenes. Countless scripters in-world and in the forums have essentially stumbled upon these workarounds by doing various quaternion operations until the right thing happens[1]. I (and possibly others) worked out the actual problem and use the above workarounds routinely when I need to. SImply fixing PRIM_ROTATION will, unfortunately, break a lot of content. A new function, llSetRotCorrectly(), and a new operation, PRIM_ROTATION_CORRECT, will need to be implemented to fix this bug.

As nearly as I can tell, this bug has been around since llSetRot() was first implemented, and was carried on when llSetPrimitiveParams() was implemented.

[1] http://forums.secondlife.com/showpost.php?p=943944&postcount=2
This bug has been around for at least a year. In short, llSetPrimitiveParams([PRIM_POSITION, ...]) and llSetRot in a child prim is implemented INCORRECTLY, resulting in unexpected results. I've been able to determine the exact nature of the implementation bug and have reported this in the past, but nevertheless the issue remains. I believe this is because rotation math is tricky stuff, so not many people notice that anything is actually wrong.

In a child prim, it the rotation of a child prim is stored internally by SL as a rotation relative to the root prim of the link set. llSetLocalRot() sets this rotation verbatim. llSetRot() in a child prim SHOULD set the prim such that its world-relative rotation is equal to the argument passed.

Logically, the following should be a no-op in a child prim:

    llSetLocalRot(llGetLocalRot());

It is, in fact. The following should also be a no-op in a child prim:

    llSetRot(llGetRot());

It's NOT. The result is that the child prim rotates some amount every time the preceding line is run.


Since child prim rotations are stored as a rotation relative to the root prim, the following should be a pseudo-implementation of llSetRot() in a child prim:

    llSetRot(rotation rot) {
        llSetLocalRot(rot/llGetRootRotation());
    }

The above code uses rotation division. In essence, this says, "tell me rot as a rotation relative to llGetRootRotation()". This is how quaternions work.

Through extensive testing, I've determined that it's actually implemented as the following:

    llSetRot(rotation rot) {
        llSetLocalRot(rot * llGetRootRotation());
    }

That's right: the internal code that implements llSetRot() and PRIM_ROTATION for child prims uses a quaternion multiplication when it should use a division. I'm absolutely sure of this.

To work around this, normally it's enough to just avoid using llSetRot() in a child prim, and to get the same functionality by using llSetLocalRot() as I showed above. However, if it's critical that the rotation and position of a child prim are set at the same instant, the only possible way to do this is llSetPrimitiveParams([PRIM_POSITION, ..., PRIM_ROTATION, ...]);. This means that you have no choice but to use the buggy PRIM_ROTATION implementation.

If you must set a child prim to a world-relative rotation "rot" using PRIM_ROTATION (or llSetRot()), use this:

    llSetPrimtiiveParams([PRIM_ROTATION, (rot / llGetRootRotation) / llGetRootRotation);

If you must set a child prim to a local rotation "rot" using PRIM_ROTATION, use this:

    llSetPrimitiveParams([PRIM_ROTATION, rot/llGetRootRotation]);



Those examples both illustrate quaternion math that does not make sense. They only work because of the errant multiply operation carried out behind the scenes. Countless scripters in-world and in the forums have essentially stumbled upon these workarounds by doing various quaternion operations until the right thing happens[1]. I (and possibly others) worked out the actual problem and use the above workarounds routinely when I need to. SImply fixing PRIM_ROTATION will, unfortunately, break a lot of content. A new function, llSetRotCorrectly(), and a new operation, PRIM_ROTATION_CORRECT, will need to be implemented to fix this bug.

As nearly as I can tell, this bug has been around since llSetRot() was first implemented, and was carried on when llSetPrimitiveParams() was implemented.

[1] http://forums.secondlife.com/showpost.php?p=943944&postcount=2
Strife Onizuka made changes - 06/Apr/07 11:12 PM
Description This bug has been around for at least a year. In short, llSetPrimitiveParams([PRIM_POSITION, ...]) and llSetRot in a child prim is implemented INCORRECTLY, resulting in unexpected results. I've been able to determine the exact nature of the implementation bug and have reported this in the past, but nevertheless the issue remains. I believe this is because rotation math is tricky stuff, so not many people notice that anything is actually wrong.

In a child prim, it the rotation of a child prim is stored internally by SL as a rotation relative to the root prim of the link set. llSetLocalRot() sets this rotation verbatim. llSetRot() in a child prim SHOULD set the prim such that its world-relative rotation is equal to the argument passed.

Logically, the following should be a no-op in a child prim:

    llSetLocalRot(llGetLocalRot());

It is, in fact. The following should also be a no-op in a child prim:

    llSetRot(llGetRot());

It's NOT. The result is that the child prim rotates some amount every time the preceding line is run.


Since child prim rotations are stored as a rotation relative to the root prim, the following should be a pseudo-implementation of llSetRot() in a child prim:

    llSetRot(rotation rot) {
        llSetLocalRot(rot/llGetRootRotation());
    }

The above code uses rotation division. In essence, this says, "tell me rot as a rotation relative to llGetRootRotation()". This is how quaternions work.

Through extensive testing, I've determined that it's actually implemented as the following:

    llSetRot(rotation rot) {
        llSetLocalRot(rot * llGetRootRotation());
    }

That's right: the internal code that implements llSetRot() and PRIM_ROTATION for child prims uses a quaternion multiplication when it should use a division. I'm absolutely sure of this.

To work around this, normally it's enough to just avoid using llSetRot() in a child prim, and to get the same functionality by using llSetLocalRot() as I showed above. However, if it's critical that the rotation and position of a child prim are set at the same instant, the only possible way to do this is llSetPrimitiveParams([PRIM_POSITION, ..., PRIM_ROTATION, ...]);. This means that you have no choice but to use the buggy PRIM_ROTATION implementation.

If you must set a child prim to a world-relative rotation "rot" using PRIM_ROTATION (or llSetRot()), use this:

    llSetPrimtiiveParams([PRIM_ROTATION, (rot / llGetRootRotation) / llGetRootRotation);

If you must set a child prim to a local rotation "rot" using PRIM_ROTATION, use this:

    llSetPrimitiveParams([PRIM_ROTATION, rot/llGetRootRotation]);



Those examples both illustrate quaternion math that does not make sense. They only work because of the errant multiply operation carried out behind the scenes. Countless scripters in-world and in the forums have essentially stumbled upon these workarounds by doing various quaternion operations until the right thing happens[1]. I (and possibly others) worked out the actual problem and use the above workarounds routinely when I need to. SImply fixing PRIM_ROTATION will, unfortunately, break a lot of content. A new function, llSetRotCorrectly(), and a new operation, PRIM_ROTATION_CORRECT, will need to be implemented to fix this bug.

As nearly as I can tell, this bug has been around since llSetRot() was first implemented, and was carried on when llSetPrimitiveParams() was implemented.

[1] http://forums.secondlife.com/showpost.php?p=943944&postcount=2
This bug has been around for at least a year. In short, llSetPrimitiveParams([PRIM_POSITION, ...]) and llSetRot in a child prim is implemented INCORRECTLY, resulting in unexpected results. I've been able to determine the exact nature of the implementation bug and have reported this in the past, but nevertheless the issue remains. I believe this is because rotation math is tricky stuff, so not many people notice that anything is actually wrong.

In a child prim, it the rotation of a child prim is stored internally by SL as a rotation relative to the root prim of the link set. llSetLocalRot() sets this rotation verbatim. llSetRot() in a child prim SHOULD set the prim such that its world-relative rotation is equal to the argument passed.

Logically, the following should be a no-op in a child prim:

    llSetLocalRot(llGetLocalRot());

It is, in fact. The following should also be a no-op in a child prim:

    llSetRot(llGetRot());

It's NOT. The result is that the child prim rotates some amount every time the preceding line is run.


Since child prim rotations are stored as a rotation relative to the root prim, the following should be a pseudo-implementation of llSetRot() in a child prim:

    llSetRot(rotation rot) {
        llSetLocalRot(rot/llGetRootRotation());
    }

The above code uses rotation division. In essence, this says, "tell me rot as a rotation relative to llGetRootRotation()". This is how quaternions work.

Through extensive testing, I've determined that it's actually implemented as the following:

    llSetRot(rotation rot) {
        llSetLocalRot(rot * llGetRootRotation());
    }

That's right: the internal code that implements llSetRot() and PRIM_ROTATION for child prims uses a quaternion multiplication when it should use a division. I'm absolutely sure of this.

To work around this, normally it's enough to just avoid using llSetRot() in a child prim, and to get the same functionality by using llSetLocalRot() as I showed above. However, if it's critical that the rotation and position of a child prim are set at the same instant, the only possible way to do this is llSetPrimitiveParams([PRIM_POSITION, ..., PRIM_ROTATION, ...]);. This means that you have no choice but to use the buggy PRIM_ROTATION implementation.

If you must set a child prim to a world-relative rotation "rot" using PRIM_ROTATION (or llSetRot()), use this:

    llSetPrimtiiveParams([PRIM_ROTATION, (rot / llGetRootRotation) / llGetRootRotation);

If you must set a child prim to a local rotation "rot" using PRIM_ROTATION, use this:

    llSetPrimitiveParams([PRIM_ROTATION, rot/llGetRootRotation]);

Furthermore, llGetRootRotation does not return a meaningful result for child prims in attachments.

Those examples both illustrate quaternion math that does not make sense. They only work because of the errant multiply operation carried out behind the scenes. Countless scripters in-world and in the forums have essentially stumbled upon these workarounds by doing various quaternion operations until the right thing happens[1]. I (and possibly others) worked out the actual problem and use the above workarounds routinely when I need to. SImply fixing PRIM_ROTATION will, unfortunately, break a lot of content. A new function, llSetRotCorrectly(), and a new operation, PRIM_ROTATION_CORRECT, will need to be implemented to fix this bug.

As nearly as I can tell, this bug has been around since llSetRot() was first implemented, and was carried on when llSetPrimitiveParams() was implemented.

[1] http://forums.secondlife.com/showpost.php?p=943944&postcount=2
Lex Neva made changes - 11/Apr/07 09:08 AM
Link This issue is related to by SVC-102 [ SVC-102 ]
Strife Onizuka made changes - 24/Apr/07 09:28 AM
Link This issue is duplicated by SVC-129 [ SVC-129 ]
Lex Neva made changes - 08/May/07 01:00 PM
Summary llSetPrimitiveParams PRIM_POSITION and llSetRot incorrectly implemented for child prims llSetPrimitiveParams PRIM_ROTATION and llSetRot incorrectly implemented for child prims
Dzonatas Sol made changes - 09/May/07 03:22 PM
Summary llSetPrimitiveParams PRIM_ROTATION and llSetRot incorrectly implemented for child prims LSL -> llSetPrimitiveParams & llSetRot -> PRIM_ROTATION -> Child Prims -> Incorrect
lindenrobot made changes - 17/May/07 02:44 PM
Linden Lab Issue ID SL-43173
Lex Neva made changes - 20/Jun/07 09:22 AM
Summary LSL -> llSetPrimitiveParams & llSetRot -> PRIM_ROTATION -> Child Prims -> Incorrect llSetPrimitiveParams PRIM_ROTATION and llSetRot incorrectly implemented for child prims
Lex Neva made changes - 20/Jun/07 09:23 AM
Link This issue is related to by MISC-322 [ MISC-322 ]
Void Singer made changes - 30/Oct/07 07:19 AM
Link This issue is related to by SVC-303 [ SVC-303 ]
Rob Linden made changes - 22/Dec/07 12:57 AM
Workflow jira [ 10814 ] jira-2007-12-21 [ 20550 ]
Rob Linden made changes - 22/Dec/07 01:13 AM
Workflow jira [ 20550 ] jira-2007-12-21 [ 21317 ]
Rob Linden made changes - 22/Dec/07 01:43 AM
Workflow jira [ 21317 ] jira-2007-12-21 [ 23011 ]
Rob Linden made changes - 23/Dec/07 12:09 AM
Workflow jira-2007-12-21 [ 23011 ] jira-2007-12-22a [ 48085 ]
Rob Linden made changes - 23/Dec/07 12:26 AM
Workflow jira-2007-12-21 [ 48085 ] jira-2007-12-22a [ 48875 ]
Thraxis Epsilon made changes - 28/Dec/07 10:32 AM
Link This issue is related to by SVC-129 [ SVC-129 ]
Thraxis Epsilon made changes - 28/Dec/07 10:33 AM
Link This issue is duplicated by SVC-129 [ SVC-129 ]
Rex Cronon made changes - 14/Jul/08 02:14 PM
Link This issue is related to by SVC-2608 [ SVC-2608 ]
Rex Cronon made changes - 14/Jul/08 02:28 PM
Link This issue Relates to SVC-2608 [ SVC-2608 ]
Andrew Linden made changes - 14/Aug/08 10:21 AM
Assignee Andrew Linden [ Andrew Linden ]
Strife Onizuka made changes - 14/Aug/08 11:01 AM
Link This issue Relates to SVC-2608 [ SVC-2608 ]
Sue Linden made changes - 13/Nov/08 12:01 PM
Workflow jira-2007-12-22a [ 48875 ] jira-2008-11-14 [ 80024 ]
Sue Linden made changes - 13/Nov/08 04:26 PM
Workflow jira-2008-11-14 [ 80024 ] jira-2008-11-14a [ 85926 ]
Sue Linden made changes - 13/Nov/08 04:37 PM
Workflow jira-2008-11-14 [ 85926 ] jira-2008-11-14a [ 89214 ]
Sue Linden made changes - 13/Nov/08 04:45 PM
Workflow jira-2008-11-14 [ 89214 ] jira-2008-11-14a [ 91672 ]
Alexa Linden made changes - 18/Nov/08 10:48 AM
Linden Lab Issue ID SL-43173 DEV-1178
Theblack Box made changes - 21/Jan/09 08:08 PM
Link This issue is related to by MISC-2237 [ MISC-2237 ]
Strife Onizuka made changes - 23/Jun/09 12:16 AM
Link This issue parent of SVC-4447 [ SVC-4447 ]
BETLOG Hax made changes - 30/Jun/09 07:12 PM
Link This issue is related to by SVC-4476 [ SVC-4476 ]
Prospero Frobozz made changes - 17/Jul/09 12:32 PM
Link This issue is related to by SVC-4580 [ SVC-4580 ]
Boroondas Gupte made changes - 15/Nov/09 04:18 AM
Description This bug has been around for at least a year. In short, llSetPrimitiveParams([PRIM_POSITION, ...]) and llSetRot in a child prim is implemented INCORRECTLY, resulting in unexpected results. I've been able to determine the exact nature of the implementation bug and have reported this in the past, but nevertheless the issue remains. I believe this is because rotation math is tricky stuff, so not many people notice that anything is actually wrong.

In a child prim, it the rotation of a child prim is stored internally by SL as a rotation relative to the root prim of the link set. llSetLocalRot() sets this rotation verbatim. llSetRot() in a child prim SHOULD set the prim such that its world-relative rotation is equal to the argument passed.

Logically, the following should be a no-op in a child prim:

    llSetLocalRot(llGetLocalRot());

It is, in fact. The following should also be a no-op in a child prim:

    llSetRot(llGetRot());

It's NOT. The result is that the child prim rotates some amount every time the preceding line is run.


Since child prim rotations are stored as a rotation relative to the root prim, the following should be a pseudo-implementation of llSetRot() in a child prim:

    llSetRot(rotation rot) {
        llSetLocalRot(rot/llGetRootRotation());
    }

The above code uses rotation division. In essence, this says, "tell me rot as a rotation relative to llGetRootRotation()". This is how quaternions work.

Through extensive testing, I've determined that it's actually implemented as the following:

    llSetRot(rotation rot) {
        llSetLocalRot(rot * llGetRootRotation());
    }

That's right: the internal code that implements llSetRot() and PRIM_ROTATION for child prims uses a quaternion multiplication when it should use a division. I'm absolutely sure of this.

To work around this, normally it's enough to just avoid using llSetRot() in a child prim, and to get the same functionality by using llSetLocalRot() as I showed above. However, if it's critical that the rotation and position of a child prim are set at the same instant, the only possible way to do this is llSetPrimitiveParams([PRIM_POSITION, ..., PRIM_ROTATION, ...]);. This means that you have no choice but to use the buggy PRIM_ROTATION implementation.

If you must set a child prim to a world-relative rotation "rot" using PRIM_ROTATION (or llSetRot()), use this:

    llSetPrimtiiveParams([PRIM_ROTATION, (rot / llGetRootRotation) / llGetRootRotation);

If you must set a child prim to a local rotation "rot" using PRIM_ROTATION, use this:

    llSetPrimitiveParams([PRIM_ROTATION, rot/llGetRootRotation]);

Furthermore, llGetRootRotation does not return a meaningful result for child prims in attachments.

Those examples both illustrate quaternion math that does not make sense. They only work because of the errant multiply operation carried out behind the scenes. Countless scripters in-world and in the forums have essentially stumbled upon these workarounds by doing various quaternion operations until the right thing happens[1]. I (and possibly others) worked out the actual problem and use the above workarounds routinely when I need to. SImply fixing PRIM_ROTATION will, unfortunately, break a lot of content. A new function, llSetRotCorrectly(), and a new operation, PRIM_ROTATION_CORRECT, will need to be implemented to fix this bug.

As nearly as I can tell, this bug has been around since llSetRot() was first implemented, and was carried on when llSetPrimitiveParams() was implemented.

[1] http://forums.secondlife.com/showpost.php?p=943944&postcount=2
This bug has been around for at least a year. In short, {{llSetPrimitiveParams([PRIM_POSITION, ...])}} and {{llSetRot}} in a child prim is implemented *incorrectly*, resulting in unexpected results. I've been able to determine the exact nature of the implementation bug and have reported this in the past, but nevertheless the issue remains. I believe this is because rotation math is tricky stuff, so not many people notice that anything is actually wrong.

In a child prim, it the rotation of a child prim is stored internally by SL as a rotation relative to the root prim of the link set. {{llSetLocalRot()}} sets this rotation verbatim. {{llSetRot()}} in a child prim *should* set the prim such that its world-relative rotation is equal to the argument passed.

Logically, the following should be a no-op in a child prim:
{code}
    llSetLocalRot(llGetLocalRot());
{code}
It is, in fact. The following should also be a no-op in a child prim:
{code}
    llSetRot(llGetRot());
{code}
It's *not*. The result is that the child prim rotates some amount every time the preceding line is run.


Since child prim rotations are stored as a rotation relative to the root prim, the following should be a pseudo-implementation of {{llSetRot()}} in a child prim:
{code}
    llSetRot(rotation rot) {
        llSetLocalRot(rot/llGetRootRotation());
    }
{code}
The above code uses rotation division. In essence, this says, "tell me {{rot}} as a rotation relative to {{llGetRootRotation()}}". This is how quaternions work.

Through extensive testing, I've determined that it's actually implemented as the following:
{code}
    llSetRot(rotation rot) {
        llSetLocalRot(rot * llGetRootRotation());
    }
{code}
That's right: the internal code that implements {{llSetRot()}} and {{PRIM_ROTATION}} for child prims uses a quaternion multiplication when it should use a division. I'm absolutely sure of this.

To work around this, normally it's enough to just avoid using {{llSetRot()}} in a child prim, and to get the same functionality by using {{llSetLocalRot()}} as I showed above. However, if it's critical that the rotation and position of a child prim are set at the same instant, the only possible way to do this is {{llSetPrimitiveParams([PRIM_POSITION, ..., PRIM_ROTATION, ...]);}}. This means that you have no choice but to use the buggy {{PRIM_ROTATION}} implementation.

If you must set a child prim to a world-relative rotation {{rot}} using {{PRIM_ROTATION}} (or {{llSetRot()}}), use this:
{code}
    llSetPrimitiveParams([PRIM_ROTATION, (rot / llGetRootRotation) / llGetRootRotation);
{code}
If you must set a child prim to a local rotation {{rot}} using PRIM_ROTATION, use this:
{code}
    llSetPrimitiveParams([PRIM_ROTATION, rot/llGetRootRotation]);
{code}
Furthermore, {{llGetRootRotation}} does not return a meaningful result for child prims in attachments.

Those examples both illustrate quaternion math that does not make sense. They only work because of the errant multiply operation carried out behind the scenes. Countless scripters in-world and in the forums have essentially stumbled upon these workarounds by doing various quaternion operations until the right thing happens[1]. I (and possibly others) worked out the actual problem and use the above workarounds routinely when I need to. Simply fixing {{PRIM_ROTATION}} will, unfortunately, break a lot of content. A new function, {{llSetRotCorrectly()}}, and a new operation, {{PRIM_ROTATION_CORRECT}}, will need to be implemented to fix this bug.

As nearly as I can tell, this bug has been around since {{llSetRot()}} was first implemented, and was carried on when {{llSetPrimitiveParams()}} was implemented.

[1] http://forums.secondlife.com/showpost.php?p=943944&postcount=2
Al Supercharge made changes - 15/Nov/09 09:56 AM
Comment [ I have a sculpted object (horse). The linked child prim sculpted leg has the exact same script as a cut box linked prim wing in a bird flying around it.
The bird's wings flap fine as they have for years, now, but the linked horse's leg rotates the whole object (horse) !!

Using llSetLocalRot and the same:
         llSetLocalRot( rot * llGetLocalRot() );
         llSetPrimitiveParams([PRIM_ROTATION, ( rot* llGetLocalRot() )]);

( I tried changed the leg to plane, cyclinder, torus it still rotates the whole horse )

I change the horse to PHYSICAL (like the bird) and then nothing rotates.

Please fix. ]