Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Rotational Mirror

Fafnir Fauna
Downy Cat
Join date: 23 Jun 2004
Posts: 34
05-02-2005 12:51
This is a little tricky for me.. I'm trying to figure out the formula for mirroring the rotation of an object's self. For example (in ASCII!) THis is the object: /> I want it to rotate itself to <\ but I'm a bit confused with the whole quaternion logic.

Anyone have any ideas?
Jeffrey Gomez
Cubed™
Join date: 11 Jun 2004
Posts: 3,522
05-02-2005 13:12
Fafnir, I have a script that does exactly this. Unfortunately, several people decided to take up arms against me about it, so I took it down.

This may be a good prompt to share the revised code I've made, which evades the problem that they complained at me for. I'll be adding that to the posted link presently.

Let's discuss the core of how this is done.

First, you will want to mirror the actual position of the object. This requires a little vector math:
CODE
vector pos = ((reference point here) - llGetPos()) / llGetRot();
rotation rot = (reference rotation here) / llGetRot();

This will give you an unbiased position and rotation versus your reference point.

If you're lost, the reference point is essentially the point, in space, that you will be mirroring through. Think of it as a tall glass mirror, with the inverted image on the other side.

Now, here are the actual transformations:

For a cube, prism, or cylinder:

CODE
vector rot2 = llRot2Euler(rot);
cut = <1 - cut.y, 1 - cut.x, 0>;
topshear = <topshear.y,topshear.x,0>;
topsize = <topsize.y,topsize.x,0>;
twist *= -1;
size = <size.y,size.x,size.z>;

// "X","Y", and "Z" denote the axes the object is mirrored over

if(mirror == "X")
{
pos.x *= -1;
rot2.y *= -1;
rot2.z *= -1;
rot = <0.00000, 0.00000, 0.70711, 0.70711> * llEuler2Rot(rot2);
}
else if(mirror == "Y")
{
pos.y *= -1;
rot2.x *= -1;
rot2.z *= -1;
rot = <0.00000, 0.00000, -0.70711, 0.70711> * llEuler2Rot(rot2);
}
else if(mirror == "Z")
{
pos.z *= -1;
rot2.x *= -1;
rot2.y *= -1;
rot = <-0.70711, -0.70711, -0.00000, 0.00000> * llEuler2Rot(rot2);
}



For a cylinder and a prism, this needs to be added. This is a little inefficient, since it basically is undoing some stuff we did already. Regardless:
CODE
if(type == 2 || type == 1)
{
topshear = <topshear.y,-1 * topshear.x,0>;
topsize = <topsize.y,topsize.x,0>;
rot2 = llRot2Euler(rot);
rot2.z += PI_BY_TWO;
rot = llEuler2Rot(rot2);
size = <size.y,size.x,size.z>;
}


And then you basically end up doing this for a cube, prism, or cylinder:
CODE

pos = llGetPos() + (pos * llGetRot());
rot = rot * llGetRot();
params = [pos,rot,size,type,holeshape,cut,hollow,twist,topsize,topshear];



If we have a sphere, we need to do this:
CODE
vector rot2 = llRot2Euler(rot);
cut = <1 - cut.y, 1 - cut.x, 0>;
twist = <twist.y,twist.x,0>;

if(mirror == "X")
{
pos.x *= -1;
rot2.z *= -1;
rot2.y *= -1;
rot = <-0.00000, -1.00000, -0.00000, 0.00000> * llEuler2Rot(rot2);
}
else if(mirror == "Y")
{
pos.y *= -1;
rot2.x *= -1;
rot2.z *= -1;
rot = <1.00000, -0.00000, -0.00000, 0.00000> * llEuler2Rot(rot2);
}
else if(mirror == "Z")
{
pos.z *= -1;
rot2.x *= -1;
rot2.y *= -1;
rot = llEuler2Rot(rot2);
}
pos = llGetPos() + (pos * llGetRot());
rot = rot * llGetRot();
params = [pos,rot,size,type,holeshape,cut,hollow,twist,dimple];


And for everything else (ring, torus, etc), we do this:

CODE
cut = <1 - cut.y, 1 - cut.x, 0>;
twist = <twist.y,twist.x,0>;
topshear = <topshear.x * -1,topshear.y * -1,0>;
taper *= -1;
radiusoffset *= -1;
skew *= -1;

if(mirror == "X")
{
vector rot2 = llRot2Euler(rot);
rot2.y *= -1;
rot2.y += PI;
rot = llEuler2Rot(rot2);
pos.x *= -1;
}
else if(mirror == "Y")
{
pos.y *= -1;
vector rot2 = llRot2Euler(rot);
rot2.x *= -1;
rot2.x += PI;
rot2.y *= -1;
rot = llEuler2Rot(rot2);
}
else if(mirror == "Z")
{
pos.z *= -1;
vector rot2 = llRot2Euler(rot);
rot2.x *= -1;
rot2 += <PI,PI,PI>;
rot = llEuler2Rot(rot2);
}

pos = llGetPos() + (pos * llGetRot());
rot = rot * llGetRot();
params = [pos,rot,size,type,holeshape,cut,hollow,twist,holesize,topshear];
params2 = [advancedcut,taper,revolutions,radiusoffset,skew];
// Basically, combine params and params2

I'm guessing that's a bit hard to digest, so I'll post the "fixed" code up now and give you a copy to fiddle with in-world.
_____________________
---
Fafnir Fauna
Downy Cat
Join date: 23 Jun 2004
Posts: 34
05-02-2005 13:39
Thank you for your reply!

I read about your object mirror script raising chaos, and I was sad to see it was removed. In fact it's what got me working on my own version. Several people have already expressed that it would be nice if they could build something and have an exact duplicate be made (since SL does not yet have a mirrored copy function like say, 3D Studio MAX) but mirrored to the original. This is particularly useful on symetrical things like body parts.

I can see this this being a concern as to whether this crosses the copyright line, but I don't think people realize that if you don't have mod rights to something (meaning you're not the owner, or a friend you gave mod rights too which I would hope is someone you're close enough to and trust) you can't place the script into the object you want to copy. So it's not like you can run around SL and create copies of everything you see. :P

I'm off topic here. But anyway I will try this out. Thank you for the quick response. :)