Skip to content
This repository has been archived by the owner on Jul 22, 2024. It is now read-only.

Make controllers for both Unity XR and WebVR #295

Closed
wants to merge 6 commits into from

Conversation

caseyyee
Copy link
Contributor

@caseyyee caseyyee commented May 31, 2018

This PR adds the ability to map controller button and axis inputs to the appropriate Unity XR input and WebVR controller, depending on which context the project is running. Basically, it enables VR controllers to work between Unity and WebVR and fixes issue #233.

This involves change with how controllers work:

  1. Removes WebVRManager and makes WebVRController a component of controller GameObject. (This binding was done auto-magically previously, this is way more straightforward and easier to understand and work with).

image

  • Handness is now defined on this component.
  • Component now deals with applying appropriate transforms for rotation and position (rather than user script).
  • Button mapping configuration defined using scriptable object asset (we'll get into how that's done down below)
  • Usage (as showcased in ControllerInteraction.cs example):
// Grab the WebVR controller component.
WebVRController controller = gameObject.GetComponent<WebVRController>();

// Check "Trigger" Input state.
if (controller.GetButtonDown("Trigger"))
{
    Debug.Log("Trigger is down!");
}

The Trigger action needs to be mapped to the appropriate Unity XR and WebVR controller inputs. To do this, we have a WebVRControllerInputSettings scriptable object that is used to create a configuration.

We bundle a basic configuration for Left and Right hand controllers: LeftControllerMap and RightControllerMap respectively. You can make your own using Assets > Create > WebVRControllerInputSettings:

image

For each action, we define a WebVR Controller button or axis ID and Unity Input definition. This is defined using Unity's Input Manager:

image

See Unity's XR Input docs https://docs.unity3d.com/Manual/OpenVRControllers.html to find the appropriate axis and button ID's to use. In this case, we want to use Axis1D.PrimaryIndexTrigger, which corresponds with joystick button 14.

@caseyyee caseyyee requested a review from cvan May 31, 2018 09:16
private FixedJoint attachJoint = null;
private Rigidbody currentRigidBody = null;
private List<Rigidbody> contactRigidBodies = new List<Rigidbody> ();

