- Home /
an ignorant's trigonometry woes: rotate a transform around an axis
I am still pretty thick regarding trigonometry problems, and have a hard time figuring out the correct solution, despite my intermediate knowledge in vectors, transforms, matrixes, rotations, etc.
What I basically need, is to always know the equivalent of 'vector3.up' in a local transform's rotation. The problem is that, since this transform's rotation is random, it's axes are most surely different from the world axes, and I'm at a loss about what kind of transforms I need apply to know the 'localvectorup' to determine 'where' is it's 'world.vector3.up' equivalent in local space.
I know that my setting is ok because if I use
mechanicarm.RotateAround(mechanicarm.position, Vector3.up,-0.5f);
it correctly rotates in the horizontal plane, regardless of how twisted its local transform is. The problem is, i don't know the direction of the rotation, nor its intensity, so I need to use
LookAt, SetRotation or SetLookRotation
to set its orientation in the horizontal plane based on another object's transform: what i basically need is to rotate 'mechanicalarm' around the 'vector3.up' regardless of mechanicalarm's local rotation and axes orientations.
To clarify further: I don't need to find the arm's 'up' vector in respect to the world vector,which I can achieve through mechanicalarm.InverseTransformDirection(mechanicalarm.up)
For a start, I think I need to find the vector which, in mechanicalarm's local coordinate space, is -always- parallel to the world's Vector3.up, regardless of mechanicalarm's rotation SIGH! So damn difficult :(
Wonder if any of you trigonometry gurus out there can help me understand what are unity's correct functions to use to reach my goal.
thanks.
perhaps I need to create a new quaternion from mechanicarm.position, and vector3.up? but then what? I tried multiplying and subtracting from vector3.up but the vector I obtain is not constantly pointing up, but actually rotating along the arm...
I am now pretty sure that this can only be solved with a 4x4 matrix, since I clearly need to
1- extract the mechanicalarm's 'up' component
2- 'cross' it with the local upwards pointing vector
3- inject the modified 'up' component back into the mechanicalarms's rotation
Can this actually be done?
Answer by Owen-Reynolds · Aug 10, 2011 at 08:59 PM
I'm thinking it may be helpful to restate the actual problem, if only just for yourself. Some things that may be helpful:
o You wrote you tested with mechanicarm.RotateAround(mechanicarm.position, Vector3.up,-0.5f);
. The thing is, that always give a perfect spin on the horizontal plane, even if you randomly roll 0-360 for your starting spins (it says to spin around the global UP line, coming straight up from your center.) Since it always works, it isn't a useful test.
o Debug.DrawRay(mechanicalarm.position, xxxx );
assumes that xxxx is in World coords, so it can't be used to test if local coords are correct. If the question is "points straight up" then the answer is Debug.DrawRay(..., Vector3.up);
o Almost nothing takes local coords as input. Are you sure you need them? RotateAround takes the axis in World; DrawRay takes the dir as World; transform.Rotate(x,y,z);
does a local rotate, but it auto-computes your local x/y/z axis for you. If you are sure you need local, try testing with myChild.localPosition = someDir*4;
(for example, if someDir is Vector3.up, that puts the child 4 out on your current (local) up direction.)
Are you sure you don't just want mechArm.up
? That gives you the local UP in World coords. It's so short since lots of people use it. Debug.DrawRay(mechArm.position, mechArm.up*4);
makes a ray always pointing to your current up. It rotates with the model, but is frozen with respect to the model.
I am marking your answer as correct since it puts things in perspective, and clarifies the local and world coordinate issues with common transform questions.
Thanks a lot for your time, I will now proceed to ask a clearer question.
Answer by Owen-Reynolds · Aug 09, 2011 at 07:24 PM
This seems to be it (world up in local coords):
Vector3 worldUpInLocal = Quaternion.Inverse(transform.rotation) * Vector3.up;
My test code, with comments on the logic behind it. I think a better way (for me) would have been to note that transform.up
is shorthand for transform.rotation*Vector3.up;
and to try to solve that.
Keeping the locals and worlds straight is a real stumper. For example, the description of transform.InverseTransformDirection(Vector3.up)
says it should work. But, it usually (not always) gives the same numbers as my answer, but with signs flipped or x/z flipped.
// testing rotation math code:
Transform kid; // attempt to use result to place him world up from me
public Vector3 U; // result
public Vector3 U2; // transform.up, to compare.
// turns out result bears NO obvious relation to transform.up
void Update () {
// cheesy way to get lots of random spins:
if(Input.GetKey("z")) {
float yRot = Random.value*360;
float xRot = Random.value*360;
float zRot = Random.value*360;
transform.rotation = Quaternion.Euler(xRot, yRot, zRot);
// show in Inspector, to compare:
U2 = transform.up;
}
// The math:
// transform.rotation is from no spin to our spin;
// This computes other way, from our spin back to normal:
Quaternion qq = Quaternion.Inverse(transform.rotation);
// Apply that to "local up in local coords" to get "world up in local coords":
U = qq * Vector3.up;
// Check:
// U.xyz in local coords means, to move distance U.x along local x-axis, etc...
// Should take us to the local (x,y,z) which is also world up:
kid.position = transform.position +
(U.x * transform.right + U.y * transform.up + U.z * transform.forward) * 4;
// NOTE: *4 is just to make it easier to spot
}
I thank you for your effort but If I
Debug.drawray(mechanicalarm.position, worldUpInLocal)
the line is indeed 'up', but only in respect to the local axes conversion, so it still rotates alongside the mechanical arm. As a matter of fact, the result is identical to
newvector = mechanicalarm.InverseTransformDirection(mechanicalarm.up)
and its drawray from mechanicalarm.position