Skip to content

ViveRole

Lawrence Wong edited this page Dec 21, 2020 · 13 revisions

ViveRole is a mapping system that relate between logic roles and tracking devices. That means application can indicate tracking device by semantic role name instead of device index.

Table of Contents

Built-in Roles

Now there are 4 built-in role sets, each role set has their own default mapping logic:

  1. DeviceRole
    Device0 ~ Device15
    role that mapping to all 16 devices, ordered exactly same as device index.
  2. HandRole
    RightHand
    Mapping to the controller on the right hand side.
    LeftHand
    Mapping to the controller on the left hand side.
    ExternalCamera
    Mapping to the 3rd found controller. If 3rd controller not available, then mapping to the first found generic tracker. It is also the default tracking target of ExternalCameraHook.
    Controller4 ~ 15
    Mapping to the rest of nth found controllers.
  3. TrackerRole
    Tracker1 ~ Tracker15
    Mapping to the nth found generic trackers.
  4. BodyRole
    Head
    RightHand
    LeftHand
    RightFoot
    LeftFoot
    Hip

Using Role Enum and ViveRoleProperty

ViveRole defines the logic roles using enum type. Most of the API in Vive Input Utility use the role enum to indicate tracking device.

For example:

using HTC.UnityPlugin.Vive;
using UnityEngine;

public class ExampleClass : MonoBehaviour
{
    private void Update()
    {
        // common functions that use role to indicate device
        uint exCamDeviceIndex = ViveRole.GetDeviceIndexEx(HandRole.ExternalCamera);
        bool rightPadTouched = ViveInput.GetPressEx(HandRole.RightHand, ControllerButton.PadTouch);
        float leftTriggerValue = ViveInput.GetAxisEx(HandRole.LeftHand, ControllerAxis.Trigger);
        Vector3 tracker1Position = VivePose.GetPoseEx(TrackerRole.Tracker1).pos;
        Quaternion headRotation = VivePose.GetPoseEx(BodyRole.Head).rot;
    }
}
You can also use ViveRoleProperty to represent a role. This class basically holds a enum type and a enum value.

This example shows how it works with the role enum:

using HTC.UnityPlugin.Vive;
using UnityEngine;

public class ExampleClass : MonoBehaviour
{
    // set default value as HandRole.RightHand
    public ViveRoleProperty viveRole = ViveRoleProperty.New(HandRole.RightHand);

    private void Update()
    {
        uint deviceIndex = viveRole.GetDeviceIndex();
        float triggerValue = ViveInput.GetAxis(viveRole, ControllerAxis.Trigger);
        transform.localPosition = VivePose.GetPose(viveRole).pos;
        transform.localRotation = VivePose.GetPose(viveRole).rot;

        // switch hands when menu button pressed
        if (ViveInput.GetPressDown(viveRole, ControllerButton.Menu))
        {
            if (viveRole.IsRole(HandRole.RightHand))
            {
                viveRole.SetEx(HandRole.LeftHand);
            }
            else
            {
                viveRole.SetEx(HandRole.RightHand);
            }
        }
    }
}
Note that ViveRoleProperty's value can also be changed in inspector:

Create Custom Role

You can create custom role by adding ViveRoleEnumAttribute to your enum type. For example:

using HTC.UnityPlugin.Vive;

[ViveRoleEnum((int)MyEquipRole.None)]// must specify invalid role value as default role value
public enum MyEquipRole
{
    None,
    MainWeapon,
    SecondaryWeapon,
    Shield,
    ...
}

You can customize auto-mapping logic by implementing ViveRoleHandler<EnumType> and call ViveRole.AssignMapHandler() to apply it. For Example:

using UnityEngine;
using HTC.UnityPlugin.Vive;

public class MyEquipRoleHandler : ViveRole.MapHandler<MyEquipRole>
{
    // called when handler is assigned
    public override void OnInitialize() { RemapAll(); }
    // called when device connected or disconnected
    public override void OnConnectedDeviceChanged(uint deviceIndex, ETrackedDeviceClass deviceClass, string deviceSN, bool connected) { RemapAll(); }
    // called when binding changed (Ex. when ViveRole.GetMap<MyEquipRole>().BindRole called)
    public override void OnBindingChanged(MyEquipRole role, string deviceSN, bool bound) { RemapAll(); }
    // called when OpenVR TrackedDeviceRoleChanged event emitted
    public override void OnTrackedDeviceRoleChanged() { RemapAll(); }

    public void RemapAll()
    {
        // some auto mapping algorithm...
        // call protected function here to map/unmap relations
        // this.UnmappingAll() to unmap all relations
        // this.MappingRole(MyEquipRole role, uint deviceIndex) to map the role to the device
    }
}

public class MyEquipRoleManager : MonoBehaviour
{
    public readonly MyEquipRoleHandler handler = new MyEquipRoleHandler();

    public void Awake()
    {
        // assign the handler to apply the auto-mapping logic
        ViveRole.AssignMapHandler(handler);
    }

    public bool TryGetEquipPosition(MyEquipRole role, out Vector3 pos)
    {
        pos = VivePose.GetPoseEx(role).pos;
        return VivePose.IsValidEx(role);
    }
}

Role Bindings

Binding feature allows overriding auto-mapping result. When a device serial number is bound to a role, the device with certain SN will force map to that role when it is connected. This can be performed in either Embedded Binding UI or bind manually in scripts.

// Bind "LHT-XXXXXXXXX" to BodyRole.LeftFoot
ViveRole.GetMap<BodyRole>().BindDeviceToRole("LHT-XXXXXXXXX", BodyRole.LeftFoot);