Search Unity

Cinemachine Freelook Recenternow() Not Working

Discussion in 'Cinemachine' started by Windroid, Apr 11, 2019.

  1. Windroid

    Windroid

    Joined:
    Nov 28, 2017
    Posts:
    10
    I have a cinemachine freelook camera, I can recenter the camera by setting the "Recenter To Target Heading" properties in the Inspector, It works fine.

    But I want to manually recenter the camera by script instead of waiting the wait time.
    And I found out there's a AxisState.Recentering.RecenterNow() method in the cinemachine freelook API,It should recenter the camera when I call the method if I haven't misunderstood it.

    So I set the Wait Time to 10 and Recentering Time to 2 under the "Recenter To Target Heading" properties in the Inspector.
    And I tried to run these...
    Code (CSharp):
    1.  
    2.         playerFreeLookVCam.m_YAxisRecentering.RecenterNow();
    3.         playerFreeLookVCam.m_RecenterToTargetHeading.RecenterNow();
    4.         playerFreeLookVCam.m_XAxis.m_Recentering.RecenterNow();
    5.         playerFreeLookVCam.m_YAxis.m_Recentering.RecenterNow();
    6.  
    None of them did anything, also the camera still recentered itself after 10 seconds...

    So, how exactly is RecenterNow() works?
    Also is there any way I can recenter the freelook camera without the camera auto recenter itself after wait time?
    (Without directly edit the CinemachineFreeLook.m_XAxis and m_XAxis field)
     
    Last edited: Apr 11, 2019
  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    Yes, RecenterNow is broken in the FreeLook. It's a bug, fixed for the upcoming CM release.
    Then, this code should work:
    Code (CSharp):
    1. playerFreeLookVCam.m_YAxisRecentering.RecenterNow();
    2. playerFreeLookVCam.m_RecenterToTargetHeading.RecenterNow();
    To instantly reset, do this:
    Code (CSharp):
    1. playerFreeLookVCam.m_XAxis.Value = 0;
    2. playerFreeLookVCam.m_YAxis.Value = 0.5f;
     
  3. Windroid

    Windroid

    Joined:
    Nov 28, 2017
    Posts:
    10
    That's good to know.
    I'll wait for the update then.
     
  4. Malaussene

    Malaussene

    Joined:
    Feb 14, 2017
    Posts:
    17
    I'm using 2.3.4 and looks like RecenterNow() still doesn't work. Any update on this?
     
  5. j-swan

    j-swan

    Joined:
    Oct 21, 2013
    Posts:
    19
    Yeah doesn't work for me either
     
  6. giantdoor

    giantdoor

    Joined:
    Sep 11, 2018
    Posts:
    52
    Still not working in 2.3.4, in which release is/was it supposed to be fixed? or will it be 2.4.0?
    Sorry for resurrecting a topic that old, but we're also looking for a way to reset a FreeLook camera to the place it's supposed to be (e.g. warp it), but the heading is really a problem.
     
  7. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    2.4.0 is available now in preview, you can use that.
    What is the binding mode of the FreeLook you're trying to reposition?
     
  8. giantdoor

    giantdoor

    Joined:
    Sep 11, 2018
    Posts:
    52
    Cattura.PNG
    Follow and LookAt properties are populated at start.
    Also, as noted by Windroid before, I can recenter the camera to the right position by enabling the recenter to target heading in the inspector but **not** by code :S
     
  9. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    Does it recenter when you set freeLook.m_XAxis.Value = 0 ?
     
  10. giantdoor

    giantdoor

    Joined:
    Sep 11, 2018
    Posts:
    52
    Nop, makes no difference, at the moment, the only way to bring the camera where I want it to be is to manually check and uncheck the RecenterTargetHeading.enabled in the inspector.

    Could it be a conflict with the standby update set to Never instead?
     
    Last edited: Nov 23, 2019
  11. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    Very strange. What Recenter does is to gradually bring m_XAxis.Value to 0. That's the result you want. So you should be able to set it to 0 by code. Can you put together a small test project that demonstrates this problem?
     
  12. giantdoor

    giantdoor

    Joined:
    Sep 11, 2018
    Posts:
    52
    The thing is, I want to teleport the vCam to the correct position before starting the transition to it, it just doesn't teleport to the right position.
    A smaller project is sadly very hard to put together as I'm not sure how much of the code I can strip away without making it unplayable and therefore impossible to replicate the problem :( Any other viable option you would be open to, to have a look at it?
     
  13. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    Oh, so it's not that setting Value to 0 fails, it's just not what you want to do.
    Maybe I misunderstood the original problem.
    Is it the case that you have recentering disabled by default, but that you want to exceptionally enable it after the teleport? So you call RecenterNow() while recentering is disabled and it doesn't do anything?
     
  14. giantdoor

    giantdoor

    Joined:
    Sep 11, 2018
    Posts:
    52
    If I could only upload a video (like, less than 3MB .mp4) it would be much easier. Anyway, Here's the two states i find myself transitioning between:
    1.PNG
    the selected transform at the center of the screenshot is the GroupTarget transform, so far so good, the camera is heading in the right dierection.
    2.PNG
    but when it transition to to the other one (which has the same exact setup) and the target group changes heading direction, the new camera is suddenly heading to a completely random direction.
    Capture.PNG
    this is the setup of both cameras
    Code (CSharp):
    1. c.groupCamera.Priority = 1; // (all other cameras are set to 0 in the lines before)
    2. c.groupCamera.m_StandbyUpdate = CinemachineVirtualCameraBase.StandbyUpdateMode.Always;
    3. c.groupCamera.m_RecenterToTargetHeading.RecenterNow();
    4. c.groupCamera.m_StandbyUpdate = CinemachineVirtualCameraBase.StandbyUpdateMode.Never;
     
  15. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    From the inspector screenshot I can see that Recentering is not enabled.
    What RecenterNow() does is to bypass the recentering wait time by setting the countdown to zero. If recentering is disabled that will result in nothing happening. At the same time as calling RecenterNow() you have to also set
    c.groupCamera.m_RecenterToTargetHeading.m_Enabled = true;
    . You can set it to false again once the recentering time has relapsed.

    Also, if the vcam is not live, recentering won't happen if StanbyUpdate is Never. I see that you set it temporarily to Always, but is has to stay on Always until the recentering is finished. So, similarly, set it back to Never after the recentering time has elapsed.

    However, this question comes to mind: if the vcam isn't live, why do you want it to recenter gradually? Just set the Value to 0.
     
    Last edited: Nov 28, 2019
  16. giantdoor

    giantdoor

    Joined:
    Sep 11, 2018
    Posts:
    52
    You mean like this?
    Code (CSharp):
    1. c.groupCamera.m_StandbyUpdate = CinemachineVirtualCameraBase.StandbyUpdateMode.Always;
    2. c.groupCamera.m_RecenterToTargetHeading.m_enabled = true;
    3. c.groupCamera.m_RecenterToTargetHeading.RecenterNow();
    4. c.groupCamera.m_RecenterToTargetHeading.m_enabled = false;
    5. c.groupCamera.m_StandbyUpdate = CinemachineVirtualCameraBase.StandbyUpdateMode.Never;
    Or do I have to also set the xaxis to 0?
    Also, do I have to wait a frame, or should it happen instantly? Cause this doesn't seem to work either :(
     
    Last edited: Nov 28, 2019
  17. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    That code will do nothing.

    For immediate instantaneous recentering, replace all that code by this single line
    c.groupCamera.m_XAxis.Value = 0;

    I think that's what you want, since you have recentering time set to 0 in your inspector.

    Is that what you want to happen, or to you want the recentering to occur gradually over time? Your earlier inspector showed nonzero recentering times, so I'm confused about what you're trying to do.
     
  18. giantdoor

    giantdoor

    Joined:
    Sep 11, 2018
    Posts:
    52
    Already tried, that doesnt work :(
    And I have to keep the recenterToHeading off, apart from that frame when in need to reposition the camera.
    (I'm super sorry, but please be aware I'm incredibly grateful for the passion and dedication you're putting into helping us <3)
     
  19. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    Please answer my question. What do you want to happen?
     
  20. giantdoor

    giantdoor

    Joined:
    Sep 11, 2018
    Posts:
    52
    ok:

    Starting situation:
    * vCam1 is live, correctly heading the same way that the TargetGroup is heading.
    * vCam2 is not updating in standby heading wherever

    Then:
    * TargetGroup rotation is changed.
    * vCam2 goes live -> here I need vCam2 to teleport in the correct position so that it matches the new rotation of the TargetGroup before i start the blend
    * i initiate the blend between the two cameras

    I can't have RecenterToTargetHedaing on apart from the frame in which I'm recentering vCam2

    I hope that"s a bit more clear ^^"
     
  21. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    Yes it is. Thank you :D

    Can you elaborate a little bit here:
    When you say "vCam2 goes live", and "i initiate the blend between the two cameras", how does that happen?
     
  22. giantdoor

    giantdoor

    Joined:
    Sep 11, 2018
    Posts:
    52
    By setting the vCam1 priotity to 0 and the vCam2 one to 1. Isn't that how this is upposed to work? :O
     
  23. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    yes, that's the right way, but I just wanted to make sure I understood what you were doing.

    Can you try this:
    1. set the group's heading to the new value
    2. set vcam2.m_XAxis.Value = 0;
    3. set vcam2.PreviousStateIsValid = false;
    4. set vcam1.m_Priority = 0;
    5. set vcam2.m_Priority = 1;
    let me know how that goes
     
    Last edited: Nov 28, 2019
  24. giantdoor

    giantdoor

    Joined:
    Sep 11, 2018
    Posts:
    52
    Doesn't seem to work either :(
    Do I have to set the update method to Always as well?
     
    Last edited: Nov 28, 2019
  25. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    Does vcam2 have InheritPosition checked?

    upload_2019-11-28_10-9-25.png

    If so, turn it off and try again.
     
  26. giantdoor

    giantdoor

    Joined:
    Sep 11, 2018
    Posts:
    52
    nope it looks exactly like in the screenshot
     
  27. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    The screenshot is hiding that value. Can you open the "Transitions" section and check?
     
  28. giantdoor

    giantdoor

    Joined:
    Sep 11, 2018
    Posts:
    52
    I did ^^"
     

    Attached Files:

  29. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    ok thanks.
    It's a little puzzling that the code I sent isn't working for you. Trying to think why...
    Could it have something to do with the group heading?
    Are you sure it's being set correctly?
    How are you setting it?
    Can you post a picture of the group's inspector?
     
  30. giantdoor

    giantdoor

    Joined:
    Sep 11, 2018
    Posts:
    52
    I'm setting up a small project to recreate the problem, with some very basic and easy to read setup, which is the best way to provide it to you?
     
  31. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    If you can export as a unitypackage, that's the best. Otherwise you can zip up the project (delete the Library folder first) and DM it to me
     
  32. giantdoor

    giantdoor

    Joined:
    Sep 11, 2018
    Posts:
    52
  33. spiritworld

    spiritworld

    Joined:
    Nov 26, 2014
    Posts:
    29
    Thanks this discussion helped me. I don't want to enable recentering (I dislike that feature in games) but when my character climbs ladders I need to recenter behind him in case the player started climbing looking towards the camera.

    So here's what I did:

    Code (CSharp):
    1.  
    2. public IEnumerator ResetCamera() {
    3.     camController.m_RecenterToTargetHeading.m_enabled = true;
    4.    camController.m_YAxisRecentering.RecenterNow();
    5.    camController.m_RecenterToTargetHeading.RecenterNow();
    6.    yield return new WaitForSeconds(camController.m_RecenterToTargetHeading.m_RecenteringTime);
    7.    camController.m_RecenterToTargetHeading.m_enabled = false;
    8. }
    9.  
    Works fine except the coroutine exits at 2/3 of the rotation, apparently m_RecenteringTime is not enough so gonna add some extra delay there.
     
    Skaster87 likes this.
  34. orzech123

    orzech123

    Joined:
    Mar 12, 2018
    Posts:
    17
    And what happend then guys?
     
  35. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    Sorry, that was a long time ago. I don't remember the details. If you a specific question now, you can ask on a new thread :)
     
  36. NicolasSouza-NIckSDev

    NicolasSouza-NIckSDev

    Joined:
    Jun 9, 2017
    Posts:
    8
    with me on 2.8.2 still not working RecenterNow() and i realy need it.
    i try to set the value diretly on m_XAxis and m_YAxis but for some reasons if this is called on Start or somethign like it, the value is forced to 0 and then the next values passed to freelook.
    same way, i tryed to make a bool variable 'started' and on UPDATE if it´s not true, calls recentering, and turns 'started' to true.. and ...... nothing!
     
  37. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    This is probably because your FreeLook binding mode is SimpleFollowWithWorldUp. That mode has no concept of recentering. Try changing the binding mode to WorldSpace.
     
  38. Titutitech

    Titutitech

    Joined:
    Jan 17, 2014
    Posts:
    26
    Hi Gregoryl, is there a way to easily know when the re-centering has finished? As @spiritworld mentioned, m_RecenteringTime does not seem match with the time needed to recenter and if you stop rotations after m_RecenteringTime seconds, then the whole rotation is not completed (note that I am not using any delay).

    Reading the documentation it mentions that this time is the "Maximum angular speed of recentering. Will accelerate into and decelerate out of this" so it makes sense that this time does not match.
     
    Last edited: Feb 22, 2022
  39. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    You can poll axis.Value and compare it to the expected recentered value.
     
  40. Titutitech

    Titutitech

    Joined:
    Jan 17, 2014
    Posts:
    26
    Thanks,

    I have implemented the check as follows:

    Code (CSharp):
    1.         private bool HasRecenteringConverged()
    2.         {
    3.             float x = cinemachineCamera.m_XAxis.Value;
    4.             float y = cinemachineCamera.Follow.rotation.eulerAngles.y;
    5.  
    6.             // Wrap angles around 0 and 360.
    7.             x = x % 360;
    8.             y = y % 360;
    9.             if (x < 0) x += 360;
    10.             if (y < 0) y += 360;
    11.  
    12.             // Compare the 2 angles.
    13.             float angle = Mathf.Abs(x - y);
    14.  
    15.             // Return if the difference between them is 1.
    16.             // NOTE: That we also need to compare with 360-1.
    17.             return (angle < 1f || angle > 359f);
    18.         }
    • Our start setup is with xaxis = 0.
    • Had to wrap angles to make sure we do not compare wrongly things like -1 != 359
    • Due to the code not accurately finishing at the exact 0 value, I added an angle threshold of 1º

    Does all this make sense? Or am I overdoing?

    Now, I am a bit worried that if the camera due to obstacle avoidance or other reasons does not converge for a while. Is this possible? Should I add some sort of max time to anyways consider the re-centering has finished?

    Thanks in advance!
     
  41. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    Your code looks good, assuming that your binding mode is WorldSpace.

    You don't need to worry about obstacle avoidance. That can move the vcam, but the axis value will still reflect that it's centered.
     
  42. Junior_Djjr

    Junior_Djjr

    Joined:
    Nov 3, 2017
    Posts:
    11
    I saw this thread from 2019 saying that it doesn't work but that it will be fixed soon, but for me (Unity 2021.2), it still doesn't work. Yes, the recentering is enabled; I'm using POV.

    I went to debug to understand the cause, and RecenterNow does just this:
    Code (CSharp):
    1. public void RecenterNow()
    2. {
    3.     mLastAxisInputTime = 0;
    4. }
    Then, DoRecentering does this:
    Code (CSharp):
    1. if (CinemachineCore.CurrentTime < (mLastAxisInputTime + m_WaitTime))
    2.     return;
    How this is going to work?? m_WaitTime is being added by 0.
    mLastAxisInputTime should be a very high number to make it work, not 0, or am I missing something here?

    I decided to do it this way:
    Code (CSharp):
    1.  
    2. characterPOV.m_HorizontalRecentering.DoRecentering(ref characterPOV.m_HorizontalAxis, -1.0f, characterPOV.FollowTarget.transform.rotation.eulerAngles.y);
    3. characterPOV.m_VerticalRecentering.DoRecentering(ref characterPOV.m_VerticalAxis, -1.0f, 0.0f);
    Note: < 0 for delta time is a special value checked internally to recenter ignoring the conditions, used natively.
    I used this for an immediate recenter, it was perfect.
     
  43. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    You are indeed misunderstanding. The recentering code works. That test is for an early-out: it's supposed to refrain from doing recentering unless it passes the test. Setting mLastAxisInputTime to 0 ensures that it fails the test, which is what's wanted in order to begin recentering.

    It works for me. I don't know why it's not working by default for you. What version of CM do you have? Check in the package manager.
     
  44. Junior_Djjr

    Junior_Djjr

    Joined:
    Nov 3, 2017
    Posts:
    11
    I'm using 2.8.4.

    Here is my settings:

    Tried with Wait time 10 and Recentering Time 1 too.
    It works if I wait until the time, but using RecenterNow there is no effect.

    Here, this condition is never true when I use RecenterNow. Is this really expected? Because the recenter code is just right after this condition, or when using RecenterNow Cinemachine does a different call?

    The condition only passes if I do NOT use RecenterNow, and wait for the time.

    Remembering that I already solved my specific problem, but I found this curious.
     
    Gregoryl likes this.
  45. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,730
    Indeed you are right. I was too hasty with my previous answer (and didn't actually test the right thing - brain fart). Thanks for pushing back.

    The code works provided that the recenter wait time is sufficiently low or current time is sufficiently large. For larger wait times, it indeed is unreliable. The correct code should be something like:
    Code (CSharp):
    1.             public void RecenterNow()
    2.             {
    3.                 mLastAxisInputTime = -m_WaitTime;
    4.             }
    We'll get a fix in asap.
     
    Last edited: Jul 5, 2022
    Junior_Djjr likes this.