Search Unity

How do you rotate the camera down to 45 degrees no matter what direction you're facing? (SOLVED)

Discussion in 'Getting Started' started by sr3d, Oct 27, 2015.

  1. sr3d

    sr3d

    Joined:
    Oct 19, 2015
    Posts:
    78
    SOLVED - use the code below to make camera look down by 45 degrees.

    Better code that doesn't gimbal lock
    Code (csharp):
    1.  
    2.   Quaternion centeredRotation = Quaternion.Euler(camCenteredAngle, transform.eulerAngles.y, transform.eulerAngles.z);
    3.  
    4.   //smoothly rotate the camera down towards the centered angle which means user wants to look at ground via c hotkey
    5.   transform.rotation = Quaternion.Slerp(transform.rotation, centeredRotation, Time.deltaTime * camSlerpToCenterSpeed);
    6.  
    7. //if you don't want to slerp just do this
    8. // transform.rotation = centeredRotation;
    9.  

    The following code is prone to gimbal lock if you start to lerp/slerp.
    Code (csharp):
    1.  
    2. //get the camera's current local euler angles
    3. Vector3 camLocalEulerAngles = transform.localEulerAngles;
    4.  
    5. //setting x will make the camera look down at the ground at 45 degree angle
    6. camLocalEulerAngles.x = 45;
    7.  
    8. //apply change to camera
    9. transform.localEulerAngles = camLocalEulerAngles;
    10.  



    Okay imagine you're looking straight, now look down 45 degrees. No matter where you're standing,you just tilt your head down by 45 degrees.

    How do I do this in Unity?

    I still haven't got my head around the rotation math.

    Here is my code. I want the camera to just look down at the terrain when the user presses the C key.

    Code (csharp):
    1.  
    2.   //when use hit's c key, the camera tilts down by 45 degrees to look at the terrain
    3.   if (Input.GetKey(KeyCode.C))
    4.   {
    5.  
    6.   // Get a copy of your forward vector
    7.   Vector3 forward = transform.forward;
    8.  
    9.   float headingAngle = Quaternion.LookRotation(forward).eulerAngles.y;
    10.  
    11.   Quaternion testing = transform.rotation;
    12.  
    13.   //this gets the camera to tilt down by 45 degrees
    14.   testing.x = 0.5f;
    15.   //if i don't set this to 0 the camera z ends up tilting, but if i zero it out the camera will always tilt in one direction
    16.   testing.z = 0f;
    17. //.... ??
    18.   testing.y = 0f;
    19.  
    20.   transform.rotation = new Quaternion(0.5f, 0, 0, 0);
    21.  
    22.   //the mouse free look modifies this camRotationX value, i have to calculate this based upon the above code
    23.   //camRotationX += testing.x * Time.deltaTime;
    24.  
    25.   //transform.rotation = testing;//Quaternion.Slerp(transform.rotation, transform.rotation + Vector3.down, 2.0f);
    26. //no matter what this always just rotates the camera forward straight without any angle
    27. //transform.eulerAngles = new Vector3(1, 0, 0);
    28.   }
    Unity needs functions that are easier to use.

    transform.rotatedownby(45);
    transform.rotateupby(45);
    transform.rotateupleftby(45);
    transform.rotaterightby(45);
     
    Last edited: Oct 27, 2015
  2. sr3d

    sr3d

    Joined:
    Oct 19, 2015
    Posts:
    78
    transform.rotation equals the exact same rotation EXCEPT the camera faces downwards by 45 degrees on the X axis ....

    I'm going to punch a hole in the wall.
     
  3. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Unity's functions are easy to use — your "transform.rotatedownby(45)" is exactly the same as transform.Rotate(45,0,0).

    So I think the difficulty isn't in rotating the camera down 45 degrees; it's in integrating it with whatever else you've got going on.
     
  4. sr3d

    sr3d

    Joined:
    Oct 19, 2015
    Posts:
    78
    The problem is the camera moves and rotates. Before rotating the camera I need to remember all it's rotations, then only adjust the Rotate(45,currenty, currentz). I need the rotation calculation to somehow know how to rotate the camera down by 45 degrees and take direction into consideration too.

    I'm trying to find tutorials that teach you how to rotate how you want no matter what direction your facing.

    Imagine walking out your door, turning around three times, looking left, right, up, down, left, right. Now take your last rotation positions, but set your head to look down at the ground at 45 degree angle. That is what I'm trying to do.

    Code (csharp):
    1.  
    2. //whatever my current rotation, just rotate down in front of me at 45 degree angle
    3. //this doesn't work, there is something i'm missing.  the camera just flips upside down
    4. //transform.rotation = transform.rotation * Quaternion.Euler(45f, 0f, 0f);
    5. transform.RotateAround(transform.position, Vector3.back, -45);
    6.  
    No matter where the camera is or what rotation it is or what direction it's facing, if you hit C the camera will just look down at the ground. Why is this so hard to do.
     
    Last edited: Oct 27, 2015
  5. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    There is no calculation. That's what transform.Rotate does (it applies an additional rotation to whatever the current orientation is).

    That tutorial is here. (You probably want the second version, the one that takes xAngle, yAngle, and zAngle, as this is probably easiest to understand — but fundamentally they all do the same thing.)

    Yes, I understand. This is exactly what transform.Rotate(45, 0, 0) does.

    Accept it. It really does do what the docs (and I) say it does. If you believe you are observing something else, then either you are not calling this, or you are calling it multiple times, or you are calling it and also calling a bunch of other stuff, or you are misinterpreting what you see.
     
  6. sr3d

    sr3d

    Joined:
    Oct 19, 2015
    Posts:
    78
    You're right about that, I appreciate it.

    I am very close to what I need now.

    Code (csharp):
    1.  
    2. //Camera slowly tilts down as if you're turning your head down to look at the ground
    3. transform.Rotate(45f * Time.deltaTime, 0, 0);
    4.  
    ......... But what i need is a way to immediately set the transform.rotation to a 45 degree downwards angle. transform.Rotate(45f * Time.deltaTime, 0, 0); is too slow and it doesn't precisely set the angle.

    Man I swear I'm going to write a guide after this. This is brutal.
     
    Last edited: Oct 27, 2015
  7. sr3d

    sr3d

    Joined:
    Oct 19, 2015
    Posts:
    78
    FINALLY.

    Code (csharp):
    1.  
    2. //get the camera's current local euler angles
    3. Vector3 camLocalEulerAngles = transform.localEulerAngles;
    4.  
    5. //setting x to 45 will make the camera look down at the ground at 45 degree angle
    6. camLocalEulerAngles.x = 45;
    7.  
    8. //apply change to camera
    9. transform.localEulerAngles = camLocalEulerAngles;
    10.  
     
  8. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    That won't work, in general. Euler angles are funny. Depending on how the camera has rotated up to this point, just setting the X angle to 45 could cause it to appear to roll or yaw in addition to the pitch you intended. (And no, this isn't Unity's fault; it's just the nature of rotations, and Euler angles in particular.)

    But I think now I'm starting to see what you really want... you don't want to rotate the camera 45 degrees down (if you did, transform.Rotate(45,0,0) would do it). You want to rotate it by some amount such that it ends up tilted 45 degrees down from horizontal. So for example if it was already looking 30 degrees down, you only want to rotate it 15 degrees more.

    Is that right?

    If so, that is a little hard to do reliably based just on the current transform. It can be done, but I think you're not going to like the math involved.

    Generally it's much better to instead do this at a higher level, at the level of your camera controller. You already have a representation somewhere of your camera in terms of a point of interest, Y angle, and angle to the ground, right? That's where you should add this feature. The easiest way would probably be to add an additional rotation, using Transform.Rotate, that takes into account the current angle to the ground you already have. (But there are lots of other ways too.)

    If you really do need to do this in a separate component, starting with nothing but the transform, then you can still do it; the math isn't that bad. Let me know if that's the case and I'll sketch out the solution for you. But having two different components modifying the camera transform at the same time seems like a recipe for grief to me.
     
  9. sr3d

    sr3d

    Joined:
    Oct 19, 2015
    Posts:
    78
    I see, it even says so here - http://docs.unity3d.com/ScriptReference/Transform-eulerAngles.html

    Do not set one of the eulerAngles axis separately (eg. eulerAngles.x = 10; ) since this will lead to drift and undesired rotations. When setting them to a new value set them all at once as shown above. Unity will convert the angles to and from the rotation stored in Transform.rotation.

    I'll fix my code asap.

    Yes exactly! :)

    Point of Interest
    Hmmmm, what is a point of interest? I just tried googling it but I got nothing concrete. Is this a programming term in general or a game dev concept? I've heard people talk about the POI a lot.

    Y angle, yes I believe so.
    //this remembers the cam's rotation on the Y (up and down)
    private float camRotationY;

    Angle to the ground, I believe so.
    //camera elevation, the distance that is kept between the camera and whatever is below it (terrain, cubes, spheres, etc)
    public float camElevation = 30f;

    I already have the camera elevation managed and I keep track of it's rotation angles. I can hold down right click to look around, then I can hold Q & E to rotate the camera left & right. Both of these functions keep track of the camRotationX and camRotationY, that way there is no sudden shifts between using Q & E to rotate the camera or right mouse click.

    Learning how to add rotations would be extremely useful!

    Whatever you show me here is going to be a part of this free RTS Camera script I've been working on - http://forum.unity3d.com/threads/mr-generic-rts-camera-movement-script-v1-01a-free.363491/

    If you have time to give a quick explanation, I'd appreciate that! :)

    Despite my moaning and complaining, I"m amazed at how fast this game project is coming along.
     
    Last edited: Oct 27, 2015
  10. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Sorry, I may have called it "focus" or "focal point" or something before... I'm talking about the point on the map that the camera is orbiting around.

    Uh-oh — your comment here suggests a pretty fundamental misunderstanding. Y rotation is not up and down. Y rotation is around the Y axis. The axis points up and down, but if you rotate around that, you're rotating in the XZ plane. Go to the playground, stick your hand on some vertical pole, and hold it tight while you run around it in circles — you're doing a Y rotation.

    Maybe you understood all this already, but I just wanted to be sure.

    Ah, so you're keeping elevation instead of angle to the ground. That makes it a bit harder.

    OK, going to check out your code to see what it's actually doing...

    Ah. Hm. Your code is directly rotating and translating the transform all over the place.

    You have elected the way of pain.

    The easier, safer way to write any camera control script is this: you keep track of the handful of variables you need to define where the camera should be (e.g. focal point, Y rotation, and height), and all your inputs affect only those variables. They do not directly muck with the transform. Then, in your Update method, you set (not modify!) the transform directly from those variables.

    When you do it this way, it is very easy to add one extra step while setting the transform, to adjust the angle and look down more if you're in "glance down" mode or whatever.

    The way you're doing it, modifying the transform all over the place and using the transform itself as part of the data that keeps track of where the transform should be, is just asking for trouble. It's very easy to get confused and in some cases can subject you to nasty things like gimbal lock.

    Go look through the various controller scripts on the wiki. Almost all of these will do it as I've described. This one seems like a pretty decent start for what you're trying to do.
     
  11. sr3d

    sr3d

    Joined:
    Oct 19, 2015
    Posts:
    78
    I see, now I know what point of interest is, thanks. In my case the camera orbits the terrain or objects like spheres, cubes, buildings, etc if it needs to auto elevate. The POI is the terrain and any objects the camera needs to fly over.

    It's funny you mentioned this. I'm now changing my wording.

    WRONG
    Code (csharp):
    1.  
    2. camRotationX += Input.GetAxis("Mouse X") * 180.0f * Time.deltaTime;
    3. camRotationY += Input.GetAxis("Mouse Y") * 180.0f * -Time.deltaTime;
    4.  
    5. //debug is your friend
    6. Debug.Log("camRotX:" + camHorizontalRotation + " " + "camRotY:" + camVerticalRotation + " " + "euler:" + transform.eulerAngles);
    7.  
    RIGHT
    Code (csharp):
    1.  
    2. //get rotation x y of mouse when you hold down right click and look around
    3. camHorizontalRotation += Input.GetAxis("Mouse X") * 180.0f * Time.deltaTime;
    4. camVerticalRotation += Input.GetAxis("Mouse Y") * 180.0f * -Time.deltaTime;
    5.  
    6. //debug is your friend
    7. Debug.Log("camHorizRot:" + camHorizontalRotation + " " + "camVertRot:" + camVerticalRotation + " " + "euler:" + transform.eulerAngles);
    8.  
    Nope, you were right. Noob mistake lol.

    What do you mean by angle to the ground? The camera moves along the X, Z and if the camera needs to go up and down that's the Y. What does it mean to keep the angle to the ground? Man, what a stupid question. I should be embarrassed, lol.

    By angle to the ground, you mean if the camera is facing the ground?

    Oh boy, I need to fix that asap.

    I'm going to do that now. I need to take my code to the next level as you just described. Thanks! This helps a great deal.
     
  12. jhocking

    jhocking

    Joined:
    Nov 21, 2009
    Posts:
    814
    fyi this
    is more or less what I was doing in the other RTS camera thread, where I suggested changing the camera movement script to store the transform position in a variable, do stuff to that variable, and then set the transform to the modified values.
     
    JoeStrout and sr3d like this.
  13. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Not at all — you're asking good questions. (And in a space of a week you've gone from grousing almost to the point of being a troll, to sharing good stuff and asking good detailed questions, along with a clear willingness and ability to learn! I'm glad we didn't give up on you. :))

    So, there are different ways of thinking about "camera orbits around a point." Fundamentally it all comes down to spherical vs. cylindrical coordinates.

    I was originally proposing a spherical approach, like this:

    Here the position of the camera is described by: (1) a focal point (O in the diagram above); (2) the angle around the vertical axis (which would be yAngle — ignore how the axes are labeled in that picture!); (3) and the angle up from the ground; and (4) the radius, or distance from the focal point. Moving the camera "up" in this system would mean keeping the same distance from the focal point, but changing that angle to the ground so you're looking more directly down on the focus.

    But you went with a cylindrical system — which is cool too. It looks something like this:

    Again ignore the axis labels (darn mathematicians... don't they know that "Y" is up?!?). So here the position of the camera is described by (1) a focal point, same as before; (2) the angle around the vertical axis (same again); (3) the height above the ground; and (4) the radius, or distance from the focal point, as measured in the XY plane. So with this one, moving "up" literally means just increasing your height above the ground; your XZ position doesn't move at all. And you can never look directly down at the focal point, no matter how high up you go.

    So, either representation is fine; you just have to choose which one produces the behavior you want.

    And it sounds like @jhocking is helping you in that other thread, so you're in good hands. I didn't jump in there because I felt I didn't have time to get into it... though look at me now. :p
     
  14. sr3d

    sr3d

    Joined:
    Oct 19, 2015
    Posts:
    78
    Since programming a custom camera and custom menu system takes so much time, I might as well spend the same time doing it on a better engine.

    I've moved on to the Unreal Engine, goodbye Unity!
     
  15. Adam-Buckner

    Adam-Buckner

    Joined:
    Jun 27, 2007
    Posts:
    5,664