Unity gets the button information of the controller in the XR device

In the development of ordinary XR equipment, especially when it is suitable for VR equipment, we will use the handle operation.

We know that the Oculus SDK provides OVRInput, which can get the key information of the controller.

// public variable that can be set to LTouch or RTouch in the Unity Inspector
public Controller controller;

// returns a float of the Hand Trigger’s current state on the Oculus Touch controller
// specified by the controller variable.
OVRInput.Get(OVRInput.Axis1D.PrimaryHandTrigger, controller);

// returns true if the primary button (“A” or “X”) is pressed on the Oculus Touch controller
// specified by the controller variable.
OVRInput.Get(OVRInput.Button.One, controller);

Because the applications we develop must not only run on Oculus, if they run on other VR devices, do we need to connect to the SDK of each VR device?

Don't panic, in fact, Unity has already done this for me. Unity encapsulates the XR Input interface, which is an abstraction that can be used on various VR devices.

How to use it? Let's first look at the correspondence of each button packaged by Unity. It already supports many VR devices on the market. Mainly Oculus. You can go to the official website for reference: Unity - Manual: Unity XR Input

I have encapsulated the usage method, and it can be used by mounting the GameObject. You can use it yourself.

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.XR;

[System.Serializable]
public enum InputFeature
{
    //
    // ժҪ:
    //     The primary face button being pressed on a device, or sole button if only one
    //     is available.
    primaryButton,
    //
    // ժҪ:
    //     The primary face button being touched on a device.
    primaryTouch,
    //
    // ժҪ:
    //     The secondary face button being pressed on a device.
    secondaryButton,
    //
    // ժҪ:
    //     The secondary face button being touched on a device.
    secondaryTouch,
    //
    // ժҪ:
    //     A binary measure of whether the device is being gripped.
    gripButton,
    //
    // ժҪ:
    //     A binary measure of whether the index finger is activating the trigger.
    triggerButton,
    //
    // ժҪ:
    //     Represents a menu button, used to pause, go back, or otherwise exit gameplay.
    menuButton,
    //
    // ժҪ:
    //     Represents the primary 2D axis being clicked or otherwise depressed.
    primary2DAxisClick,
    //
    // ժҪ:
    //     Represents the primary 2D axis being touched.
    primary2DAxisTouch,
    //
    // ժҪ:
    //     Represents the secondary 2D axis being clicked or otherwise depressed.
    secondary2DAxisClick,
    //
    // ժҪ:
    //     Represents the secondary 2D axis being touched.
    secondary2DAxisTouch,
    //
    // ժҪ:
    //     Use this property to test whether the user is currently wearing and/or interacting
    //     with the XR device. The exact behavior of this property varies with each type
    //     of device: some devices have a sensor specifically to detect user proximity,
    //     however you can reasonably infer that a user is present with the device when
    //     the property is UserPresenceState.Present.
    userPresence
}

public class XRControllerButtonWatcher : MonoBehaviour
{
    private Dictionary<InputFeature, InputFeatureUsage<bool>> inputFeatureUsageMap = new Dictionary<InputFeature, InputFeatureUsage<bool>>() {
        { InputFeature.primaryButton, CommonUsages.primaryButton },
        { InputFeature.primaryTouch, CommonUsages.primaryTouch },
        { InputFeature.secondaryButton, CommonUsages.secondaryButton },
        { InputFeature.secondaryTouch, CommonUsages.secondaryTouch },
        { InputFeature.gripButton, CommonUsages.gripButton },
        { InputFeature.triggerButton, CommonUsages.triggerButton },
        { InputFeature.menuButton, CommonUsages.menuButton },
        { InputFeature.primary2DAxisClick, CommonUsages.primary2DAxisClick },
        { InputFeature.primary2DAxisTouch, CommonUsages.primary2DAxisTouch },
        { InputFeature.secondary2DAxisClick, CommonUsages.secondary2DAxisClick },
        { InputFeature.secondary2DAxisTouch, CommonUsages.secondary2DAxisTouch },
        { InputFeature.userPresence, CommonUsages.userPresence }
    };

    [SerializeField]
    public InputFeature ButtonInputFeature;

    [SerializeField]
    public InputDeviceCharacteristics inputDeviceType = InputDeviceCharacteristics.None;

    [SerializeField]
    public UnityEvent OnInputDown;

    [SerializeField]
    public UnityEvent OnInputUp;

    private InputFeatureUsage<bool> buttonInputFeatureUsage;

    private bool lastButtonState = false;
    private List<InputDevice> devicesButton;

    private void Awake()
    {
        if (OnInputDown == null)
            OnInputDown = new UnityEvent();
        if (OnInputUp == null)
            OnInputUp = new UnityEvent();

        devicesButton = new List<InputDevice>();

        if (!inputFeatureUsageMap.TryGetValue(ButtonInputFeature, out buttonInputFeatureUsage))
        {
            Debug.LogError("not found inputFeature: " + ButtonInputFeature);
        }
    }

    private void OnEnable()
    {
        Init();
    }

    private void OnDisable()
    {
        InputDevices.deviceConnected -= InputDevices_deviceConnected;
        InputDevices.deviceDisconnected -= InputDevices_deviceDisconnected;
        devicesButton.Clear();
    }

    private void InputDevices_deviceConnected(InputDevice device)
    {
        bool discardedValue;
        if (device.TryGetFeatureValue(buttonInputFeatureUsage, out discardedValue))
        {
            Debug.Log($"add device: {device.name}");
            devicesButton.Add(device); // Add any devices that have a primary button.
        }
    }

    private void InputDevices_deviceDisconnected(InputDevice device)
    {
        if (devicesButton.Contains(device))
            devicesButton.Remove(device);
    }

    private void Update()
    {
        bool tempState = false;
        foreach (var device in devicesButton)
        {
            bool primaryButtonState = false;
            tempState = device.TryGetFeatureValue(buttonInputFeatureUsage, out primaryButtonState) // did get a value
                        && primaryButtonState // the value we got
                        || tempState; // cumulative result from other controllers
        }

        if (tempState != lastButtonState) // Button state changed since last frame
        {
            if (tempState)
                OnInputDown?.Invoke();
            else
                OnInputUp?.Invoke();

            lastButtonState = tempState;
        }
    }

    public void Init()
    {
        List<InputDevice> allDevices = new List<InputDevice>();
        if (inputDeviceType == InputDeviceCharacteristics.None)
            InputDevices.GetDevices(allDevices);
        else
            InputDevices.GetDevicesWithCharacteristics(inputDeviceType, allDevices);

        foreach (InputDevice device in allDevices)
            InputDevices_deviceConnected(device);

        InputDevices.deviceConnected += InputDevices_deviceConnected;
        InputDevices.deviceDisconnected += InputDevices_deviceDisconnected;
    }
}

Using the XR Input that comes with Unity can well support a variety of devices. There is no need to connect the Input in the SDK of each VR device one by one.

Reference documentation:

Unity - Manual: Unity XR Input

Guess you like

Origin blog.csdn.net/grace_yi/article/details/123237832