- Home /
Change orientation
Hi!
I was trying to change the orientation of an object on a defined axis (I tried with Y ans Z). After having a lot of trouble, I realized that my solutions were working except in the case where the said object has an initial rotation of 90 or -90 along X axis (maybe other values too).
What happened (in my script AND in the inspector) is when I changed the angle along Y or Z axis, the resulting rotation was visually the same. I have the feeling that I was falling into a specific case but I can't put my finger on it. If you understand why it behaves that way, feel free to enlighten me ;)
Here is the script I'm using (on a monobehaviour) :
public void Update() // classic Unity Update
{ float value = (float)ControllableParameter.GetFinalValue<object>(); // the desired angle for the axis
Vector3 currentValues = this.transform.localEulerAngles; // get current angles.
TRACE("Desired angle : " + value + "\t current angles values : " + currentValues); // for debug purposes
value -= (AxisToRotateAround == Axis.X ? currentValues.x :
(AxisToRotateAround == Axis.Y ? currentValues.y : currentValues.z)
); // get the current angle of the selected axis and calculate the needed rotation angle to obtain the desired angle
TRACE("rotation needs an angle of : " + value);
this.transform.Rotate( AxisToRotateAround == Axis.X ? value % 360 : 0,
AxisToRotateAround == Axis.Y ? value % 360 : 0,
AxisToRotateAround == Axis.Z ? value % 360 : 0
, Space.Self);
TRACE("values after call to Rotate : " + this.transform.localEulerAngles);
I tried setting localEulerAngles directly instead of using Rotate (but I think it's a bad way to do it as 2 of the angles directly depend on their current values), and various complicated ways to set this orientation.
Whatever the method, when my object has (for the case I mostly tested) a -90° angle around x axis, the modified value for the angle was modifying the Y axis instead of the Z one (I think I also had the problem where you revert Y ans Z in this sentence, but not sure) and the modification was wrong, there was an addition to the angle instead of an assignation.
Here is an example :
If my desired angle is, say, 5° around Z axis (so, getting from (-90,20,0) to (-90,20,5) I obtain the following : (-90,25,0) But if I set angles to (-47,20,0) for example, the exact same code will produce : (-47,20.000002,5).
So my questions are :
do I use the correct and most efficient methods to set the angle of my object (you can think of it as what happens in Unity's editor window, when you rotate an object to set it correctly in your scene before launching you game)?
If Unity's behaviour is not abnormal, what did I miss ? (conversion to quaternions maybe ?)
Thanks
@flonou Sounds like the models pivot is set up incorrectly. Go into the modeling program and make sure that Y face up and Z face forward. 3ds$$anonymous$$ax defaults to Z up
Can this explain why it doesn't work on some conditions and it works on others ?
Answer by aldonaletto · May 24, 2012 at 06:55 PM
The property localEulerAngles is a decomposition of the current transform.localRotation into single rotations around the axes X, Y and Z. Since there are several combinations that may result in the same rotation, the conversion quaternion->eulerAngles isn't reliable: it may change suddenly from one combination to another completely different (but equivalent) at certain points.
If you want to orient an object in a one-way-fashion (only your controls set the orientation, without no external factors like forces, collisions etc.), the best approach is to make currentValues a member variable set at Start and "rotate" these angles by math when needed, assigning them back to localEulerAngles - like this:
Vector3 currentValues;
public void Start(){ currentValues = transform.localEulerAngles; }
public void Update(){ // classic Unity Update float value = (float)ControllableParameter.GetFinalValue(); // the desired angle for the axis TRACE("Desired angle : " + value + "\t current angles values : " + currentValues); // for debug purposes switch (AxisToRotateAround){ // modify the desired axis: case Axis.X: currentValues.x = value; break; case Axis.Y: currentValues.y = value; break; case Axis.Z: currentValues.z = value; break; } transform.localEulerAngles = currentValues; // update actual object rotation }
Thanks for your answer
I tried something like this. The difference was that I was getting the local euler angles in the Update in order to only modify the controlled axis (so the currentValues = transform.localEulerAngles call was just under float value = ...). The behaviour was wrong too (incrementation on Y axis ins$$anonymous$$d of assignation on Z axis). What happened actually was that the eurlerAngler I assigned to transform.localEulerAngles where good (obviously) and if I tried to access transform.localEulerAngles right after, the resulting angles where messed up. I am wondering if this is not a gimbal lock issue but it doesn't explain why the problem is still present when I use Rotate.
I tried your solution, the visual behaviour is good but the Y euler angle is modified ins$$anonymous$$d of the Z one as I specify (unless I give the Y axis a initial angle other than 0). 2 examples : Desired angle : -126 current angles values : (270.0, 0.0, -126.0) values after assignation : (270.0, 234.0, 0.0)
Desired angle : 80 current angles values : (270.0, 20.0, 79.0) values after assignation : (270.0, 100.0, 0.0) (but on the next update, Desired angle : 80 current angles values : (270.0, 20.0, 80.0) which is actually good) (I'm pretty sure this is a gimbal lock problem on this specific case).
The thing is, I'd like to be able to modify the other angles if needed (the case with external factors)
Your answer
Follow this Question
Related Questions
How do I rotate a game object in 45 degree steps per keystroke? 2 Answers
2 axis rotated towards 2 different points 1 Answer
Rotation like in editor 2 Answers
How can I store the individual values of EulerAngles on a Database then re-apply 2 Answers
Clamp Rotation of an object depending of the Rotation of an other one 0 Answers