VR Add-On: Smooth Locomotion

Shotts

New member
Hi Everyone,
I'd like to get the VR character controller's movements to be directed by the Oculus Rift left joystick and to disable teleport.

Justin mentioned in the VR Add-On release thread that this could be configured in the Unity Input Manager. Link to the documentation on Unity Input Manager:

I located what appears to be the Unity documentation for the Oculus Rift controller mappings:

In the Unity project, I have revised the Horizontal and Vertical Axes so that 'Type' is now 'Joystick Axis'. I'm at a bit of loss what to do from here (or if that was even the right action to take). The Unity documentation claims that it should receive input from all joysticks unless a specific one is specified,
("Joy Num Choose which joystick should be used. Defaults to retrieving the input from all joysticks.").

My assumption then is that I need to somehow disable the Opsive VR Add-On teleport ability. However, the teleport ability does not come enabled in the demo scene's First Person Character, and yet, the player's movements are still controlled through teleport so it's a bit of a mystery to me as to how to disable it.
 

Justin

Administrator
Staff member
My assumption then is that I need to somehow disable the Opsive VR Add-On teleport ability. However, the teleport ability does not come enabled in the demo scene's First Person Character, and yet, the player's movements are still controlled through teleport so it's a bit of a mystery to me as to how to disable it.
That is correct. The teleport is enabled by default - you can disable it by deselecting it within the ability list.

From there you'll want to ensure the First Person VR Movement Type is not blocking the input. After that the character will move according to the Character Locomotion's Motor Acceleration/Damping based on the button mapping setup on the Character Locomotion Handler component. The movement maps to the PrimaryThumbstick so you'll want to ensure that the button mappings specified on the Character Locomotion Handler matches the axis specified by the PrimaryThumbstick (joystick mappings 1 and 2)
 

Shotts

New member
Thanks for the reply Justin and for your patience in walking me through this!

My confusion with the teleport ability is that I didn't enable it nor is it marked as enabled under abilities and yet that is the locomotion option.

In regards to the first person VR movement type blocking the input, I'm interpreting that as I should add the "First Person Combat" type under the Ultimate Character Locomotion (Script) attached to the "First Person Character". Doing so, however, still left me with teleport.

I noticed that the "One Hand First Person Nolan" also has the Ultimate Character Locomotion (Script). Would this also need to be modified?

The "Ultimate Character Locomotion Handler (Script)" has two fields: Horizontal Input Name and Forward Input Name. The Horizontal field has "Horizontal" and the Forward field has "Vertical". These appear consistent with the Unity Input Names (Horizontal and Vertical). Under the Unity Input, I have the Joy Num of Horizontal and Vertical set to "Get Motion from all Joysticks". I switched these to "Joystick 1" and then later to "Joystick 2" but neither seemed to have any effect.
 

Justin

Administrator
Staff member
In regards to the first person VR movement type blocking the input, I'm interpreting that as I should add the "First Person Combat" type under the Ultimate Character Locomotion (Script) attached to the "First Person Character". Doing so, however, still left me with teleport.
You should be using the First Person VR movement type.

I noticed that the "One Hand First Person Nolan" also has the Ultimate Character Locomotion (Script). Would this also need to be modified?
No, this is just an example for one-handed trackers such as the Oculus Go.

The "Ultimate Character Locomotion Handler (Script)" has two fields: Horizontal Input Name and Forward Input Name. The Horizontal field has "Horizontal" and the Forward field has "Vertical". These appear consistent with the Unity Input Names (Horizontal and Vertical). Under the Unity Input, I have the Joy Num of Horizontal and Vertical set to "Get Motion from all Joysticks". I switched these to "Joystick 1" and then later to "Joystick 2" but neither seemed to have any effect.
Your inputs sound correct. Horizontal should be mapped to joystick axis 1 and vertical mapped to joystick axis 2.

Just as a test if you enable the One Handed First Person character does it allow for smooth movement?
 

Shotts

New member
I still haven't had any success getting this up and running. Joystick axis 1 and 2 aren't explicitly listed under Unity Input. Under Axis, the options are Y or X axis and then the list goes on to numbered axes. I also did not have any success with the one hand controller. The character was inoperable aside from the trigger buttons initiating a punch. I've attached screenshots in hopes this will lead to a speedier resolution.

Screen of Unity Input Alongside the First Person Character's Ultimate Character Locomotion Handler
UFPC_Oculus Joystick.jpg

Screen of Available Options for Axis in Unity Input
UFPC_Oculus Joystick Options.jpg
 

Justin

Administrator
Staff member
Version 1.0.1 just went out and in the next version we'll add a smooth movement option to the two handed first person character to make this setup easier.

That setup looks correct on the unity side of things. To be debug this can you create a new component and add the following to the Update method:

Code:
Debug.Log(UnityEngine.Input.GetAxis("Horizontal") + " " + UnityEngine.Input.GetAxis("Vertical"));
This will indicate if Unity is getting the correct input or not. If it getting the correct input then it is something on the character controller side of things.
 

Shotts

New member
Hi Justin,
I placed that script on the First Person Character on the demo scene and the console was showing values. Most were 0 0 but there were actual values like the following:

-0.9999511 -0.07544439
UnityEngine.Debug:Log(Object)
Testing:Update() (at Assets/Testing.cs:10)

I assume this means there is something holding this up on the character controller side then.

I don't think you've spoken to this but I did not enable "Teleport" under the first person character abilities so I'm puzzled as to why that seems to be the default. I noticed that the Demo Manager has a script called State Switcher that has Teleport defined as the Start State Name. I cleared it out just for fun which did disable teleport but did not allow me to move the character with the joystick.

