- Home /
Problem with rotating two axes independently, simultaneously
Hi everyone,
I've got a problem with matching two rotations. Let's start from the beginning - as seen on the first picture, I have a ball with wings. I want them to move up and down (by rotating them) while in the same time rotate them a little (just like on the second picture). So basically, when wings go up, they rotate a little in one direction, and when they go down, they rotate in the second direction.
The point of rotation for the wings is set in a 3D program right in the point of contact with the ball (so I don't have to set it manually in the script).
I thought that the best way to do what I want was to make an empty object which would be a parent for the wings. Then I could rotate the parent in one axis (for me that is local X axis) and the children-wings in second (that would be the local Z axis) - as shown on the third picture.
The whole movement can be seen on the fourth picture.
So now it's time to state my problem. When running the rotations separately (just one at a time) either the X rotation or the Z rotation is working fine. The problem occurs when I try to combine them and start them simultaneously. The first two or three cycles are working ok (the wings have their maximum on the X axes exactly when they reach maximum on the Z axis), but then everything starts to fall apart - rotation on the X axis doesn't match the rotation on the Z axis anymore.
Here's my code for the whole "animation":
using UnityEngine;
using System.Collections;
using System;
public class WingsAnimation : MonoBehaviour
{
public GameObject leftWing;
public GameObject rightWing;
public GameObject parent;
public float rotationTime; // time in which the object will rotate
private float rotationAngleZ;
private float rotationAngleX;
private bool upOrDown = false;
private bool twist = false;
private float angles; // angles for the Z axis
private float angles2; // angles for the X axis
// Use this for initialization
void Start ()
{
rotationAngleZ = 33.0f; // max rotation on the Z axis
rotationAngleX = 20.0f; // max rotation on the X axis
}
// Update is called once per frame
void Update ()
{
angles = 2 * rotationAngleZ / rotationTime * Time.deltaTime;
angles2 = 2 * rotationAngleX / rotationTime * Time.deltaTime;
UpAndDown();
SelfRotate ();
}
void UpAndDown () // Z axis movement
{
if (leftWing.transform.localRotation.z * 100 >= rotationAngleZ)
{
upOrDown = false;
}
if (leftWing.transform.localRotation.z * 100 <= -rotationAngleZ)
{
upOrDown = true;
}
if (upOrDown)
{
leftWing.transform.Rotate(0, 0, angles, Space.Self);
rightWing.transform.Rotate(0, 0, -angles, Space.Self);
}
else
{
leftWing.transform.Rotate(0, 0, -angles, Space.Self);
rightWing.transform.Rotate(0, 0, angles, Space.Self);
}
}
void SelfRotate () // X axis movement
{
if (parent.transform.localRotation.x * 100 >= rotationAngleX)
{
twist = false;
}
if (parent.transform.localRotation.x * 100 <= -rotationAngleX)
{
twist = true;
}
if (twist)
{
parent.transform.Rotate(angles2, 0, 0, Space.Self);
}
else
{
parent.transform.Rotate(-angles2, 0, 0, Space.Self);
}
}
}
If I set rotationTime to 1, the problem occurs after a couple of minutes, but when it's less then 1, it happens a lot faster.
My guess is that this has to be a problem with floating-point numbers, but I'm not sure. I've tried to debug angles and angles2 to see, if they are changing over time, but they stay constant (or I should say that they change but the difference is so small, that it shouldn't have any effect - or not this big anyway - on the movement).
I've made a small test in which I tried to move two cubes in one direction with different displacement and velocity, but with the same time, while moving their parent slowly in the opposite direction. The test was supposed to show, if the two cubes would reach designated point in the same time or if there would be some delay for one of them. I thought that this situation would be similiar to my problem, but in the test everything was working fine.
While "playing" with the positions of the object, I never had such problem. But with rotation it's somehow different. I don't know if I am making a mistake in my understanding or is there a bug in my code, so any help and explanation would be much appreciated :)
Sounds like a perfect thing to do with the animation editor, so you can keyframe the wings and get exactly the behaviour you want.
If everything fails I will probably do it with the animation editor - but for now I would like to try to code it :)
By using Space.Self, you are rotating around axes that have moved because of previous rotations. Could that be the case? First of all, I would try using Space.World, because you always want to rotate around fixed axes.
I'm using Space.Self, because the whole GameObject can move or rotate and I need wings to always rotate with it no matter where that GameObject is or what rotation does it have :)
I understand, but notice that once you have rotated your object around its X axis, its Z axis is no longer facing "forward", and therefore, rotating around Z axis will not rotate it upwards. $$anonymous$$aybe it is expected behavior, I'm just pointing it out because this has bothered be sometimes :-) By the way, this is also true when directly editing transform.eulerAngles.
Answer by TheDarkVoid · May 14, 2013 at 10:40 AM
You shouldn't be modifiying a Quaternion directly like that. you need to do this with the Transform.eulerAngles Do it like this:
private Vector3 rotationAngles; //store you desired rotation here
void Update()
{
transform.eulerAngles = rotationAngles;
}
instead of modffifying the rotation directly just moddify the rotationAngles vector and then set it at the end of the update. Also testing the current rotation should also be done with eulerAngles.
Ok, I'm trying to use Transform.eulerAngles ins$$anonymous$$d of Transform.Rotate(), but I'm having an issue - it seems that eulerAngles are changing the rotation in world space, but I need them in local space (or am I misunderstanding something with this?)
Ok, so the solution with Transform.eulerAngles partially helped :)
I had to resign from the idea of two functions - one for parent and the other one for children (it didn't work properly that way). Now I have only one function which rotates wings around the X and Z axes with no parent.
But all in all, solution with eulerAngles has a couple of disadvantages - first and most important for me is "lack" of local space. Second is problem in catching right moment of the rotation when speed of rotation is high - but this is mainly problem with float numbers and missing some of the steps (interesting thing is that transform.Rotate() doesn't have this problem - or I didn't see it).
For this moment the solution works so I'm happy :) I'll also try to make this with animation editor as Graham Dunnett suggested and see, which will look better :)
Anyway thank you for all the help and suggestions :)
to get local rotation do transform.localRotation.eulerAngles works the same way as before but on local space
Answer by raimon.massanet · May 15, 2013 at 07:16 AM
In your case, I think that what was causing the desynchronization had nothing to do with the rotation method used.
I think the problem is that you don't check whether the angles are going to go past the fixed limits before applying the rotation. This can cause your wings to actually sweep a larger angle than expected (at "random" depending on the last deltaTime before reaching the end of the sweep).
Since you have defined a fixed time for every sweep, but your sweeping angles might vary, there you have your desynchronization.
I tried that, but it didn't help (desynchronization was showing later but it was still there). I didn't include that in the code in order to simplify my problem as much as possible :) But thanks anyway - this is something worth remembering.
But did you just "clamp" your angle or did you calculate the position it should move (in the opposite direction) in order to maintain sync?
If this does not work, I have no more ideas for the moment. And I don't see why modifying eurlesAngles should work and Rotate not.
First I tried only to "clamp" it, later I added a fixed position for every rotation if the angle of either one of them was greater than the limit. Thanks to that, they all would start every sweep from proper positions. Of course sometimes you could see a little teleportation of the wings, but this was not the issue.
I guess that the desynchronization could be caused by the fact, that I had two separate functions for each rotation (they could have been calculated in a little different times). Now when it's in one function, everything is working fine.
I guess that if I've wrote previous code in a single function, the Rotate() would work ok.
I'm not sure I understand what you mean by "fixed position". What I meant by correcting the position is: Let's say your maximum angle is 45º, and you foresee that after applying your rotation you are going to end up in a 47º, then, since you are oscilating, the new position should be 43º (45º limit - 2º offset). There should be no "teleporting" in doing that. I believe you could do that in two different rotations, as intended.
By "fixed position" I meant that for example I have my maximum angle 45º on the X axis and 30º on the Z axis. So when I'm rotating wings, whenever X axis or Z axis is greater then 45º or 30º, both axes are automatically set to match their maximum values. Then when they are all set and ready, another sweep begins.
It's not pretty, but in theory it should work properly.
As to what you wrote, I tried that and it works (even better than my original approach :) ).
But there are two things that make me wonder - first is that in eulerAngles approach I had to make one function, because when I had two functions, the axes on the mesh were working fine (visually on the scene view and in the Inspector), but mesh itself was rotating only in one axis. It sounds impossible but it happened - but I have no idea why.
Second thing is that there is still problem with small desynchronization at the beginning of the rotation (whichever approach), only when the time of the rotation is small (for example 0.1 sec.). But now after one broken sweep (which starts with the beginning of the scene) rotation returns to correct movement and from then it works fine. I found that this is connected to the Time.deltaTime. The first five sample logs for Time.deltaTime are: 0.02; 0.02; 0.308; 0.024; 0.016 - in the third log the value of Time.deltaTime is very high and this is the moment rotation is going crazy.
Of course when I use FixedUpdate() ins$$anonymous$$d of Update() or set the time of rotation to 1 sec. everything is ok. I'm just curious if that supposed to be like that - I know that Time.deltaTime has different values after each frame, but is it normal that one of the first values is so much higher than the others?
Answer by IntergalacticSloth · Jul 03, 2017 at 03:56 PM
I'll leave this for others. I had a similar problem where the axes start to get all messed up over time.
I think I was suffering from "Un-commutativeness of Rotation in 3D Space". Explained at this link.
I shared the details of my solution on that link. And shared again as an answer to this question. (Just want to make sure y'all can find the information I could not.)
Your answer
![](https://koobas.hobune.stream/wayback/20220613102207im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
90 Degree stopping rotation on y-axis issue 0 Answers
LookAt on one axis 2 Answers
Transform.Translate but ignore rotation on one axis 0 Answers
Orbit Collision Axis 0 Answers
joystick dpad axes snapping to 1 0 Answers