void Awake()
{
controllerManager = WebVRControllerManager.Instance;
//controllerManager = WebVRControllerManager.Instance;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, will remove this.

{
#if UNITY_EDITOR
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, this might be better as !UNITY_WEBGL since XR can be used outside of UNITY_EDITOR as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, good call 👍 can you change this? as well as in GetButton?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a comment explaining the #if/#else/#endif block?


void Update()
{
#if UNITY_EDITOR
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix casing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above, can you fix? and also can you add a comment explaining the conditional logic? thanks!

Copy link
Contributor

@cvan cvan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great work - refactor looking good!

on both master and on this branch, I tested the following:

  • Oculus Rift with Touch controllers in Unity's XR preview mode
  • Oculus Rift with Touch controllers in WebVR in Firefox for Windows
  • HTC Vive with controllers in Unity's XR preview mode
  • HTC Vive with controllers in WebVR in Firefox for Windows

in the Vive, my right-hand controller could not pick up objects. both hands appeared correctly, and I was able to pick up the interactable objects with my left hand. but my right hand did not work in Unity's XR preview mode. surprisingly or not, my right hand (and left hand) did work in WebVR in Firefox for Windows. (I'm not sure if this is an Oculus vs. OpenVR bug, or whether it's reproducible with Oculus as well. I encountered some problematic tracking issues with my Oculus Rift that seemed unrelated to your patch/this project, so I was unable to grab objects to test if Oculus is also affected.)

👍 fantastic progress here. this makes development easy breezy. I can't believe how simple it is now to develop whilst testing in VR and rapidly making adjustments.

{
[Tooltip("Map GameObject to controller hand name.")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you change this to Hand of controller to map to. (or something succincter, of course)?

{
[Tooltip("Map GameObject to controller hand name.")]
public WebVRControllerHand hand = WebVRControllerHand.NONE;
[Tooltip("Controller Input settings")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Controller input settings. (including the trailing period)

public int index;
public Enum hand;
[HideInInspector]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 good call


private Dictionary<WebVRInputAction, bool[]> buttonStates = new Dictionary<WebVRInputAction, bool[]>();
private Dictionary<string, bool[]> buttonStates = new Dictionary<string, bool[]>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 this is probably better to use native strings than the WebVRInputAction interface

if (i == (int)action) {
if (buttonStates.ContainsKey(action))
buttonStates[action][0] = button.pressed;
if (input.gamepadId == i)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if a gamepad is removed and/or added, gamepadId can be guaranteed to reflect the same Gamepad object as the one that was initially detected? (I'm pretty sure Gecko and Chromium handle this properly, but I haven't checked all the implementations.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I messed this one up. This should be gamepadButtonId, not gamepadId.


[CreateAssetMenu(menuName = "WebVRControllerInputSettings")]
public class WebVRControllerInputSettings : ScriptableObject {
[Header("WebVR Controller Input Settings")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: do we need to say WebVR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just want to be clear since there are two different input systems in use here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following my former comments, we should change this to: WebVR Input Map.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, WebVR Input Map is clearer.


[System.Serializable]
public class WebVRControllerInput {
public string actionName;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add [Tooltip(…)]s or helpful descriptions?

}

private void onControllerUpdate(
int index, string h, Vector3 position, Quaternion rotation, Matrix4x4 sitStand, WebVRControllerButton[] b)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is index used here?

private void onControllerUpdate(
int index, string h, Vector3 position, Quaternion rotation, Matrix4x4 sitStand, WebVRControllerButton[] b)
{
// convert string to enum
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it be possible to just pass in the enum instead of passing and parsing the string on every call?

int index, string h, Vector3 position, Quaternion rotation, Matrix4x4 sitStand, WebVRControllerButton[] b)
{
// convert string to enum
WebVRControllerHand updateHand;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wherever you decide to keep this string-to-enum parsing, could you do something like this to catch any possible enum-parsing errors?

WebVRControllerHand updateHand = WebVRControllerHand.NONE;
if (!String.IsNullOrEmpty(h)) {
  try {
    updateHand = (WebVRControllerHand) Enum.Parse(typeof(WebVRControllerHand), h.ToUpper(), true);
  }
  catch {
  }
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update: it looks like you can use Enum.TryParse

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@caseyyee
Copy link
Contributor Author

caseyyee commented Jun 8, 2018

@cvan ready for another review, fixed review issues + nits.

cvan
cvan previously approved these changes Jun 8, 2018
Copy link
Contributor

@cvan cvan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

grabbing objects with the right controller now works now. 👍

great work! I tested with both Rift and Vive in both Unity's XR player and WebVR-exported builds in Firefox. ship it! 🚢

P.S. see my comment about the changed default camera position in non-VR mode. also, we should address the varying camera positions in Oculus and in Windows Mixed Reality.

@@ -515,6 +515,7 @@ GameObject:
- component: {fileID: 54027100335586508}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

something in here caused the default camera position to be different (compare it to the position in master)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

master

screenshot 61
screenshot 64

this branch

screenshot 63
screenshot 62

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cvan hm. not sure I understand. Only when entering VR?

Copy link
Contributor Author

@caseyyee caseyyee Jun 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

regarding the default camera position. It's the transform that the browser supplies. Not sure if there is anything that we need to do specifically to accommodate different devices, but I suspect this may be an issue with WebVR with Edge. Will need to do some testing.

I will give it a check with the Samsung HMD.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, I just filed issue #303 to track this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, so I tried rearranging the order of the Virtual Reality SDKs in the XR Settings, but it seems to set the camera position below the desk when rendered via both Oculus and SteamVR.

rendered with Oculus SDK:
screenshot

@cvan cvan changed the title Make controllers for both Unity XR and WebVR. Make controllers for both Unity XR and WebVR Jun 12, 2018
Copy link
Contributor

@delapuente delapuente left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super nice job @caseyyee ! This is great, we should provide full mappings for not only the trigger and grip but including all the buttons but is a great enhancement.

Please, make the changes I've requested you and feel free to discuss. Although the ease of use is mainly provided by the default mappings, we should make super clear that the user understand what is she doing.

Another thing, there is a Input folder inside the script. Do you mind to move the controller-related scripts inside that folder?

@@ -81,13 +113,56 @@ public bool GetButtonUp(WebVRInputAction action)
return isUp;
}

public WebVRController(int index, Enum hand, Vector3 position, Quaternion rotation, Matrix4x4 sitStand)
private void onControllerUpdate(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Public names should be in UpperCamelCase.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's internal. The public function is on the WebVRManager.

@@ -81,13 +113,56 @@ public bool GetButtonUp(WebVRInputAction action)
return isUp;
}

public WebVRController(int index, Enum hand, Vector3 position, Quaternion rotation, Matrix4x4 sitStand)
private void onControllerUpdate(
int index, string h, Vector3 position, Quaternion rotation, Matrix4x4 sitStand, WebVRControllerButton[] b)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is h? Can you provide a more meaningful name here?

private void onControllerUpdate(
int index, string h, Vector3 position, Quaternion rotation, Matrix4x4 sitStand, WebVRControllerButton[] b)
{
// convert string to enum
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extract this into a meaningful function handFromString() and remove the comment.

handValue = (WebVRControllerHand) Enum.Parse(typeof(WebVRControllerHand), h.ToUpper(), true);
}
catch
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least, we should show a warning explaining what happened, hinting ourselves about how to solve the problem.

@@ -81,13 +113,56 @@ public bool GetButtonUp(WebVRInputAction action)
return isUp;
}

public WebVRController(int index, Enum hand, Vector3 position, Quaternion rotation, Matrix4x4 sitStand)
private void onControllerUpdate(
int index, string h, Vector3 position, Quaternion rotation, Matrix4x4 sitStand, WebVRControllerButton[] b)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, provide a meaningful name for the b parameter.

using UnityEngine;

[CreateAssetMenu(menuName = "WebVRControllerInputSettings")]
public class WebVRControllerInputSettings : ScriptableObject {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.


[CreateAssetMenu(menuName = "WebVRControllerInputSettings")]
public class WebVRControllerInputSettings : ScriptableObject {
[Header("WebVR Controller Input Settings")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following my former comments, we should change this to: WebVR Input Map.

}

[System.Serializable]
public class WebVRControllerInput {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following the naming from before, the former is the map containing individual mappings so this should be WebVRInputMapping. I'm not enforcing these names but try to make clear that these structures are mapping to different sources (the one from the Unity Input System and the one coming from the Web platform) to a common name. Clever idea and very nice from your side to provide some defaults but let make it super-clear.


[System.Serializable]
public class WebVRControllerInput {
[Tooltip("Name of input action to be performed.")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since these are tooltips, I would say for this: A meaningful name describing the gesture performed on the controller.

public class WebVRControllerInput {
[Tooltip("Name of input action to be performed.")]
public string actionName;
[Tooltip("WebVR Gamepad button ID.")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather say: Button ID coming from Web Gamepad API.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@cvan
Copy link
Contributor

cvan commented Jun 18, 2018

@caseyyee let me know when you've addressed @delapuente's review feedback (excellent comments, btw 👍). and I can take another look, test it, and we can merge this. let me know if you're stuck on anything or need a hand. otherwise, this looks very close to ready. great work, @caseyyee!

Copy link
Contributor

@cvan cvan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

almost there!

two issues:

  1. I cannot pick up objects anymore (seems to be a regression, but it seems fixed somewhat in your follow-up PR Cross platform controller support for Unity XR and WebVR. #306)
  2. the starting camera position in the Rift (regardless of the order of OpenVR vs. Oculus in Unity's XR Settings) starts below the desk

looking good 👍 let me know what else you'd like me to test

@@ -515,6 +515,7 @@ GameObject:
- component: {fileID: 54027100335586508}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, so I tried rearranging the order of the Virtual Reality SDKs in the XR Settings, but it seems to set the camera position below the desk when rendered via both Oculus and SteamVR.

rendered with Oculus SDK:
screenshot

@caseyyee
Copy link
Contributor Author

Closing in favor of #306.

@caseyyee caseyyee closed this Jun 26, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants