- Home /
Rotating child object around X and Z from different angles causing issues
I've been trying to write the logic for rotating an object that is nested in a parent object.
The parent object will be rotated around the Y axis (and possibly in other directions in future, so I don't want to tie rotating the child object to using and world space coordinates, as it should rotate relative to the parent.)
The child object needs to rotate in 90 degree increments in X and Z depending on the view point. Basically there are turn left and turn right buttons, if looking straight on (on positive Z direction) the turn right will rotate the child 90 degrees around Z, if looking from the side (along the negative x direction) the turn right will rotate the child 90 degrees around x.
I've been trying to do this with euler angles but I think I'm running into gimble lock and think I need to be using quaternions.
Currently I have this, it appears to be working if the child begins at 0, 0, 0 rotation, but if it's already been rotated it is behaving strangely and rotating in unintended directions
public void TurnRight(ViewPoint viewPoint, int rotations) {
switch (viewPoint) {
case ViewPoint.A:
RotateZ(rotations);
break;
case ViewPoint.B:
RotateX(rotations);
break;
case ViewPoint.C:
RotateZ(-rotations);
break;
case ViewPoint.D:
RotateX(-rotations);
break;
}
}
private void RotateZ(int value) {
transform.Rotate(new Vector3(0, 0, 90 * value));
}
private void RotateX(int value) {
transform.Rotate(new Vector3(90 * value, 0));
}
How were you using euler angles? I always use euler angles when rotating things. Only way for me to get what I want lol
Answer by cjdev · Jun 09, 2016 at 12:42 PM
As FortisVenaliter said, this isn't a case of Gimbal Lock but of local vs world coordinate systems. Still, I'd recommend using Quaternions anyways because it's a good habit to get into. In this case it might look something like this:
transform.rotation *= Quaternion.Euler(0, 0, 90f * value);
Note that multiplying Quaternions is adding their rotations.
That didn't solve my problem and I think it's equivalent to the code I initially posted. But I do now understand the problem more. $$anonymous$$y issue is if the transform starts at (0, 0, 0) to turn it left I'd need to rotate it -90 in z to (0, 0, -90). But if it starts at say (0, 90, 0) then the z rotation would be in the wrong direction and I'd actually need a 90 degree x rotation ins$$anonymous$$d to (90, 90, 0). How would I go about knowing which rotation to apply in this case?
If you need to rotate around an arbitrary axis in world space you can use Quaternion.AngleAxis ins$$anonymous$$d.
Awesome that's what I was missing, working well now! Thanks @cjdev! I realise my original question wasn't at all well worded so thanks for sticking with me :)
Ok maybe I jumped the gun, I thought this did the trick but I've noticed some odd behaviour. $$anonymous$$y code now looks like this: void RotateZ(int value) { transform.rotation *= Quaternion.AngleAxis(90f * value, pivot.transform.forward); }
and void RotateX(int value) { transform.rotation *= Quaternion.AngleAxis(90f * value, pivot.transform.right); }
with pivot being the transform I want to rotate relative to. This works great if the transform is (0, 0, 0) and works rotating from any view point. But if from one viewpoint I rotate it to (0, 0, 90) with the RotateZ
method, then switch view and RotateX
it rotates the child around Y and I can't figure out why
Are you changing the rotation of the pivot at all? You're using it's local right and forward as the axis to rotate around and if the pivot gets rotated the axis of rotation will change.
The pivot is childed to the main playspace. Neither the playspace or the pivot object have any rotation. I'm just rotating the camera around the playspace, the playspace isn't moving at all so I can rule that out. Right now it's just the camera position and rotation and the child's rotation which is changing.
What's weird is if I rotate the child 90 degrees in Z, and I moved to a side view I would expect a TurnRight it to rotate 90 in Y (in the child's local transform because after 90 z rotation, the child's Y axis should be in parallel to the pivot's x axis, and a side view calls RotateX
). And in the inspector it's changing to (0, 90, 90) but it appears to be moving around the child's x axis which is now pointing up and down in line with the pivots Y axis.
As I'm only rotating in 90 degree shifts I could probably write some if statements as the logic seems broken if the child is on it's side (90 or 270) so I could rotate on a different axis in these cases but I'd love to expand my understanding by understanding what is going on here.
If it makes it easier to understand the child should always rotate around the local axis which is pointing towards the camera
Answer by FortisVenaliter · Jun 08, 2016 at 07:09 PM
Check out the documentation. If you don't specify which frame of reference to use, it uses the world frame. What you want for this code to work is the local frame. You can achieve this by adding Space.Self as a second parameter to the transform.Rotate() calls.
Thanks but I need to rotate locally to the parent and I'm not sure of a way of doing that. If a piece gets rotated it's X and Z planes move too, so I can't rotate it in relation to that I don't think. I think I need to rotate it based on the fixed parent axis