Thursday, July 17, 2008

Second Life Physics Scripting - Pinball #14 - Flipper Rotation Off Axis Issue

I've spent way too much time trying to get the flipper to rotate properly. I'm not even sure if it will work properly when I do get it to rotate, but now I'm on a mission to get this working.

Basically there are two rotation pages.
http://www.lslwiki.net/lslwiki/wakka.php?wakka=rotation
http://wiki.secondlife.com/wiki/Rotation

The rotation from the center of the flipper works great, the off axis rotation is even harder. I think I spent a lot of time on one flipper that was rotated differently than I thought so I started over with a new flipper and the same code.

Basically, I need to calculate the base/heal of the flipper. I do this by looking at the initial orientation of the tip of the flipper and it was straight up in the z direction. I take the negative z vector and multiply it by the starting rotation which points me in the direction of the heal and convert it to a unit vector. I then multiply that unit vector by half of the z size which should give the the starting location of the heal offset from the center of the flipper. Tricky. That will be the point of rotation and that is what I've struggled with so far.

Both wiki's say it should be fairly straight forward, but I keep getting a rotational axis that is missing the mark.

Here is the current (not working code with a ton of test code). The test code is not offset so I can find it more easily.

link_message(integer from, integer msg_id, string str, key id)
{
if (msg_id == MSG_RIGHT_ON_NUM)
{
//llOwnerSay("right flipper on");
//llSetLocalRot(end_rot);
// a rotation of 45 degrees around the x-axis
rotation x_45 = llEuler2Rot( <0, 0, -45 * DEG_TO_RAD> );


// the original orientation of the flipper wedges is <0,0,1>
// i use -1 to point at the heal of the wedge
vector norm = <0,0,-1>;
// rotate that norm so it points towards the point of the wedge
norm = llVecNorm(norm * llGetLocalRot());

// find the size of the wedge
vector sz = llList2Vector(llGetPrimitiveParams([PRIM_SIZE]),0);
llOwnerSay("size = "+(string)sz);
vector offset = norm * (sz.z / 2);
vector rot_axis = start_pos + offset;
llMessageLinked(dbg_marker, 1,(string)rot_axis, NULL_KEY);
llOwnerSay("distance from center to heal = "+(string)offset);
llOwnerSay("get rot = "+(string)llGetRot());
rotation new_rot = llGetLocalRot() * x_45; // compute global rotation
//new_rot = new_rot * norm;
// http://wiki.secondlife.com/wiki/Rotation
// find the rotated norm
vector rotated_offset = offset * new_rot;
llOwnerSay("new rot = "+(string)new_rot);
llSetLocalRot(new_rot);

llOwnerSay(" cur pos = "+(string)llGetLocalPos());
vector offsettimesrot = (-offset*new_rot);
llOwnerSay("offset times rot ="+(string)offsettimesrot);
vector new_pos = rot_axis + (offset * new_rot);
//vector new_pos = llGetLocalPos() - (offset * llGetLocalRot());
//vector newPos = llGetPos() + (offset - rotatedOffset) * llGetRot()
llOwnerSay(" new pos = "+(string) new_pos);
llSetPos(new_pos);

}
else if (msg_id == MSG_RIGHT_OFF_NUM)
{
//llOwnerSay("right flipper off");
llSetLocalRot(start_rot);

// already in local coords since child prim
llSetPos(start_pos);
}
}

At this point I'm having trouble visualizing the actual origin that is being rotated, so I've created a thin black cylinder called "dbg_marker" and I'm going to position that what I calculate to be the origin of the heal.


As usual I can find the marker by traversing the link list.


test_find_marker()
{
integer current_link_nr = llGetNumberOfPrims();
// Check if it's more than one
if (1 < current_link_nr)
{
// avatars sitting on us get added at the end, so subtract...
while (llGetAgentSize(llGetLinkKey(current_link_nr)))
--current_link_nr;

while(current_link_nr>0)
{
if (llGetLinkName(current_link_nr)=="dbg_marker")
{
llOwnerSay("found dbg_marker: "+(string)current_link_nr);
dbg_marker = current_link_nr;
}
current_link_nr--;
}
}
}

The code to actually move the marker is yet another link message and some code in the marker. There really isn't a lot of api code to move another object to a specific location, you have to send a message to the object and have it move itself. Sort of a pain, but it forces you to separate out your logic which is a good thing.

Here is the code placed in the dbg_marker to move it to the location.

default
{
state_entry()
{

}

link_message(integer from, integer msg_id, string str, key id)
{
if (msg_id == 1)
{
vector vpos = (vector)str;
llOwnerSay("dbg_marker position"+(string)vpos);

llSetPos(vpos);
}
}
}


Then this final screen shot which shows that the location I calculated with all that crazy math was actually precisely on target.


It is obviously very very close to working, I just have a transformation out of order or something... Hmmm.... Welcome to my world.

No comments: