Search Unity

How to Lock or Set the Camera´s Z rotation to ZERO ?

Discussion in 'Scripting' started by Falott, Nov 29, 2010.

  1. Falott

    Falott

    Joined:
    Nov 29, 2010
    Posts:
    8
    hello everybody!
    I have very little programm experience so far so please be patient with me:

    task:
    creating the simplest flythrough camera possible. move in direction Z and X, plus rotating the camera by the help of LMB on screen.

    _____________________________________

    using UnityEngine;
    using System.Collections;

    public class CameraX : MonoBehaviour
    {
    public float speed = 100F;
    public float rotationSpeed = 2.0F;


    void Update()
    {
    float translationZ = Input.GetAxisRaw("Vertical") * speed;
    float translationX = Input.GetAxisRaw("Horizontal") * speed;
    translationZ *= Time.deltaTime;
    translationX *= Time.deltaTime;

    transform.Translate(translationX, 0, translationZ);


    // camera lookat
    if (Input.GetMouseButton(0))
    {
    float h = rotationSpeed * Input.GetAxis("Mouse X");
    float v = rotationSpeed * Input.GetAxis("Mouse Y");

    transform.Rotate(-v, h, 0);


    }
    }
    }



    problem:

    unfortunately the Z_rotation is never 0 at all. with every mouseAction on the screen the rotation.z is constantly updated and makes the camera tilt left or right.

    maybe I read C# wrong, but shouldn´t this line of code prevent the camera from tilting and "lock" the z rotation?

    transform.Rotate(-v, h, 0);


    many thanks in advance!
    Falott
     
  2. mrwelcam@hotmail.com

    mrwelcam@hotmail.com

    Joined:
    Nov 26, 2010
    Posts:
    17
    You could use a quaternion to do the rotation.
     
  3. paulg568

    paulg568

    Joined:
    Sep 9, 2010
    Posts:
    31
    I am not sure if this will work since I have never tried it but you can attach a Configurable Joint to your camera and restrict the Angular ZMotion.

    To do this you go to Component -> Physics -> Configurable Joint.

    Then in the inspector change Angular ZMotion from free to Locked.

    Let me know how it goes if you try this out.
     
    Term1nus3st likes this.
  4. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    That won't change anything (the OP is already rotating using quaternions, albeit indirectly).

    That shouldn't be necessary.

    It actually doesn't have anything to do with the language (C#, UnityScript, etc.), but rather how Transform.Rotate() functions. To answer your question, no, that line of code won't prevent the object from rolling. In fact, it will almost certainly lead to perceived roll over time.

    The above line of code applies relative rotations about the local side and up axes. If you hold some object in your hand that has a clear local orientation (that is, you can visualize in which directions the local axes point) and then rotate it randomly and incrementally about its local side and up vectors, you should see that it can quickly end up in more or less arbitrary orientations, including orientations that cause the perception of roll.

    For standard FPS-style controls, what you want to do instead is to rebuild the orientation from scratch each update from two angles (e.g. yaw and pitch). The easiest way to do this is probably to assign a new value directly to transform.eulerAngles.
     
  5. Nikolay116

    Nikolay116

    Joined:
    Mar 21, 2010
    Posts:
    421
  6. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
  7. Falott

    Falott

    Joined:
    Nov 29, 2010
    Posts:
    8
    first of all - thanks to all of you for your input,

    I tried to stick to Jesse Anders advice and rebuild rotation from scratch by use of euler.Angles. unfortunatelly, since I am just starting to wrap my brain around the programming language I am not able to find the right commands for solving this.I didn´t find the right topics in the docs - or I am just not able to stitch the right sections of code together. here is what I have so far:

    I thought I´ve already stored values in a temporary variable:

    float y = rotationSpeed * Input.GetAxis("Mouse X");
    float x = rotationSpeed * Input.GetAxis("Mouse Y");
    float z = 0;


    I searched the docs for everything that has to do with transform.eulerAngles, but nothing really helps me out here. I am sure this rotation issue is a very common problem for a lot of people in the beginning. funny enough I havent found similar topics on the net.

    would be happy if anyone can point me in the right direction or even write down the correct lines of code for the eulerAngles if thats not overcharged.

    thx alot so far!
     
  8. Ifandbut

    Ifandbut

    Joined:
    Dec 1, 2010
    Posts:
    19
    I had about the same problem as you do today when I was learning Unity today. It ended up being real simple.

    Using your code:
    Code (csharp):
    1.  
    2. if (Input.GetMouseButton(0))
    3. {
    4. float h = rotationSpeed * Input.GetAxis("Mouse X");
    5. float v = rotationSpeed * Input.GetAxis("Mouse Y");
    6.  
    7. transform.Rotate(-v, h, 0);
    8. //Add these two lines
    9. float z = transform.eulerAngles.z;
    10. transform.Rotate(0, 0, -z);
    11. }
    Basically you apply the rotation you want, then cancel out any Z rotation that got added in there.
    There might be a better way to do it but this is what I came up with while learning Unity today.
     
  9. Falott

    Falott

    Joined:
    Nov 29, 2010
    Posts:
    8
    thx a ton mate, this does the trick perfectly!

    I´d like to add one question tough because I am curious -

    If I understand it correctly you defined the current zRotation value as a variable with:
    float z = transform.eulerAngles.z;

    and subtracted that value from each updated zRotation with:
    transform.Rotate(0, 0, -z);

    which makes sense for me if only Z is taken into account.
    but why doesn´t this set x and y to 0? or does this command mean -> rotate +0 +0 -z (basically just an addition)
    ok, by writing that question down it makes perfect sense now.

    again - thx a lot for your help!
     
  10. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    Rather than trying to 'correct' the orientation using Transform.Rotate() (I'm actually a little surprised that that seems to be working correctly), better just to do it right from the get-go, IMO.

    Here's some example code (C#). I'm just going to type this into the post, so no guarantee of correctness:

    Code (csharp):
    1. public class MyClass : MonoBehaviour
    2. {
    3.     public float rotationSpeed;
    4.  
    5.     float pitch;
    6.     float yaw;
    7.    
    8.     void Update()
    9.     {
    10.         pitch += rotationSpeed * Input.GetAxis("Mouse Y");
    11.         yaw += rotationSpeed * Input.GetAxis("Mouse X");
    12.        
    13.         // Clamp pitch:
    14.         pitch = Mathf.Clamp(pitch, -90f, 90f);
    15.        
    16.         // Wrap yaw:
    17.         while (yaw < 0f) {
    18.             yaw += 360f;
    19.         }
    20.         while (yaw >= 360f) {
    21.             yaw -= 360f;
    22.         }
    23.        
    24.         // Set orientation:
    25.         transform.eulerAngles = new Vector3(pitch, yaw, 0f);
    26.     }
    27. }
     
  11. Ifandbut

    Ifandbut

    Joined:
    Dec 1, 2010
    Posts:
    19
    Well I have only been scripting with Unity for less then 24hrs and it was the first solution I came up with. I just plugged your solution in and it works fine. I actually like yours better because it feels like less of a hack then mine.
     
  12. Falott

    Falott

    Joined:
    Nov 29, 2010
    Posts:
    8
    Thanks for the additional explanation on the script!

    I´ve tested it right away and it is kind of working. I guess there´s nothing wrong with both methods, the only concern but is that the updating of Zrotation isn´t working as clean as ifandbut´s script does. means, the Z value gets cleared every 2nd - 4th mouse click. I added ->
    Code (csharp):
    1.  if (Input.GetMouseButton(0)){
    again, before calculating rotations. (also tested it without GetMouseButton of course) in between the rotation shows values between +10 and -10. I have no clue why, but on the other hand it´s not such a big problem since it gets updated - but it doesn´t seem to follow a rule.

    more of an issue is that the camera gets initiated at rotation (0 0 0) not right after hitting play but after the very first mouse movement. it hasn´t anything to do with Clamp pitch or Wrap yaw, since I´ve commented these lines out to test it. in my understanding these lines
    HTML:
                pitch += rotationSpeed * Input.GetAxis("Mouse Y");
                yaw += rotationSpeed * Input.GetAxis("Mouse X");
    should feed the camera with update information, but not zero out rotation and go from there.

    I updated the script with your suggestions and it would be nice to get rid of the camera jump at start. but unless it is working I´d rather stick to the ifandbut_version since it takes the initial camera rotation into acount and animates from there.

    again thank you for the valuable input!


    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class simpleFlyThrough : MonoBehaviour
    5. {
    6.     public float speed = 100F;
    7.     public float rotationSpeed = 2.0F;
    8.  
    9.     float pitch;
    10.     float yaw;
    11.  
    12.  
    13.     void Update()
    14.     {
    15.         float translationZ = Input.GetAxisRaw("Vertical") * speed;
    16.         float translationX = Input.GetAxisRaw("Horizontal") * speed;
    17.         translationZ *= Time.deltaTime;
    18.         translationX *= Time.deltaTime;
    19.  
    20.         transform.Translate(translationX, 0, translationZ);
    21.  
    22.  
    23.         // camera lookat
    24.         if (Input.GetMouseButton(0))
    25.         {
    26.             pitch += rotationSpeed * Input.GetAxis("Mouse Y");
    27.             yaw += rotationSpeed * Input.GetAxis("Mouse X");
    28.  
    29.             // Clamp pitch:
    30.             pitch = Mathf.Clamp(pitch, -90f, 90f);
    31.  
    32.             // Wrap yaw:
    33.  
    34.             while (yaw < 0f)
    35.             {
    36.                 yaw += 360f;
    37.             }
    38.             while (yaw >= 360f)
    39.             {
    40.                 yaw -= 360f;
    41.             }
    42.  
    43.  
    44.             // Set orientation:
    45.             transform.eulerAngles = new Vector3(-pitch, yaw, 0f);
    46.         }
    47.     }
    48. }
     
    Last edited: Dec 2, 2010
    eccece likes this.
  13. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    I'm not sure if I fully understand what problems you're running into, but:

    I'm not sure what you mean by that. Unless you're trying to do something different than I think you're trying to do, there should be no updating of the z rotation, nor any need to update the z rotation. (My understanding was that you wanted standard 'FPS-style' control with no z rotation at all, but maybe my understanding is incorrect.)

    That's due to a logic error in your code. You're only setting the camera orientation when the mouse button is down; if you move that line of code outside of the conditional (so that it executes every update regardless of whether or not the mouse button is down), it should work as expected.

    Those lines have no effect on the camera orientation.

    If you want to start from the original rotation, you can initialize yaw and pitch to appropriate values in Awake() or Start() (assuming that the original rotation incorporates yaw and pitch only).

    If the other method is working for you, then that's good, I suppose, but I still question it (it seems like a workaround, and it also seems like it could potentially produce incorrect results in some cases).
     
  14. Falott

    Falott

    Joined:
    Nov 29, 2010
    Posts:
    8
    Hey Jesse!

    thanks for all your help!

    to be honest I still don´t quite know what a standard FPS-style controlled camera actually does. my basic intention is to have a camera which can fly through space and have zero values on zRotation to not get sick while watching. in my specific case here I have a simple presentation scene. it´s a concept design object which can be viewed freely from all sides by the clients.

    I´ve mapped all actions to the mouse for convenience. also targeted the camera to my object now because classic awsd + mouse doesn´t fit the purpose.

    I´ve finished my script with your helps. it´s short and more or less easy to understand for me, but it lacks preciseness, means - when I move the camera around the object very fast, it drifts away and moves out of my clipping planes sooner or later. but anyway, the camera at least functions as intended. another minus with my script is, that speed multipliers don´t effect the movement in a linear way or as I would expect it.

    to sum up, here´s the script. it should tell you much quicker what I was looking for.

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class simpleFlyThrough_test : MonoBehaviour
    5. {
    6.     public float speed = 10F;
    7.     public Transform target;
    8.        
    9.     void Update()
    10.     {
    11.     // float translationY = Input.GetAxisRaw("Vertical") * speed;
    12.     // float translationX = Input.GetAxisRaw("Horizontal") * speed;
    13.        
    14.        
    15.         if (Input.GetMouseButton(0))
    16.         {
    17.            
    18.         float translationX = Input.GetAxisRaw("Mouse X") * speed *20;
    19.         float translationY = Input.GetAxisRaw("Mouse Y") * speed *20;      
    20.                
    21.         translationY *= Time.deltaTime;
    22.         translationX *= Time.deltaTime;
    23.            
    24.         transform.Translate(-translationX, -translationY, 0);
    25.            
    26.         }
    27.        
    28.         float translationZ = Input.GetAxisRaw("Mouse ScrollWheel") * speed * 160;
    29.        
    30.         translationZ *= Time.deltaTime;
    31.        
    32.         transform.Translate(0, 0, translationZ);
    33.        
    34.         // look at target
    35.         transform.LookAt(target.transform.position);   
    36.        
    37.     }
    38. }
     
  15. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    I'm not sure what the difference between GetAxis() and GetAxisRaw() is for mouse movement (maybe the docs say - I haven't checked). In general though, you don't need to scale mouse movements by Time.deltaTime because they're already implicitly time scaled. (I kind of doubt this is the cause of the 'precision' problems you're seeing though - that may be more an issue of shortcomings in the control scheme itself, and/or just not having your 'speed' value set to an appropriate value.)
     
  16. gagalug

    gagalug

    Joined:
    Oct 25, 2011
    Posts:
    1
    Hey I tried this it didn't work the camera still rotated but it looked as if it were lagging when rotating. :razz:
     
    Nolaif likes this.
  17. Kjaka

    Kjaka

    Joined:
    Dec 8, 2015
    Posts:
    18
    Thank you that was clear
     
    Jonnypontes likes this.
  18. reutrabin

    reutrabin

    Joined:
    Sep 16, 2018
    Posts:
    1
    Worked perfectly, thanks!
     
  19. philpw99

    philpw99

    Joined:
    Dec 1, 2021
    Posts:
    1
    I know this is a very old threat, yet as a newbie I still didn't get it right until I change the code like this:

    Code (CSharp):
    1. public class CameraMove : MonoBehaviour
    2. {
    3.     public float CameraSpeed = 1.0f;
    4.    
    5.     // Update is called once per frame
    6.     void Update()
    7.     {
    8.         float yRot = CameraSpeed * Input.GetAxis("Vertical");
    9.         float xRot = CameraSpeed * Input.GetAxis("Horizontal");
    10.  
    11.         if( xRot != 0 ){transform.Rotate(0.0f, xRot, 0.0f, Space.World);}    // horizontal
    12.         if( yRot != 0 ){transform.Rotate(yRot, 0 , 0, Space.Self);}    // Vertical
    13.     }
    14. }
    You see. The problem of the whole thing is that the camera rotates not follow the world's Y axis, but on its own Y axis.
    So I think the above code is the simplest way to keep the camera at a horizontal level.