Search Unity

Sync up noise for all three rigs of FreeLookCamera?

Discussion in 'Cinemachine' started by AhSai, May 20, 2019.

  1. AhSai

    AhSai

    Joined:
    Jun 25, 2017
    Posts:
    129
    Is there way to sync up the noise for all three rigs of a FreeLookCamera? Currently each rig has its own seed, even if they have the same noise setting, it will create choppiness when switching between rigs. Is there way to work around this?
     
  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    The seed is encoded in CinemachineBasicMultiChannelPerlin.mNoiseOffsets. You have to set those to the same thing in all three rigs. Unfortunately, that member is private. Perhaps you could cheat and do it via reflection, or just manually edit it in the streamed file?
     
  3. AhSai

    AhSai

    Joined:
    Jun 25, 2017
    Posts:
    129
    I manually hard coded the mNoiseOffsets to be Vector3.zero and commented out the code for reseed. However, it doesn't seem to remove the choppiness when switching between rigs.
     
  4. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    Can you export a simple project that shows this issue and send it to me?
     
  5. AhSai

    AhSai

    Joined:
    Jun 25, 2017
    Posts:
    129
    I have attached a simple scene to show the issue. All three rigs have same height, radius, and noise settings. The script is a modified version of CinemachineBasicMultiChannelPerlin. All I did was hard coding mNoiseOffsets = Vector3.zero in the Initialize() method and commenting out the Reseed().
     

    Attached Files:

  6. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,728
    Very interesting! There are a couple of issues going on here.
    1. I misled you (sorry!). It's not enough to set the noise offset to zero because the inactive rigs are not advanced, leading to loss of synchronization
    2. Your usage of FreeLook with DoNothing in the Aim is unusual, and it turns out there's a bug when it's used that way: the rigs' aims never get properly initialized, so you're getting a rotational glitch there too.
    There are 2 fixes.

    1. Use this custom noise script instead of your modified CinemachineBasicMultiChannelPerlin.cs. Just drop it in your assets and it will become visible to the vcam inspector as BasicMultiChannelPerlinNoSeed:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Serialization;
    3.  
    4. namespace Cinemachine
    5. {
    6.     /// <summary>
    7.     /// As a part of the Cinemachine Pipeline implementing the Noise stage, this
    8.     /// component adds Perlin Noise to the Camera state, in the Correction
    9.     /// channel of the CameraState.
    10.     ///
    11.     /// The noise is created by using a predefined noise profile asset.  This defines the
    12.     /// shape of the noise over time.  You can scale this in amplitude or in time, to produce
    13.     /// a large family of different noises using the same profile.
    14.     /// </summary>
    15.     /// <seealso cref="NoiseSettings"/>
    16.     [DocumentationSorting(DocumentationSortingAttribute.Level.UserRef)]
    17.     [AddComponentMenu("")] // Don't display in add component menu
    18.     [SaveDuringPlay]
    19.     public class CinemachineBasicMultiChannelPerlinNoSeed : CinemachineComponentBase
    20.     {
    21.         /// <summary>
    22.         /// Serialized property for referencing a NoiseSettings asset
    23.         /// </summary>
    24.         [Tooltip("The asset containing the Noise Profile.  Define the frequencies and amplitudes there to make a characteristic noise profile.  Make your own or just use one of the many presets.")]
    25.         [FormerlySerializedAs("m_Definition")]
    26.         [NoiseSettingsProperty]
    27.         public NoiseSettings m_NoiseProfile;
    28.  
    29.         /// <summary>
    30.         /// Gain to apply to the amplitudes defined in the settings asset.
    31.         /// </summary>
    32.         [Tooltip("Gain to apply to the amplitudes defined in the NoiseSettings asset.  1 is normal.  Setting this to 0 completely mutes the noise.")]
    33.         public float m_AmplitudeGain = 1f;
    34.  
    35.         /// <summary>
    36.         /// Scale factor to apply to the frequencies defined in the settings asset.
    37.         /// </summary>
    38.         [Tooltip("Scale factor to apply to the frequencies defined in the NoiseSettings asset.  1 is normal.  Larger magnitudes will make the noise shake more rapidly.")]
    39.         public float m_FrequencyGain = 1f;
    40.  
    41.         /// <summary>True if the component is valid, i.e. it has a noise definition and is enabled.</summary>
    42.         public override bool IsValid { get { return enabled && m_NoiseProfile != null; } }
    43.  
    44.         /// <summary>Get the Cinemachine Pipeline stage that this component implements.
    45.         /// Always returns the Noise stage</summary>
    46.         public override CinemachineCore.Stage Stage { get { return CinemachineCore.Stage.Noise; } }
    47.  
    48.         /// <summary>Applies noise to the Correction channel of the CameraState if the
    49.         /// delta time is greater than 0.  Otherwise, does nothing.</summary>
    50.         /// <param name="curState">The current camera state</param>
    51.         /// <param name="deltaTime">How much to advance the perlin noise generator.
    52.         /// Noise is only applied if this value is greater than or equal to 0</param>
    53.         public override void MutateCameraState(ref CameraState curState, float deltaTime)
    54.         {
    55.             if (!IsValid || deltaTime < 0)
    56.                 return;
    57.  
    58.             float noiseTime = Time.timeSinceLevelLoad * m_FrequencyGain;
    59.             curState.PositionCorrection += curState.CorrectedOrientation * NoiseSettings.GetCombinedFilterResults(
    60.                     m_NoiseProfile.PositionNoise, noiseTime, Vector3.zero) * m_AmplitudeGain;
    61.             Quaternion rotNoise = Quaternion.Euler(NoiseSettings.GetCombinedFilterResults(
    62.                     m_NoiseProfile.OrientationNoise, noiseTime, Vector3.zero) * m_AmplitudeGain);
    63.             curState.OrientationCorrection = curState.OrientationCorrection * rotNoise;
    64.         }
    65.     }
    66. }
    67.  
    2. If you are going to use DoNothing in the rigs' Aim, then you'll also need to add this little script to the FreeLook as a workaround for the FreeLook initialization bug (if you have a nontrivial Aim, then you don't need to do this):
    Code (CSharp):
    1. using UnityEngine;
    2. using Cinemachine;
    3.  
    4. public class InitFreeLookRigs : MonoBehaviour
    5. {
    6.     void Start()
    7.     {
    8.         var freeLook = GetComponent<CinemachineFreeLook>();
    9.         if (freeLook != null)
    10.         {
    11.             for (int i = 0; i < 3; ++i)
    12.             {
    13.                 freeLook.GetRig(i).transform.localPosition = Vector3.zero;
    14.                 freeLook.GetRig(i).transform.localRotation = Quaternion.identity;
    15.             }
    16.         }
    17.  
    18.     }
    19. }
    Let me know if this fixes your issue, and thanks for bringing it to our attention!
     
  7. AhSai

    AhSai

    Joined:
    Jun 25, 2017
    Posts:
    129
    Thanks a lot for the solution. It works perfectly!!
    One thing to note to whoever also need this fix is that Standby Update has to be set to "Always" in order for this to work.
     
  8. AhSai

    AhSai

    Joined:
    Jun 25, 2017
    Posts:
    129
    It is very weird. When I am trying to make a prefab of a freelookcamera with the NoSeed noise attached to it, it gives me this error:
    You are trying to replace or create a Prefab from the instance 'cm' that contains the script 'CinemachineBasicMultiChannelPerlinNoSeed', which does not derive from MonoBehaviour. This is not allowed.

    I also notice that the noise property with NoSeed cannot be saved to the scene in my current project. I works fine with a brand new project. One thing to note is that the SaveDuringPlay function has also stopped working in my current project, and I have not yet find out the reason for it.
     
  9. AhSai

    AhSai

    Joined:
    Jun 25, 2017
    Posts:
    129
    Re-importing the script seems to fix the problem, but would like to know what caused this problem in the first place.