Search Unity

  1. Get all the Unite Berlin 2018 news on the blog.
    Dismiss Notice
  2. Unity 2018.2 has arrived! Read about it here.
    Dismiss Notice
  3. We're looking for your feedback on the platforms you use and how you use them. Let us know!
    Dismiss Notice
  4. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  5. Improve your Unity skills with a certified instructor in a private, interactive classroom. Learn more.
    Dismiss Notice
  6. ARCore is out of developer preview! Read about it here.
    Dismiss Notice
  7. Magic Leap’s Lumin SDK Technical Preview for Unity lets you get started creating content for Magic Leap One™. Find more information on our blog!
    Dismiss Notice
  8. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

Making Cinemachine play nice with Rewired

Discussion in 'Cinemachine' started by Murgilod, Feb 14, 2018.

  1. Murgilod

    Murgilod

    Joined:
    Nov 12, 2013
    Posts:
    3,318
    Alright, I've finally encountered a problem I can't even begin to figure out how to solve.

    I use Rewired to handle all my player input because the Unity input system becomes quickly cumbersome when it comes to supporting multiple platforms and controller types. Unfortunately, I have no idea how to make it so that the Cinemachine Free Look component uses Rewired instead of the base input system.

    I started poking around in the code to see if I could code around this, but quickly found myself lost as I began to navigate deeper and deeper into the various scripts. Eventually I found what I think I need to start changing, but I have no idea how as my scripting knowledge is woefully at a beginner-to-intermediate level, and the concepts at play are a bit beyond me. This is what I found in CinemachineCore.cs:

    Code (CSharp):
    1.         /// <summary>Delegate for overriding Unity's default input system.  Returns the value
    2.         /// of the named axis.</summary>
    3.         public delegate float AxisInputDelegate(string axisName);
    4.  
    5.         /// <summary>Delegate for overriding Unity's default input system.
    6.         /// If you set this, then your delegate will be called instead of
    7.         /// System.Input.GetAxis(axisName) whenever in-game user input is needed.</summary>
    8.         public static AxisInputDelegate GetInputAxis = UnityEngine.Input.GetAxis;
    It looks like this is what I need to start changing, but I have no idea how. Any help would be greatly appreciated.

    edit: While I'm here, is there a guide to making custom camera behaviours? I'd really like a proper 360 camera orbit like in a 6 DOF third person game and the Free Look camera just isn't cutting the mustard for a few reasons. It'd be a great bonus if I could have it work with the camera collision system as well.
     
    Last edited: Feb 14, 2018
    thatscraigz likes this.
  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    1,412
    Code (CSharp):
    1.         class MyInputHandler
    2.         {
    3.             [RuntimeInitializeOnLoadMethod]
    4.             static void InitializeModule()
    5.             {
    6.                 CinemachineCore.GetInputAxis = GetInput;
    7.             }
    8.  
    9.             static float GetInput(string name)
    10.             {
    11.                 // Do something here to parse name for Rewired
    12.                 // then call rewired and return the value
    13.                 return 0;
    14.             }
    15.         }
    16.  
     
  3. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    1,412
    There is no written guide, but I'd be happy to help. Can you give some details about the behaviour you're looking for?
     
  4. Murgilod

    Murgilod

    Joined:
    Nov 12, 2013
    Posts:
    3,318
    Just so I don't completely break anything, I should just stick this in its own script, correct?

    Please excuse my lack of editing, I don't have OBS configured to produce videos in a format Vegas can accept and didn't want to deal with the hassle of FFMPEG.



    As you can see, the camera is simple as can be. It's basically just a free orbit around the model with no clamping on the x or y value. The code is as follows, if you need. It's just a pared down version of this script from the wiki.

    Code (CSharp):
    1. using UnityEngine;
    2. using Rewired;
    3. using System.Collections;
    4.  
    5. public class MouseOrbitImproved : MonoBehaviour
    6. {
    7.  
    8.     public Transform target;
    9.     public float distance = 5.0f;
    10.     public float xSpeed = 120.0f;
    11.     public float ySpeed = 120.0f;
    12.  
    13.     float x = 0.0f;
    14.     float y = 0.0f;
    15.  
    16.     Player player;
    17.  
    18.     // Use this for initialization
    19.     void Start()
    20.     {
    21.         player = ReInput.players.GetPlayer(0);
    22.  
    23.         Vector3 angles = transform.eulerAngles;
    24.         x = angles.y;
    25.         y = angles.x;
    26.     }
    27.  
    28.     void LateUpdate()
    29.     {
    30.         if (target)
    31.         {
    32.             x += player.GetAxis("CameraHorizontal") * xSpeed * distance * Time.deltaTime;
    33.             y -= player.GetAxis("CameraVertical") * ySpeed * Time.deltaTime;
    34.  
    35.             Quaternion rotation = Quaternion.Euler(y, x, 0);
    36.  
    37.             Vector3 negDistance = new Vector3(0.0f, 0.0f, -distance);
    38.             Vector3 position = rotation * negDistance + target.position;
    39.  
    40.             transform.rotation = rotation;
    41.             transform.position = position;
    42.         }
    43.     }
    44. }
     
  5. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    1,412
    Not necessary to do that, since it doesn't derive from ScriptableObject. You can just put it anywhere.

    The simplest way to turn this into a vcam is to add the script as a behaviour to an ordinary vcam, with "Do Nothing" in both Aim and Body. That turns off all the procedural stuff, allowing your script to drive the vcam's transform.
     
  6. Murgilod

    Murgilod

    Joined:
    Nov 12, 2013
    Posts:
    3,318
    Doesn't this invalidate the functionality of the cinemachine collider though?
     
  7. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    1,412
    Actually not. Collider will still work. Amazing, isn't it :)
     
    juicefoozle likes this.
  8. Murgilod

    Murgilod

    Joined:
    Nov 12, 2013
    Posts:
    3,318
    Oh, perfect! I accidentally forgot to set "avoid obstacles" which was causing me the problem! Thanks for all your help!
     
  9. StarFluke

    StarFluke

    Joined:
    Jan 19, 2013
    Posts:
    22
    Awesome Input Catcher! err... "Handler." However, it does not seem to be abiding by the speed laws I set up for X axis and Y axis... I have to add my own speed laws into the Handler class. That does not seem very DRY :oops:.
     
  10. canis

    canis

    Joined:
    Oct 25, 2013
    Posts:
    33
    Thanks for Gregoryl.
    for those who may still looking into this issue. here is my implementation.

    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using UnityEngine;
    4. using Cinemachine;
    5. using Rewired;
    6.  
    7. [RequireComponent(typeof(CinemachineFreeLook))]
    8. public class CinemachineRewiredFreeLook : MonoBehaviour
    9. {
    10.     [SerializeField] int m_PlayerId = 0;
    11.  
    12.     private void Reset() { OnValidate(); }
    13.     private void OnValidate()
    14.     {
    15.         if (Application.isPlaying && ReInput.isReady)
    16.             InitializeInput();
    17.     }
    18.  
    19.     private IEnumerator Start()
    20.     {
    21.         yield return new WaitUntil(() => ReInput.isReady);
    22.         InitializeInput();
    23.     }
    24.  
    25.     private void InitializeInput()
    26.     {
    27.         if (ReInput.isReady)
    28.         {
    29.             Player input = ReInput.players.GetPlayer(m_PlayerId);
    30.             CinemachineCore.GetInputAxis = input.GetAxis;
    31.         }
    32.     }
    33. }
    34.  
    35. public class CinemachineRewiredOverrider
    36. {
    37.     [RuntimeInitializeOnLoadMethod]
    38.     private static void InitializeSystemPlayer()
    39.     {
    40.         CinemachineCore.GetInputAxis = ReInput.players.SystemPlayer.GetAxis;
    41.     }
    42. }
    43.  
    if you only have single player (playerId = 0) in your game. (common case ?)
    you can just create the the following script and put it into your project.
    without using the above over engineering script :)
    however the Cinemachine will ONLY listen to player 0.

    Code (CSharp):
    1. public class CinemachineRewiredOverrider
    2. {
    3.     [RuntimeInitializeOnLoadMethod]
    4.     private static void InitializeSystemPlayer()
    5.     {
    6.         CinemachineCore.GetInputAxis = ReInput.players.GetPlayer(0).GetAxis;
    7.     }
    8. }
     
    Last edited: May 19, 2018
  11. StarFluke

    StarFluke

    Joined:
    Jan 19, 2013
    Posts:
    22
    Nice one canis!
     
  12. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    3,160
    I would do it like this. This also handles joystick/keyboard camera movement better.

    NOTE: Rewired 1.1.19.0+ includes this integration in the package. The integration included with Rewired is likely to be more up to date than this script.

    Code (csharp):
    1. // Copyright (c) 2018 Augie R. Maddox, Guavaman Enterprises. All rights reserved.
    2.  
    3. namespace Rewired.Integration.Cinemachine {
    4.     using UnityEngine;
    5.  
    6.     /// <summary>
    7.     /// Changes input source for Cinemachine to Rewired.
    8.     /// You do not need to add this Component to a GameObject in order for it to work,
    9.     /// but you can do so if you want to be able to set the Player Id in the inspector.
    10.     /// Otherwise, you can change the Player Id through the static playerId property.
    11.     /// </summary>
    12.     public sealed class RewiredCinemachineBridge : MonoBehaviour {
    13.  
    14.         // Instance Members
    15.  
    16.         [Tooltip("The Player Id of the Player that controls Cinemachine input.")]
    17.         [SerializeField]
    18.         private int _playerId = 0;
    19.  
    20.         [Tooltip("The absolute sensitivity multipler. This is only applied to absolute axis sources (joystick axes, keyboard keys, etc.).")]
    21.         [SerializeField]
    22.         [Rewired.Utils.Attributes.FieldRange(0f, float.MaxValue)]
    23.         private float _absoluteAxisSensitivity = defaultabsoluteAxisSensitivity;
    24.        
    25.         [Tooltip("If enabled, input values from absolute axis sources will be scaled based on the screen resolution. This makes joystick axes behave more consistently with mouse axes at different screen resolutions.")]
    26.         [SerializeField]
    27.         private bool _scaleAbsoluteAxesToScreen = s_scaleAbsoluteAxesToScreen;
    28.  
    29.         private void Awake() {
    30.             s_instance = this;
    31.             s_playerId = _playerId;
    32.             s_absoluteAxisSensitivity = _absoluteAxisSensitivity;
    33.         }
    34.  
    35. #if UNITY_EDITOR
    36.         private void OnValidate() {
    37.             if(s_playerId != _playerId) {
    38.                 s_playerId = _playerId;
    39.             }
    40.             if(s_absoluteAxisSensitivity != _absoluteAxisSensitivity) {
    41.                 s_absoluteAxisSensitivity = _absoluteAxisSensitivity;
    42.             }
    43.         }
    44. #endif
    45.  
    46.         private void OnDestroy() {
    47.             if(s_instance == this) s_instance = null;
    48.         }
    49.  
    50.         // Static Members
    51.  
    52.         /// <summary>
    53.         /// The default absolute source sensitivity.
    54.         /// </summary>
    55.         public const float defaultabsoluteAxisSensitivity = 30f;
    56.  
    57.         private static RewiredCinemachineBridge s_instance;
    58.         private static int s_playerId = 0;
    59.         private static float s_absoluteAxisSensitivity = defaultabsoluteAxisSensitivity;
    60.         private static bool s_scaleAbsoluteAxesToScreen = false;
    61.  
    62.         /// <summary>
    63.         /// The Player Id of the Player that controls Cinemachine input.
    64.         /// </summary>
    65.         public static int playerId {
    66.             get { return s_playerId; }
    67.             set {
    68.                 s_playerId = value;
    69.                 if(s_instance != null) s_instance._playerId = value;
    70.             }
    71.         }
    72.  
    73.         /// <summary>
    74.         /// The absolute sensitivity multipler. This is only applied to absolute axis sources (joystick axes, keyboard keys, etc.).
    75.         /// </summary>
    76.         public static float absoluteAxisSensitivity {
    77.             get { return s_absoluteAxisSensitivity; }
    78.             set {
    79.                 if(value < 0f) value = 0f;
    80.                 s_absoluteAxisSensitivity = value;
    81.                 if(s_instance != null) s_instance._absoluteAxisSensitivity = value;
    82.             }
    83.         }
    84.        
    85.         /// <summary>
    86.         /// If enabled, input values from absolute axis sources will be scaled based on the screen resolution.
    87.         /// This makes joystick axes behave more consistently with mouse axes at different screen resolutions.
    88.         /// </summary>
    89.         public static bool scaleAbsoluteAxesToScreen {
    90.             get { return s_scaleAbsoluteAxesToScreen; }
    91.             set {
    92.                 s_scaleAbsoluteAxesToScreen = value;
    93.                 if(s_instance != null) s_instance._scaleAbsoluteAxesToScreen = value;
    94.             }
    95.         }
    96.  
    97.         [RuntimeInitializeOnLoadMethod]
    98.         private static void Initialize() {
    99.             global::Cinemachine.CinemachineCore.GetInputAxis = GetAxis;
    100.         }
    101.  
    102.         private static float GetAxis(string name) {
    103.             if (!ReInput.isReady) return UnityEngine.Input.GetAxis(name);
    104.             Player player = ReInput.players.GetPlayer(playerId);
    105.             if(player == null) return 0f;
    106.             float value = player.GetAxis(name);
    107.             if(value != 0f && player.GetAxisCoordinateMode(name) == AxisCoordinateMode.Absolute) {
    108.                 value *= s_absoluteAxisSensitivity * Time.unscaledDeltaTime;
    109.                 if(s_scaleAbsoluteAxesToScreen) value *= Screen.currentResolution.width / 1920f;
    110.             }
    111.             return value;
    112.         }
    113.     }
    114. }
     
    Last edited: Aug 2, 2018