Rotating, Panning, and Zooming a Camera in Unity

————————————————

Link to code on bottom of post. ↓

————————————————

In Caelium, one of the features I wanted was simple camera movement system that could rotate the camera, pan it on the plane defined by its forward direction, and zoom. In the video, I demonstrate the movement of a camera in Unity.

To rotate the camera, you left click the mouse and move around. To pan the camera, you right-click the mouse and move around. To zoom, you middle click the mouse and move up or down.

By no means is it perfect, but what I have now is pretty good, as you can see in the video. I’ll explain how the movements work.

————————————————

I’ll start with zooming since that’s the simplest. You move the camera forward or back by a numerical factor. In my implementation, the factor is calculated based on the displacement of the mouse’s position from the point the mouse was at when zooming was enabled. This factor is used in all the camera movements. This part of the code came from a Unity forum topic about camera movement, so credit for this snippet goes to damien_oconnell:

Vector3 pos = Camera.main.ScreenToViewportPoint(Input.mousePosition - mouseOrigin);

The pos is the factor that determines how much rotation, panning, or zooming happens. It’s used when calculating the camera’s change in position that’s needed for zooming:

Vector3 move = pos.y * zoomSpeed * transform.forward;
transform.Translate(move, Space.World);

The move vector is used to move the camera. Only the y factor in pos is needed because we only want to zoom if the mouse moves up or down. The zoomSpeed is  a public variable (a float) that’s used to adjust the right amount of zoom.

————————————————

The panning code used the pos factor to determine how much to pan. In the code snippet, pos.x pans the camera in its x-dimension (left and right) and pos.y pans in the y-dimension (up and down). I attribute this code to damien_oconnell from the Unity Forum link mentioned before (here, the panSpeed is a public variable to adjust panning):

Vector3 move = new Vector3(pos.x * panSpeed, pos.y * panSpeed, 0);
transform.Translate(move, Space.Self);

The big difference here is that we use Space.Self, and not Space.World. The reason is because we want to pan the camera along a plane defined by the camera’s forward direction, not the world’s forward direction. Using the camera’s forward direction, we can pan consistently with respect to the camera, even if the camera is rotated in some obscure angle.

————————————————

I had a little trouble with rotating the camera, but I figured it out eventually. The premise for rotating was when the mouse moved up and down, the camera would look up or down. If the mouse moved left or right, the camera would turn left or right.

The problem was when I tried rotating the camera starting with its up direction being the same as the world’s up direction, rotating at an obscure angle would cause the camera’s up to be misaligned with the world’s up.

Before talking about how I fixed this, I’ll talk about the rotation code. To rotate the camera, you call RotateAround(), which takes a position that is used as the center of rotation, the axis in which to base the rotation, and the angle of rotation desired (in the code, the turnSpeed is a public variable to tweak the change in rotation):

transform.RotateAround(transform.position, transform.right, -pos.y * turnSpeed);
transform.RotateAround(transform.position, transform.up, pos.x * turnSpeed);

When moving the mouse diagonally, the camera’s transform.up would not point in the same direction as the up direction defined by the world (which technically never changes). It turns out that to keep the camera’s up direction pointing the same constant direction, I had to rotate with respect to the world as opposed to the camera. See the revised snippet for rotation:

transform.RotateAround(transform.position, transform.right, -pos.y * turnSpeed);
transform.RotateAround(transform.position, Vector3.up, pos.x * turnSpeed);

Notice how I’m now using Vector3.up instead of transform.up. If you watched in the video, you’ll notice that the gray plane in the background is always aligned as a straight horizontal line and never goes diagonal. That’s how you know it works.

>>> You can get the whole script on GitHub Gist. Feel free to use it in your own projects. <<<

Update: A new version of this script is available here. It features smooth stopping with inertia.

Advertisements

16 thoughts on “Rotating, Panning, and Zooming a Camera in Unity

  1. Hello, may I ask you something? First, I really appreciate your work and I want to know if I need the camera panning, rotating and zooming to be smoother, what the script should change? Sorry for my poor English and wait for your response, Thank you.

    • Hi Tomleung,

      When you say “smoother,” I’m thinking you mean apply an inertia effect on the camera so that it doesn’t suddenly stop. Is that correct?

      Assuming that was what you wanted, the first thing you might want to do is to add a RigidBody component to the camera that you want to move. Take note that I haven’t tested this yet.

      The script would have to change a little in order to make use of the RigidBody. The “transform.Translate()” functions would have to be replaced with “rigidbody.AddForce()”, and the “transform.RotateAround()” functions would have to be replaced with “rigidbody.AddTorque()”. Please note that I have not tested this yet, and know that the parameters of the RigidBody functions are not identical to the Transform functions.

      The “Update()” functions would also have to be changed to “FixedUpdate()” because physics is usually implemented in “FixedUpdate()”.

      Here’s a link to documentation on “RigidBody.AddForce()”: http://docs.unity3d.com/Documentation/ScriptReference/Rigidbody.AddForce.html

      And here’s a link to documentation on “RigidBody.AddTorque()”: http://docs.unity3d.com/Documentation/ScriptReference/Rigidbody.AddTorque.html

      Hope that helps. Let me know if you’re having problems.

  2. Thank you for your quick responese. What I mean is like what you think.That I want the camera panning,rotating and zooming can be smooth like slowly accelerated when start and slowly decelerated to 0 when stop, Also, I can use a varable to control the smoothness, However I don’t know how to change your script. So I would be very happy if you help change the script and write here. Sorry becasue I’m a newie of unity. Thank you very much of your help. Waiting for your response and you are so nice.

  3. Excuse me, may I ask you a question?
    Suppose If I have your above demo and I want to use this in android or iOS smart phone, and use finger in smart phone to control all the camera movement. What should I do? Do I need to change the program? What should I consider and prepare?
    Thank you and I would wait for your response.
    Sorry for my disturbance again and I really want to learn unity from you.

  4. I understand that you would be busy. Thank you so much for your help and I would use time to study those you gave me. I would ask you questions if I still have any problems.

  5. Hi Jibran,

    Thank you very much for sharing your great work. I downloaded your code and I am trying to test with my game. I attached your CS code to my main camera. Unfortunately, whenever I try to run my game I’m keep getting error message as below:

    “NullReferenceException: Object reference not set to an instance of an object
    MoveCamera.Update () (at Assets/MoveCamera.cs:60)”

    I assume it’s just because of something real simple or easy. Any advise or guidance would be greatly appreciated.

    • Hello,

      I appreciate it when people like what I share. Unfortunately, I couldn’t reproduce the problem you had. I went into a Unity project that didn’t have the camera movement script, made a new C# script called “MoveCamera”, copied everything from the Gist’s raw link (raw link for MoveCamera.cs), and pasted it into the “MoveCamera” script file. I got no error messages. Tell me if doing my procedure worked or not.

  6. Pingback: Unity3D Camera Movement Revisited | Professional game

  7. Pingback: Touch View Transform | gongsick

Comments are closed.