Search Unity

Question Lock to target with spherical world movement.

Discussion in 'Cinemachine' started by MirzaBeig, Jan 1, 2023.

  1. MirzaBeig

    MirzaBeig

    Joined:
    Dec 27, 2014
    Posts:
    602
    I have a player controller that can walk over any surface, where the FreeLook camera position should follow the movement rather than remain relatively fixed and just look at the target.

    Unity v2021.3.16f1, Cinemachine 2.8.9.

    Here's what I mean:


    What I have, which works well with walking on spheres.

    The first part of the video is what I currently have Simple Follow With World Up, the second part (which I'm simulating by moving my mouse) is what I want to have. I can simulate the second part with Lock To Target On Assign, but this creates problems once the controller starts walking on curved surfaces.


    What I want, which doesn't work with walking on spheres.

    Using Simple Follow with World Up has other implications, in that I can't directly control the Y-axis value.


    upload_2023-1-1_17-38-21.png

    The reason I need to be able to set this value is that I have two cameras for the player: one for relatively slow (low FoV) and another for fast movement (higher FoV, pulled closer to the player: dolly zoom).


    When the player is moving fast I switch to the second camera, which needs to have the same rotation around the player, but the distance may be different from the dolly zoom, which is why I can't simply copy the position using the Inherit Position tick or else it ends up cutting between the two cams.


     
    Last edited: Jan 1, 2023
  2. gaborkb

    gaborkb

    Unity Technologies

    Joined:
    Nov 7, 2019
    Posts:
    856
    Have a look at our sample scene: SphericalSurfaceFollow. It shows how to setup a freelook that works on curved surfaces.

    The key step is to set CinemachineBrain's World Up Override to the Player's Transform.
     
  3. MirzaBeig

    MirzaBeig

    Joined:
    Dec 27, 2014
    Posts:
    602
    Thank you! But I've looked at that scene and the setup is identical in my first video: Simple Follow With World Up, which already works with curved and spherical surfaces (I have a component of the player assigned to the Brain's world up override there, too).

    I'm just not sure how to lock the camera's position to the target when it moves left-right of the camera.
    Here's a video showing the first setup again over a sphere along with the inspector.



    Here are the time stamps:

    0:00 - 0:21: I show the same setup from the first video I posted in my last post, which is a FreeLook camera that targets a component of the player that matches the rotation of the player at all times, including the up axis. The Brain also has this same transform as the override.

    0:21 - 0:29: I show that tracking over spheres works fine- again, not an issue! This is great, and I love how CM makes this easy, but I already had this working.

    0:29 - 0:39: This is where I show the problem I've been stuck on. The camera's position stays relatively the same as I hold the right-move key for the player, which is not what I want. It causes the player to essentially move in a circle around the camera rather than a straight line.

    0:39 - 0:59:
    This is what I want. The camera should move with the player even when moving left-right of the current orientation, and cause them to automatically move in a straight line in whichever direction he's already facing. The way I'm doing it in the video is by carefully adjusting my mouse as he moves.

    1:06 - 1:15: Here I show the same issue on a flat surface. Moving the player left-right will cause them to move in a circle around the camera, rather than in a straight line.

    1:15 - End: And here I show what I want again, which I do by moving the mouse as the player moves, which causes them to move in a straight(-ish, because my hand isn't so steady) line based on the direction they are already facing.

    Notice the issue I have with this is the same as what I described before- it's not that the player doesn't track over spheres correctly (it does), it's that the camera's position remains fixed and does not follow the movement as you get with a Lock To Target On Assign. If I do use Lock To Target On Assign, the camera has issues as it goes around the sphere near the poles and such.

    Another video showing Lock To Target On Assign (the second setup from my first post) and the problem it has over the sphere.



    It works great on flat surface, and has the behaviour I want, but not on curved surfaces. And unlike Simple Follow With World Up, I'll be able to read/write the X axis directly which I also need. CM unfortunately comes with the burden that its components are huge and difficult to manage, so I'm not really sure what to do here.



    This is a modified SphericalSurfaceFollow (smaller sphere) that shows the same issue with the existing setup (looping around the current camera position when moving left/right), and I still need to be able to write to the X axis input for my own controller, which I can't do with this binding mode.
     
    gaborkb likes this.
  4. gaborkb

    gaborkb

    Unity Technologies

    Joined:
    Nov 7, 2019
    Posts:
    856
    This could be fixed by decoupling the player movement from the camera. I suppose your player movement controller depends on the Camera's orientation, probably the forward vector.
    When you want your player to move sideways in a straight line instead of a circle, you could make your player movement controller depend on the player's forward direction.
     
  5. MirzaBeig

    MirzaBeig

    Joined:
    Dec 27, 2014
    Posts:
    602
    This wouldn't work, because the input -> move direction should always be translated based on the camera view.
    Right is defined by the camera, and player input has no meaning without a reference.

    What would happen if the player rotated the camera while the avatar moved? I still need to define right as the right of the camera, which is what correctly happens with the Lock To Target On Assign binding mode, but not with Simple Follow With World Up

    Perhaps I misunderstood what you meant?

    Problem 1: Camera should move with the player right-left, not simply look at them.

    Simple Follow With World Up works with curved surfaces, but doesn't have this behaviour.
    Vice-versa for Lock To Target On Assign.

    upload_2023-1-4_14-46-38.png

    It also doesn't solve the problem of the FreeLook camera not having an X input axis I can modify. I still need to also blend between the slow and fast move vcams.

    Problem 2: Cameras should match rotation around player-avatar exactly, and at all times.

    upload_2023-1-4_14-48-50.png

    In this image I need the two to have matching rotation around the player to prevent awkward cuts or jumps when transitioning. This is because one of them has higher FoV and the actual camera in the scene needs to pull in closer to retain the same relative distance to the player, which is why I activate that second vcam with those settings.

    upload_2023-1-4_14-54-32.png

    FoV 40:
    upload_2023-1-4_14-56-11.png
    FoV 60:
    upload_2023-1-4_14-56-19.png
     
  6. gaborkb

    gaborkb

    Unity Technologies

    Joined:
    Nov 7, 2019
    Posts:
    856
    What I meant is that there are several ways to process input:
    • Relative to camera
      Camera's transform's forward vector defines the forward direction. For example, when you push W on your keyboard, the player moves in the direction of the camera's forward vector; this could also induce a rotation in the player's transform to make it face towards the camera's forward direction.
    • Relative to the player
      Player's transform's forward vector defines the forward direction. For example, when you push W on your keyboard, the player moves towards its forward direction. No rotation happens to the player.
    • Relative to world
      Forward is always North in your world, does not matter how the player is oriented or how the camera is oriented. This could also induce a rotation in the player's transform to make it face towards North.
    • ...

    I feel like you could solve your issue by having 2 separate cameras on flat surfaces and on curves surfaces (maybe +1 for the fast camera version).
    Then you only need to solve the blending issue you mention.

    Could you clarify why the blends are not satisfactory?
    It is possible that instead of using one of the built-in transition hints (such as InheritPosition), we could come up with one that fits your needs. For example, a script that rotates the inactive camera before activation to the correct rotation around the player (possibly using ForceCameraPosition()).
     
  7. MirzaBeig

    MirzaBeig

    Joined:
    Dec 27, 2014
    Posts:
    602
    Ah, I think see where my confusion was. Yes, I understood this, but it's essentially suggesting a change to the player controller to something non-intuitive for the kind of game I'm working on.

    The camera should be the reference for input -> move direction.

    As per your description of 'Relative to camera': Yes, the forward direction is stored based on the input relative to the camera orientation, and the player moves and rotates to face that direction.

    upload_2023-1-5_20-7-7.png

    upload_2023-1-5_20-6-31.png

    One of the games I use as a reference (I believe also made with Unity) has the Lock To Target On Assign-type controller and camera setup, although I can't be sure they're using Cinemachine, and they certainly don't have curved surfaces or surface-based local up directions/gravity (it's a flat surface, world up-only platformer).

    Otherwise, I could use that binding mode without issues as I was prior to adding in the gravity shifting mechanic. I switched over to Simple Follow With World Up and the camera Up override after noticing the issues.

    Is there no way in Cinemachine to have the Lock To Target On Assign-type behaviour work with curved surfaces?

    I thought about doing this, but it would introduce some problems:

    1. Switching between the two types of binding mode cameras may disorient the player. It's perhaps better to remain consistent.

    2. It's not just curved surfaces, the player may walk up-side down or side ways on flat surfaces. Basically, the (target) up orientation of the player can be anything at any given time. How would this be resolved using CM and when should I switch between world and lock to target?



    Here's what I'm currently doing to match the cameras as best I can.

    upload_2023-1-5_20-11-48.png

    upload_2023-1-5_20-11-56.png

    This gets me most of the way, but introduces issues with movement because of desyncs in rotation, which you'll notice in the video in the top scene view.



    Here's a shot from one such instance.

    upload_2023-1-5_20-15-59.png

    While the game view won't clearly reveal what this is like, it causes the player to feel like they've momentarily lost control over the character while the camera completes the blend since the forward is based on the camera. It basically makes controlling the player and camera feel really 'janky', and there are still some sudden cuts.

    Syncing the camera rotations as per their Y and X axis inputs would resolve the issue, but it's not possible to do that with the X axis value directly using the Simple Follow binding mode.
     
  8. gaborkb

    gaborkb

    Unity Technologies

    Joined:
    Nov 7, 2019
    Posts:
    856
    Have you tried Lock To Target with World Up? That should work on curved and flat surfaces just like Simple Follow with World Up, but with the behaviour of Lock To Target.

    Note, that if you have damping on your camera this will affect the direction of the input, since your camera is lagging a bit behind. This will add some amount (depends on the damping amount) of curve to the player's path.

    Copying the input axis values is a smart way to make the freelooks align. ;)

    You could also use
    Code (CSharp):
    1. freeLook1.ForceCameraPosition(freeLook2.transform.position, freeLook2.transform.rotation);
    Thank you for providing so much information about your issue. I think you are very close to having the behaviour you like. There may be some minor things to fix here and there.
    If you can send me a repro project, then I will take a look-see to find what works best in your case.
     
    Last edited: Jan 6, 2023
    MirzaBeig likes this.
  9. MirzaBeig

    MirzaBeig

    Joined:
    Dec 27, 2014
    Posts:
    602
    I appreciate the help so far :)

    Lock To Target With World Up causes the following issue.



    In the video you'll see me start with Simple Follow With World Up, then quickly switch to Lock To Target With World Up. The player just ends up spinning. If I enable a new debug option for the camera target which only copies the player's local up transform, then I generally get things working on curved surfaces, but spheres and certain angles are tricky (gimble lock?).

    upload_2023-1-6_7-33-28.png

    I can mitigate some of this by also forcing a consistent forward with the local up, but that means only curved surfaces on a fixed axis (like a cylinder) will work.



    This seems to cause cuts and jitters in the camera, as the position is forced and I only want the axis rotation itself.

    This project scenario is definitely something that would benefit from a direct look, I think.
    I'll cut it down some and get you a download link to your inbox. Thanks!
     
    Last edited: Jan 6, 2023
    gaborkb likes this.
  10. MirzaBeig

    MirzaBeig

    Joined:
    Dec 27, 2014
    Posts:
    602
    Just sent in the basic project to your inbox, @gaborkb.
    Hope we can figure this out! Thanks so much.
     
    gaborkb likes this.
  11. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,711
    If I understand correctly, you want LockToTarget behaviour, but with the character forward decoupled from the camera direction.

    I think you can achieve this by adjusting your player to have this kind of structure:
    • Player Root: capsule collider, player controller script. No visible geometry.
      • Player Geometry: the visible geometry
    Your player controller script should manage the Player Root's up to match it to the current surface, but it should rotate the Player Geometry to face the direction of motion (not the Player Root).

    Set up your two FreeLooks to track the Player Root, with LockToTarget Binding Mode.
    Set InheritPosition on each FreeLook. Adjust damping as you like it.
    Blending works automatically, no special code required.

    Use Player Root as the Brain's World Up Override.

    I've attached a quick mockup of this. WASD to move, Shift to switch cameras. Let me know if this is what you're looking for.
     

    Attached Files:

    MirzaBeig likes this.
  12. MirzaBeig

    MirzaBeig

    Joined:
    Dec 27, 2014
    Posts:
    602
    Thank you, I'll have a look at this! I was swept up into some other stuff.