stripeyzebra Posted July 15, 2017 Share Posted July 15, 2017 I have a simple linked object (see picture) with the colors representing the positive axes. The cylinder is in the same orientation as the colored boxes with +Z at the top face. The two boxes and the cylinder are all rotated at <0, 30, 0> with respect to the root (the white prim) and share the same center of rotation. The root is at zero rotation. The cylinder must rotate in increments on its local X axis. Now, imagine that the cubes are children of the cylinder (how I wish we had proper parenting in SL!). When the cylinder rotates in X, the cubes will follow. Also easy to implement and is simply a matter of doing the same rotation on the cubes in the SLPPF call. integer id_of_cyl = 2; rotation Rx = llEuler2Rot (<1.0, 0.0, 0.0> * DEG_TO_RAD); rotation O; rotation new_rot; integer count; for (count = 0; count < 10; count++) { O = llList2Rot (llGetLinkPrimitiveParams (id_of_cyl, [PRIM_ROT_LOCAL]), 0); new_rot = Rx * O; llSetLinkPrimitiveParamsFast (id_of_cyl, [PRIM_ROT_LOCAL, new_rot]); } In addition to rotating with the cylinder, the cubes must also rotate on their local Z axis. Again, this is easy and is the same solution as to what I've already written. The issue is that both rotations should happen at the same time. Limiting movement to one axis works for both axes. Rotating the cubes on both axes at once produces unexpected rotation around the Y axis. I (obviously naively) thought that it was a matter of composing the rotations like so: integer id_of_cyl = 2; integer id_of_box1 = 3; integer id_of_box2 = 4; rotation Rx = llEuler2Rot (<1.0, 0.0, 0.0> * DEG_TO_RAD); rotation Rz = llEuler2Rot (<0.0, 0.0, 1.0> * DEG_TO_RAD); rotation O_cyl; rotation O_box; rotation new_cyl_rot; rotation new_box_rot; integer count; for (count = 0; count < 10; count++) { O_cyl = llList2Rot (llGetLinkPrimitiveParams (id_of_cyl, [PRIM_ROT_LOCAL]), 0); O_box = llList2Rot (llGetLinkPrimitiveParams (id_od_box1, [PRIM_ROT_LOCAL]), 0); new_cyl_rot = Rx * O_cyl; new_box_rot = Rz * Rx * O_box; llSetLinkPrimitiveParamsFast (LINK_SET, [PRIM_LINK_TARGET, id_of_cyl, PRIM_ROT_LOCAL, new_cyl_rot, PRIM_LINK_TARGET, id_of_box1, PRIM_ROT_LOCAL, new_box_rot, PRIM_LINK_TARGET, id_of_box2, PRIM_ROT_LOCAL, new_box_rot]); } Based on research I've done, the error is due to a problem with the order applying the rotations. However, with a orientation and two rotations, there can only be 12 ways to combine them, and I've tried them all, and all exhibit some degree of error. As a sanity check, here are the orders I've tried. O = current local rotation... Rz * Rx * O Rx * Rz * O Rz * O * Rx Rx * O * Rz O * Rx * Rz O * Rz * Rx (Rz * Rx) * O (Rx * Rz) * O (Rz * O) * Rx (Rx * O) * Rz (O * Rx) * Rz (O * Rz) * Rx I must be missing something (well I'm sure I'm missing something!) Could someone point out my error and save my sanity please? Link to comment Share on other sites More sharing options...
Rolig Loon Posted July 15, 2017 Share Posted July 15, 2017 You are dealing with Gimbal Lock, You'll find some excellent tutorials with a Google search. As long as you use llEuler2Rot, you will continue to run into the problem. Link to comment Share on other sites More sharing options...
stripeyzebra Posted July 15, 2017 Author Share Posted July 15, 2017 (edited) I'm going from zero degrees to 10 degrees, not 90 degrees, how can I be dealing with gimbal lock? And even if I am, what are the alternatives to make this actually work? Edited July 15, 2017 by stripeyzebra Link to comment Share on other sites More sharing options...
Rolig Loon Posted July 15, 2017 Share Posted July 15, 2017 Sorry. That's what happens if I type something in the middle of the night. Gimbal lock is a typical worry, but I think the problem here is llEuler2Rot itself. If you look at the function in the LSL wiki, you'll see that the llEuler2Rot rotation is calculated from v/=2; rotation k = <0.0, 0.0, llSin(v.z), llCos(v.z)> * <0.0, llSin(v.y), 0.0, llCos(v.y)> * <llSin(v.x), 0.0, 0.0, llCos(v.x)>; I think you're dealing with noise due to roundoff errors when the function calculates k from the sine or cosine of a small angle like 1.0 degrees. When you make small rotations of a degree at a time, the errors accumulate. You might try just doing a final cleanup adjustment after you have finished doing the incremental rotations. Link to comment Share on other sites More sharing options...
stripeyzebra Posted July 15, 2017 Author Share Posted July 15, 2017 Firstly, thanks so much for your input so far. Based on your suggestion that the increments were so small that they were producing roundoff error (even though the same increments work perfectly in one axis), I increased the increment to 10 degrees. Here's a picture of the object rotated 40 degrees on X and 20 degrees on Z. This is the same error produced with my original increment (which is actually significantly smaller that 1 degree. 1 degree was easier to talk about that SPEED/ FRAMERATE) Link to comment Share on other sites More sharing options...
arton Rotaru Posted July 16, 2017 Share Posted July 16, 2017 Incrementing Z by 1.0 degree each time, and just do Rz * new_cyl_rot on the boxes might be an option? Like: float gfRzInc; loop { gfRzInc += 1.0; Rz = llEuler2Rot (<0.0, 0.0, gfRzInc> * DEG_TO_RAD); new_cyl_rot = Rx * O_cyl; new_box_rot = Rz * new_cyl_rot; } Link to comment Share on other sites More sharing options...
stripeyzebra Posted July 17, 2017 Author Share Posted July 17, 2017 2 hours ago, arton Rotaru said: Incrementing Z by 1.0 degree each time, and just do Rz * new_cyl_rot on the boxes might be an option? Like: float gfRzInc; loop { gfRzInc += 1.0; Rz = llEuler2Rot (<0.0, 0.0, gfRzInc> * DEG_TO_RAD); new_cyl_rot = Rx * O_cyl; new_box_rot = Rz * new_cyl_rot; } How is your rotation composition different from new_box_rot = Rz * Rx * O_cyl; except the composition order (which, believe me, I've tried)? I've actually tried the "save the start rotation of the objects and add increments to them" approach, and I'd like to get back to that as it optimizes the increment loop. Unfortunately you still have to do Rz * Rx * O_cyl, no matter if the increment is always the same and O_cyl is the current position, or the increment increases and O_cyl is the "start" position. Link to comment Share on other sites More sharing options...
arton Rotaru Posted July 17, 2017 Share Posted July 17, 2017 12 hours ago, stripeyzebra said: How is your rotation composition different from new_box_rot = Rz * Rx * O_cyl; Having a fixed 1 degree rotation around z will rotate the boxes just that initial 1 degree obviously, and that's it. Because the cylinder doesn't rotate around local Z. Link to comment Share on other sites More sharing options...
Love Zhaoying Posted July 17, 2017 Share Posted July 17, 2017 I thought only insane people understand this stuff. Link to comment Share on other sites More sharing options...
stripeyzebra Posted July 19, 2017 Author Share Posted July 19, 2017 Solved! default { state_entry () { integer id_of_cyl = 2; integer id_of_box1 = 3; integer id_of_box2 = 4; rotation initial_rot = llEuler2Rot (<0.0, 30.0, 0.0> * DEG_TO_RAD); rotation Rx = llEuler2Rot (<1.0, 0.0, 0.0> * DEG_TO_RAD); rotation Rz = llEuler2Rot (<0.0, 0.0, 1.0> * DEG_TO_RAD); rotation O_cyl; rotation O_box; rotation relative_rot; rotation new_cyl_rot; rotation new_box_rot; integer count; // Set initial orientation llSetLinkPrimitiveParamsFast (LINK_SET, [PRIM_LINK_TARGET, id_of_cyl, PRIM_ROT_LOCAL, initial_rot, PRIM_LINK_TARGET, id_of_box1, PRIM_ROT_LOCAL, initial_rot, PRIM_LINK_TARGET, id_of_box2, PRIM_ROT_LOCAL, initial_rot]); for (count = 0; count < 10; count++) { O_cyl = llList2Rot (llGetLinkPrimitiveParams (id_of_cyl, [PRIM_ROT_LOCAL]), 0); O_box = llList2Rot (llGetLinkPrimitiveParams (id_of_box1, [PRIM_ROT_LOCAL]), 0); relative_rot = O_box / O_cyl; new_cyl_rot = Rx * O_cyl; new_box_rot = Rz * relative_rot * new_cyl_rot; llSetLinkPrimitiveParamsFast (LINK_SET, [PRIM_LINK_TARGET, id_of_cyl, PRIM_ROT_LOCAL, new_cyl_rot, PRIM_LINK_TARGET, id_of_box1, PRIM_ROT_LOCAL, new_box_rot, PRIM_LINK_TARGET, id_of_box2, PRIM_ROT_LOCAL, new_box_rot]); } } } 2 Link to comment Share on other sites More sharing options...
Berksey Posted July 20, 2017 Share Posted July 20, 2017 Thanks for posting what worked for you~! Much appreciated. ^-^ Link to comment Share on other sites More sharing options...
Recommended Posts
Please take a moment to consider if this thread is worth bumping.
Please sign in to comment
You will be able to leave a comment after signing in
Sign In Now