Search Unity

How to teleport an orbiting camera?

Discussion in 'Cinemachine' started by Seith, Dec 13, 2018.

  1. Seith

    Seith

    Joined:
    Nov 3, 2012
    Posts:
    755
    Hello, I'm currently using the FreeLook component which allows the camera to follow a transform (the player) and orbit around it using the top, middle and bottom rigs. So to change (via code) where the camera is looking I simply animate the lookAt transforms of the rigs, which works fine.

    My question is: How can I tell the camera to teleport to a certain position, while still looking at the same thing and remaining at the same distance (so that there's no nasty readjustment after the fact)?

    In other words I can tell the camera where to look and it smoothly orbits its point of interest, which is great. But how can I make it jump (via code) to another position, while remaining on the "surface/spline" determined by the lookAt rigs?
     
  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    I'm having a little trouble understanding what you're trying to do.

    The surface of the FreeLook is defined by the spline and the Follow target, not the LookAt target. The LookAt target is completely independent. So you can have the camera orbit around one thing while looking at (i.e. Aiming at) something else.

    Is that what you're doing? Is the transform you're animating for the LookAt separate from the Follow transform, or is it the same thing? If they're different, then animating the LookAt transform won't reposition the camera, it will just re-aim it in place.

    If you're trying to move the vcam to a different point on the aforementioned surface, it's just a question of setting the X/Y axis values inside the FreeLook to the appropriate values.

    If you're trying to warp the Follow target, so that the surface moves along with it, and you want the vcam to remain stuck on the surface without moving gradually to the new position because of damping, there is an API call for that: vcam.OnTargetObjectWarped():
    https://forum.unity.com/threads/rep...how-to-avoid-the-popping.514293/#post-3396611
     
  3. Seith

    Seith

    Joined:
    Nov 3, 2012
    Posts:
    755
    Thanks for you reply, Gregoryl.

    What I'm trying to do is simply have the camera be in one position on frame F and be in another position at frame F+1 while still looking at (and following) the same transform. I simply want to warp the camera from one orbit position to another orbit position.

    Now if I understand you correctly I just need to change the X and Y Axis values inside the FreeLook camera component. Changing the Y axis value works (I can set it to 0.5 to be level with the horizon for example) but changing the X axis value in the inspector doesn't work the same way: it always instantly reverts to zero. In other words the Y value is an absolute value from 0 (bottom) to 1 (top) but the X value seems to be an offset (in degrees) relative to the current value.

    Just to be clear: manually entering a value of 90 in the Axis X makes the camera instantly rotate by 90 degrees (laterally) from its current orbit, and the value instantly resets to 0 at the same time.



    So my question is: Given a position in space, how can I deduce the proper values to input in the X and Y axis in order to warp the camera to the desired position?
     
  4. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    The X value reverts to 0 because you're in SimpleFollow binding mode. In that mode, the X axis angle value is relative to the camera-target axis, so once the camera goes there the value must become zero.

    So your problem now is: how to compute the appropriate axis value, given the current camera position and the approximate desired position. That's just a little geometry. If you're using the very latest CM 2.2.8, there is a handy method in CinemachineOrbitalTransposer that does exactly what you want.

    First get an orbital transposer from the FreeLook, then ask it what value the X axis needs to be to get as close as possible to the point you want.
    Code (CSharp):
    1.     var orbital = freeLook.GetRig(1).GetCinemachineComponent<CinemachineOrbitalTransposer>();
    2.     float axisValue = orbital.GetAxisClosestValue(myTargetLocation, Vector3.up);
    3.     freeLook.m_XAxis.Value = axisValue;
    4.  
    If you're not using CM 2.2.8, you can just copy the code and adapt the implementation to your needs.
     
    Shorely and Seith like this.