Thanks for adding smooth locomotion as an ability! That should simplify things.
 

Justin

Administrator
Staff member
That looks good. Did you disable the Disable Input parameter on the First Person VR movement type? I just created a new character and did the following to get it working:

1. Went through the standard scene, camera, and first person character setup.
2. Updated the scene, camera, and character to work with two handed VR.
3. Removed the teleport ability.
4. Disabled Disable Input on the First Person VR movement type.

The character now moves with the left joystick for the Oculus Touch. I've attached the scene for your reference.
 

Attachments

Shotts

New member
Thanks Justin! I have yet to make this work with the demo scene but the scene you provided works nicely.

I'd like to have Directional Rotate on the right hand. I enabled it under abilities but to no effect. The inputs of Right Vertical Movement are mapped to 4th axis (Joysticks) and Right Horizontal Movement to 5th axis (Joysticks). This seems reasonable and changing it did nothing useful. Any thoughts?

Playing with the scene also reminded me that there are two ways to go about smooth locomotion. The one you provided uses the headset orientation to define what is forward. The other option that VR developers offer is to have it based on the joystick. The joystick option allows players, for example, to peer over their shoulder, glance forward, and then glance back again all without having to adjust the direction they are pressing on the joystick. I personally prefer this option and feel it is a better fit for fast-paced shooters.
 

Justin

Administrator
Staff member
Ahh, I see what happened. DirectionalRotate is waiting for the UI to fade before it actually applies the rotation. If there is no fader on the UI then it is never going to rotate. You can fix this by doing one of the following:

1. Adding the UI components to the scene
2. Adding:

Code:
m_ApplyRotation = true;
to the lines immediately following m_Rotating = true;. This is within OnHorizontalAxisInput and OnVerticalAxisInput. I am going to update the ability so it will work regardless on if you have the UIFader component.

The joystick option allows players, for example, to peer over their shoulder, glance forward, and then glance back again all without having to adjust the direction they are pressing on the joystick.
Do you know of an example game that uses this method so I can wrap my head around it?
 
Fallout VR, Skyrim VR, Vanishing Realms, Serious Sam series, No Man's Sky, basically every VR FPS game. They call it hand oriented or controller oriented or some such. I had to implement my own in my own Locomotion Handler. Get the rotation of the controller and use that to adjust the vectors going to the KinematicObjectManager.SetCharacterMovementInput.
 

Shotts

New member
Thanks Justin! I'll give that a try.

Thanks for chiming in RobotGames! You're absolutely right that this is a common standard.

It's still early access but I feel Zero Caliber (developed by XReal Games) is doing a lot of things right with their FPS. They have the option for the user to toggle between headset- or joystick-driven smooth locomotion. You may also find the work they've done with the weapon systems interesting (reload system, weapons holstered on avatar, weapon grips, changing weapon attachments on the fly, etc).
 
If you are using SteamVR with the new Input system here is how I did it. I had to create my own Locomotion Handler to deal with Steam Input and am planning on one for Oculus. The important stuff for us is in the Update.

Code:
public SteamVR_Input_Sources handType;
public SteamVR_Action_Vector2 stickAction;
public SteamVR_Action_Pose handPose;

private Vector2 stickVector = Vector2.zero;
private Vector3 moveDirection = Vector3.zero;
private Quaternion orientation = Quaternion.identity;

...

        private void Update()
        {
            StickPointing();
            KinematicObjectManager.SetCharacterMovementInput(
                m_CharacterLocomotion.KinematicObjectIndex, moveDirection.x, moveDirection.z);
         
            UpdateAbilityInput();
        }
     
        void StickPointing()
        {
            orientation = handPose.GetLocalRotation(handType);
            stickVector = stickAction.GetAxis(handType);
            moveDirection = orientation * Vector3.forward * stickVector.y + orientation * Vector3.right * stickVector.x;
        }
For Oculus they also have a hand pose, OVRPose and you can figure out how to use that if you are doing Oculus. If you are wondering Pose is just a structure that contains all the info for an object, like the hand, Position Rotation etc. Steam includes stuff like velocity as well that Oculus does not.
 
Last edited:
I made an update that will work with Steam or Oculus or anything that the VR Add on works with because it only uses the VR add on. I just used the HandHandler to get the hand transform, then did the math on it from there. Works pretty good, it would better if I made a mechanism for Left/Right hand because some people want Left Handed input but I may just say too bad lefty! ;)

Code:
private HandHandler m_handHandler;
...

protected override void Awake()
{
    ...
    // put this up top where the other variables are cached
    m_handHandler = m_GameObject.GetCachedComponent<HandHandler>();
    ...
   
private void Update()
{
    // The input should be retrieved within Update. The KinematicObjectManager will then move the character according to the input.
    m_HorizontalMovement = m_PlayerInput.GetAxisRaw(m_HorizontalInputName);
    m_ForwardMovement = m_PlayerInput.GetAxisRaw(m_ForwardInputName);

// These are the new/changed lines.
    orientation = m_handHandler.LeftHand.localRotation;
    moveDirection = orientation * Vector3.forward * m_ForwardMovement + orientation * Vector3.right * m_HorizontalMovement;
    KinematicObjectManager.SetCharacterMovementInput(m_CharacterLocomotion.KinematicObjectIndex, moveDirection.x, moveDirection.z);
   
    UpdateAbilityInput();
}
 
Top