- Home /
Weird offsets by iTween?
Hey guys, I hope this is less of a mystery in the end, then it is to me.
Basically what I have is a Player, which gets rotated around his local x axis by a mouse script.
A second script rotates the player around the global axes, always 90 degree. Now here is the problem: using transform.Rotate(eulerAngles, Space.World)
, I only get an incredibly small, unproblematic offset, so that the player gets almost perfectly aligned to the global axes in the end.
However, when I use itweens iTween.RotateAdd()
, also in global space, I get a significantly bigger offset. This offset adds on, until the Player isn't aligned anymore, practically not orthogonal anymore.
Errors that I have tested/disproved:
It's not caused by some sort of gravity or selfmade force. I've turned it off and made the attached rigidbody of the character kinematic.
It's not caused by mouse look. Even when not using mouse look, an offset occurs.
It always gets passed 90 degree-rotations
Is there any known issue that could cause this kind of behaviour, or do you need some script and/or pictures?
EDIT: Here's the code, also posted in comments
public void switchGround()
{
//Some code to determine the normals which is pointed at with raycasting
Quaternion desRot = Quaternion.FromToRotation(transform.up, hit.normal);
float desRotX;
float desRotY;
float desRotZ;
//normalizing it to 180 degree max
if (desRot.eulerAngles.x > 180) { desRotX = desRot.eulerAngles.x - 360; }
else { desRotX = desRot.eulerAngles.x; }
if (desRot.eulerAngles.y > 180) { desRotY = desRot.eulerAngles.y - 360; }
else { desRotY = desRot.eulerAngles.y; }
if (desRot.eulerAngles.z > 180) { desRotZ = desRot.eulerAngles.z - 360; }
else { desRotZ = desRot.eulerAngles.z; }
Vector3 ea = new Vector3(desRotX, desRotY, desRotZ);
if (ea.magnitude < 178) //I want to handle 180 degree rotations manually
{
if (!rotating)
{
//clamping it to 90 degree rotations
if (Mathf.Ceil(desRotX) >= 45) desRotX = 90;
else if (Mathf.Floor(desRotX) <= -45) desRotX = -90;
else desRotX = 0;
if (Mathf.Ceil(desRotY) >= 45) desRotY = 90;
else if (Mathf.Floor(desRotY) <= -45) desRotY = -90;
else desRotY = 0;
if (Mathf.Ceil(desRotZ) >= 45) desRotZ = 90;
else if (Mathf.Floor(desRotZ) <= -45) {desRotZ = -90; }
else desRotZ = 0;
ea = new Vector3(desRotX, desRotY, desRotZ);
//transform.Rotate(ea, Space.World); <---- This works fine
iTween.RotateAdd(gameObject, iTween.Hash("amount", ea, "time", 0.4f, "space", Space.World, "onstart", "rotStart", "oncomplete", "rotComplete", "easetype", "easeInOutCubic"));
//This doesn't. onstart and oncomplete functions get called to make the rigidbody kinematic and stop gravity for the rotation
}
}
else
{
//What happens for 180 degree rotations, not important for the question
}
}
It is easiest for folks on the list to figure out these kinds of problems if we see the code.
Okay, I hoped I could get away without posting it, since it's a rather long bit of code. Let me see if I can condense it down to the essential parts, then.
Answer by robertbu · Mar 19, 2013 at 12:00 AM
Transform.Rotate() here is going to happen between one frame and the next. iTween.RotateAdd() will happen over time, and at each frame some of the total rotation is added to the current rotation at that time. So you get a sort-of compounding with iTween.
Local and global may not mean what you think they mean. Typically when I have two different kinds of rotation like you say you have, I isolate one rotation from the other by using an empty game object. So the empty parent game object get the "global" rotation, and the child character get the "local" rotation. This doesn't solve every kind of rotation, but it can solve a lot of headaches when it does.
Also you are reading back the euler angles from the rotation. Without going through your logic in detail (I see you are attempting to normalize everything), I cannot say that what you are doing won't work, but typically it is a bad idea to read euler angles. There are multiple euler angles for any specific rotation, and the euler angles readings from Transforms or Quaternions often don't give back what you would expect. One moment you might have a rotation of (179.9,0,0) and the next it will return (0,180,180) for example. When I need to do this kind of thing, I treat euler angles as 'write-only'. I maintain my own Vector3 and assign it to Transform.eulerAngles or Transform.localEulerAngles each frame.
I see what you are saying there. I did as you recommended, but it didn't help. Separating the rotations gives the same result. Not reading eulerAngles doesn't seem to help either - that being said, I need to read them at least once.
So, I get the following scenario: I make two rotations, each 90 degree. The following lines show the vectors of the rotations. The first one is the one generated by FromToRotation, the "NOR$$anonymous$$:" one is the one that gets used in the iTween Rotation.
Rotation 1: (270.0, 0.0, 0.0) NOR$$anonymous$$: (-90.0, 0.0, 0.0)
Rotation 2: (270.0, 0.0, 0.0) NOR$$anonymous$$: (-90.0, 0.0, 0.0) The Player-Transform shows an offset of 3 degree in x-direction in the editor here, which is also easily noticeable.
Okay, I'll just use Quaternion.Slerp again, if we can't find a solution. I switched to iTween in the first place, since I didn't want to separate Rotations as you mentioned, and it seemed generally easier.
Still though, it would be nice to know what causes this issue.
I too don't like when I don't understand something. If I can play a bit I can usually figure out what is going on. Do you have a simple piece of code that demonstrates the problem? It just has to do the two rotations you mention. If so perhaps I can figure it out.
I got my functionality using regular Slerps by the way, not using iTween for precision rotation anymore.
When I just put together the following example for you, I noticed that the attached rigidbody seems to cause the problem. So: you can reconstruct the problem, if you just attach something similar to this script to an object with a rigidbody:
void Update () {
if (Input.GetButtonDown("Fire1"))
iTween.RotateAdd(gameObject, iTween.Hash("amount", new Vector3(-90, 0, 0) , "time", 0.4f, "space", Space.World, "oncomplete", "rotComplete", "easetype", "easeInOutCubic"));
}
void rotComplete()
{
Debug.Log(transform.eulerAngles);
}
$$anonymous$$aking the rigidbody kinematic or setting angular drag to zero isn't the solution.