Search Unity

Position stability issues with group composition

Discussion in 'Cinemachine' started by BlackGateDev, Jul 28, 2017.

  1. BlackGateDev

    BlackGateDev

    Joined:
    Jul 27, 2017
    Posts:
    9
    I've been experimenting with Cinemachine for camera control in our current project and it is really impressive in general. That said, I'm running into some camera stability issues that I cannot seem to overcome.

    Here's the situation: in our game we have a grid with a camera that is able to move and zoom in/out at certain regions of the grid, not unlike XCom games. The camera is looking down at a 45 degree angle, aligned with the forward vector of the grid. For specifying the area to be displayed, I am using a bounding box that can move freely within the bounding box of the entire grid. Using mouse and keyboard, the user can move the view bounds around and enlarge or decrease its size relative to the grid bounding box.

    To make this work with Cinemachine I calculate the corners of the view bounds, and assign their positions to four marker Transforms, which I then plug into a TargetGroup object. The virtual camera uses this TargetGroup to look at and follow it. The setup of the virtual camera can be seen in the screenshot below. The blue lines are drawn from each corner of the view bounds to the active camera in the scene.

    upload_2017-7-28_10-2-55.png

    This works great for the most part. However there are a couple issues that crop up randomly:

    A) Bobbing Up & Down: When I move the view box around, the camera bobs up slightly when the movement starts, and then down again when the movement stops. When I track the camera object, I can actually see the y component of the position changing by up to 4-5% of its stable value. This is tolerable to a degree with keyboard controls and constant movement rate. But we also have drag and move panning using the mouse for fine control, with a movement rate dependent on exactly how much the mouse has moved. That's where the up and down bobbing becomes really noticeable and jarring. I can't find any settings on the Virtual Camera script that can account for the sudden change in height of the camera transform. As you can see in the screenshot I set all damping to 0, I played around with various update methods (late update / smart update / fixed update), I tried all combinations of Target Group position and rotation modes, and all binding modes on the transposer, all to no avail. I also noticed that when panning the view bounds, there is a slight tilt to the bounding box that Cinemachine draws in scene view (in yellow), even though the corners do not move that way at all.

    upload_2017-7-28_10-32-55.png


    B) Rotation Creep: Initially I was using the default damping values on the group composer and transposer, and ran into this issue where if I panned the camera left or right and rapidly zoomed in and out (mouse wheel changes the size of the view bounds), the virtual camera would suddenly introduce a rotation around the y axis that would persist, even though no settings were changed. Interestingly, that does not happen if I go slow on the mouse wheel, or if I set all damping to zero. Similar to the problem above, I tried all combinations and could not find a way of eliminating the unexpected rotation aside from getting rid of all damping.

    C) Dolly vs Zoom: My virtual camera is set to dolly then zoom. When I pan the view bounds around, even though the size of the intended area does not change at all, I notice an increase in the camera FOV. It goes from 30 when stationary to 40 when moving, and back to 30 again when it stops, which I suspect has something to do with the tilt that CM introduces when moving (mentioned above in point A)

    To eliminate the possibility that I might be doing something silly in code, here's what I have in my CameraController:

    Code (CSharp):
    1.  
    2. public class CameraController : MonoBehaviour, ICameraDirector, IInitializable {
    3.  
    4.     [Inject]
    5.     private GridManager gridManager;
    6.  
    7.     [Inject]
    8.     private InputManager inputManager;
    9.  
    10.     private Camera _camera;
    11.     private Bounds gridBounds;
    12.  
    13.     public Transform[] ViewRectCorners;
    14.     private ViewBounds viewBounds;
    15.    
    16.     public float PanSpeed = 2;
    17.     public float ZoomSpeed = 0.2f;
    18.     private float zoomFactor = .5f;
    19.  
    20.     public Camera ActiveCamera
    21.     {
    22.         get
    23.         {
    24.             if (_camera == null)
    25.             {
    26.                 _camera = GetComponent<Camera>();
    27.             }
    28.  
    29.             return _camera;            
    30.         }
    31.     }
    32.  
    33.     [Inject]
    34.     public void Initialize()
    35.     {
    36.         _camera = GetComponent<Camera>();        
    37.         gridBounds = gridManager.GridBounds;
    38.         var view = new Bounds(gridBounds.center, gridBounds.size * zoomFactor);
    39.         viewBounds = new ViewBounds(gridBounds, view);
    40.     }
    41.  
    42.     private void ListenForInput()
    43.     {
    44.         viewBounds.horizontalNormalizedPosition -=  inputManager.HorizontalMapPan * PanSpeed * Time.smoothDeltaTime;
    45.         viewBounds.verticalNormalizedPosition -= inputManager.VerticalMapPan * PanSpeed * Time.smoothDeltaTime;
    46.         zoomFactor += (ZoomSpeed * inputManager.MapZoom * Time.smoothDeltaTime);
    47.         zoomFactor = Mathf.Clamp(zoomFactor, 0f, 1f);
    48.     }
    49.  
    50.     void Update () {
    51.         ListenForInput();
    52.  
    53.         Vector3[] corners = new Vector3[4];
    54.         corners[0] = viewBounds.View.center + new Vector3(viewBounds.View.extents.x, 0, viewBounds.View.extents.z);
    55.         corners[1] = viewBounds.View.center + new Vector3(viewBounds.View.extents.x, 0, -viewBounds.View.extents.z);
    56.         corners[2] = viewBounds.View.center + new Vector3(-viewBounds.View.extents.x, 0, -viewBounds.View.extents.z);
    57.         corners[3] = viewBounds.View.center + new Vector3(-viewBounds.View.extents.x, 0, viewBounds.View.extents.z);
    58.  
    59.         for (int i = 0; i < 4; i++)
    60.         {
    61.             ViewRectCorners[i].transform.position = corners[i];
    62.             Debug.DrawLine(corners[i], this.transform.position, Color.blue);
    63.         }
    64.         viewBounds.ClampedSize = zoomFactor * viewBounds.Borders.size;        
    65.     }    
    66. }
    67.  

    Anything I'm doing wrong here?
     

    Attached Files:

  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    Hmmm... interesting problem. I'd like to see these unwanted camera moves in action. It's not immediately obvious why you're getting them. It might be a script ordering thing. Any chance that you can zip up a sample project for me?
     
  3. BlackGateDev

    BlackGateDev

    Joined:
    Jul 27, 2017
    Posts:
    9
    Sure, just PMed you the link.
     
  4. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    Thanks, I had a look at your scene and can identify the issues.

    1. Introduction of camera pan/tilt. This is happening because you've told the camera composer to always look at the center of the group, and have at the same time added some damping to the transposer. This means that there necessarily will be a time, during the move, when the camera angle must change. Turn off transposer damping and this goes away.

    2. Persistence of pan/tilt. This is because you've given the composer a dead zone, so it stops adjusting when the center of interest hits the dead zone. Set the composer dead zone to zero, and the pan/tilt will no longer persist.

    3. The bobbing is due, as you suspected, to the change in camera angle. The box boundaries look different when viewing from a different angle, so the zoom/dolly will adjust to accommodate. Turn off transposer damping and this goes away - or make it smoother by turning up the frame damping.

    So, my question to you is: what behaviour are you looking for? Do you want there to be positional damping? If so, do you want a constant camera angle, or do you like the angle change during the damping? If you want positional damping but a constant viewing angle, you will have to set up the camera differently. Let me know.
     
  5. BlackGateDev

    BlackGateDev

    Joined:
    Jul 27, 2017
    Posts:
    9
    Thanks Gregoryl,

    I tried it and was indeed able to get rid of unwanted tilts and bobbing with elimination of damping. As for desired behavior, yeah I was hoping to have positional damping at a fixed viewing angle. Actually I just tried using smooth damp for updating the positions of the target group transforms, and that worked out just the way I was hoping for. I think the problem was that the transposer damping did not match the aim damping, so it started tracking the points with aim before the transposer actually started moving. So I'm all good for now in terms of desired outcome, but if there is a smarter way to achieve the same effect, I'd love to hear that. :)
     
    Last edited: Jul 31, 2017
  6. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    It's likely that it's working by happy accident of the damping values cancelling each other out. Probably there is a simpler way to achieve what you're looking for.

    I would tackle it this way:
    • A simple vcam with a transposer, following a dummy target object that you're moving around with the keyboard.
    • No LookAt target on the vcam. Set the vcam's transform to have the fixed angle that you want.
    • Rotate your dummy target so that its z axis is along the camera z axis (i.e. it should correspond with the camera's fixed axis).
    • Put whatever damping you like on the transposer.
    • For target repositioning, your script should just move the target around on the plane.
    • For dolly in/out, have your script simply adjust the vcam's transposer Z offset.
    • That should do it.