Skip to content

Instantly share code, notes, and snippets.

@sh-akira
Last active September 21, 2021 16:18
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sh-akira/1f3fdb2dad46b71cd215d2a045897bd3 to your computer and use it in GitHub Desktop.
Save sh-akira/1f3fdb2dad46b71cd215d2a045897bd3 to your computer and use it in GitHub Desktop.
SteamVR Plugin 2.xでVIVEトラッカーの役割設定からトラッカー位置を取得するサンプル(肘と膝を含む)
{
"actions": [
{
"name": "/actions/default/in/Pose",
"type": "pose"
},
{
"name": "/actions/default/in/SkeletonLeftHand",
"type": "skeleton",
"skeleton": "/skeleton/hand/left"
},
{
"name": "/actions/default/in/SkeletonRightHand",
"type": "skeleton",
"skeleton": "/skeleton/hand/right"
},
{
"name": "/actions/default/in/SelectButton",
"type": "boolean"
},
{
"name": "/actions/default/in/CancelButton",
"type": "boolean"
},
{
"name": "/actions/default/in/StickButton",
"type": "boolean"
},
{
"name": "/actions/default/in/MenuButton",
"type": "boolean"
},
{
"name": "/actions/default/in/TriggerButton",
"type": "boolean"
},
{
"name": "/actions/default/in/GripButton",
"type": "boolean"
},
{
"name": "/actions/default/in/StickAxis",
"type": "vector2"
},
{
"name": "/actions/default/out/Haptic",
"type": "vibration"
}
],
"action_sets": [
{
"name": "/actions/default",
"usage": "single"
}
],
"default_bindings": [
{
"controller_type": "vive_controller",
"binding_url": "bindings_vive_controller.json"
},
{
"controller_type": "oculus_touch",
"binding_url": "bindings_oculus_touch.json"
},
{
"controller_type": "knuckles",
"binding_url": "bindings_knuckles.json"
},
{
"controller_type": "holographic_controller",
"binding_url": "bindings_holographic_controller.json"
},
{
"controller_type": "vive_cosmos_controller",
"binding_url": "bindings_vive_cosmos_controller.json"
},
{
"controller_type": "vive_cosmos",
"binding_url": "binding_vive_cosmos.json"
},
{
"controller_type": "vive",
"binding_url": "binding_vive.json"
},
{
"controller_type": "indexhmd",
"binding_url": "binding_index_hmd.json"
},
{
"controller_type": "vive_pro",
"binding_url": "binding_vive_pro.json"
},
{
"controller_type": "rift",
"binding_url": "binding_rift.json"
},
{
"controller_type": "holographic_hmd",
"binding_url": "binding_holographic_hmd.json"
},
{
"controller_type": "vive_tracker_camera",
"binding_url": "binding_vive_tracker_camera.json"
},
{
"controller_type": "vive_tracker_chest",
"binding_url": "binding_vive_tracker_chest.json"
},
{
"controller_type": "vive_tracker_head",
"binding_url": "binding_vive_tracker_head.json"
},
{
"controller_type": "vive_tracker_left_elbow",
"binding_url": "binding_vive_tracker_left_elbow.json"
},
{
"controller_type": "vive_tracker_left_foot",
"binding_url": "binding_vive_tracker_left_foot.json"
},
{
"controller_type": "vive_tracker_left_hand",
"binding_url": "binding_vive_tracker_left_hand.json"
},
{
"controller_type": "vive_tracker_left_knee",
"binding_url": "binding_vive_tracker_left_knee.json"
},
{
"controller_type": "vive_tracker_left_shoulder",
"binding_url": "binding_vive_tracker_left_shoulder.json"
},
{
"controller_type": "vive_tracker_right_elbow",
"binding_url": "binding_vive_tracker_right_elbow.json"
},
{
"controller_type": "vive_tracker_right_foot",
"binding_url": "binding_vive_tracker_right_foot.json"
},
{
"controller_type": "vive_tracker_right_hand",
"binding_url": "binding_vive_tracker_right_hand.json"
},
{
"controller_type": "vive_tracker_right_knee",
"binding_url": "binding_vive_tracker_right_knee.json"
},
{
"controller_type": "vive_tracker_right_shoulder",
"binding_url": "binding_vive_tracker_right_shoulder.json"
},
{
"controller_type": "vive_tracker_waist",
"binding_url": "binding_vive_tracker_waist.json"
}
],
"localization": [
{
"language_tag": "en_US",
"/actions/default/in/Pose": "Pose",
"/actions/default/in/SkeletonLeftHand": "Skeleton (Left)",
"/actions/default/in/SkeletonRightHand": "Skeleton (Right)",
"/actions/default/out/Haptic": "Haptic"
}
]
}
{
"alias_info" : {},
"bindings" : {
"/actions/default" : {
"poses" : [
{
"output" : "/actions/default/in/pose",
"path" : "/user/chest/pose/raw"
}
]
}
},
"controller_type" : "vive_tracker_chest",
"description" : "",
"name" : "Chest",
"options" : {},
"simulated_actions" : []
}
{
"alias_info" : {},
"bindings" : {
"/actions/default" : {
"poses" : [
{
"output" : "/actions/default/in/pose",
"path" : "/user/head/pose/raw"
}
]
}
},
"controller_type" : "vive_tracker_head",
"description" : "",
"name" : "Head",
"options" : {},
"simulated_actions" : []
}
{
"alias_info" : {},
"bindings" : {
"/actions/default" : {
"poses" : [
{
"output" : "/actions/default/in/pose",
"path" : "/user/elbow/left/pose/raw"
}
]
}
},
"controller_type" : "vive_tracker_left_elbow",
"description" : "",
"name" : "LeftElbow",
"options" : {},
"simulated_actions" : []
}
{
"alias_info" : {},
"bindings" : {
"/actions/default" : {
"poses" : [
{
"output" : "/actions/default/in/pose",
"path" : "/user/foot/left/pose/raw"
}
]
}
},
"controller_type" : "vive_tracker_left_foot",
"description" : "",
"name" : "LeftFoot",
"options" : {},
"simulated_actions" : []
}
{
"alias_info" : {},
"bindings" : {
"/actions/default" : {
"poses" : [
{
"output" : "/actions/default/in/pose",
"path" : "/user/hand/left/pose/raw"
}
]
}
},
"controller_type" : "vive_tracker_left_hand",
"description" : "",
"name" : "LeftHand",
"options" : {},
"simulated_actions" : []
}
{
"alias_info" : {},
"bindings" : {
"/actions/default" : {
"poses" : [
{
"output" : "/actions/default/in/pose",
"path" : "/user/knee/left/pose/raw"
}
]
}
},
"controller_type" : "vive_tracker_left_knee",
"description" : "",
"name" : "LeftKnee",
"options" : {},
"simulated_actions" : []
}
{
"alias_info" : {},
"bindings" : {
"/actions/default" : {
"poses" : [
{
"output" : "/actions/default/in/pose",
"path" : "/user/shoulder/left/pose/raw"
}
]
}
},
"controller_type" : "vive_tracker_left_shoulder",
"description" : "",
"name" : "LeftShoulder",
"options" : {},
"simulated_actions" : []
}
{
"alias_info" : {},
"bindings" : {
"/actions/default" : {
"poses" : [
{
"output" : "/actions/default/in/pose",
"path" : "/user/elbow/right/pose/raw"
}
]
}
},
"controller_type" : "vive_tracker_right_elbow",
"description" : "",
"name" : "RightElbow",
"options" : {},
"simulated_actions" : []
}
{
"alias_info" : {},
"bindings" : {
"/actions/default" : {
"poses" : [
{
"output" : "/actions/default/in/pose",
"path" : "/user/foot/right/pose/raw"
}
]
}
},
"controller_type" : "vive_tracker_right_foot",
"description" : "",
"name" : "RightFoot",
"options" : {},
"simulated_actions" : []
}
{
"alias_info" : {},
"bindings" : {
"/actions/default" : {
"poses" : [
{
"output" : "/actions/default/in/pose",
"path" : "/user/hand/right/pose/raw"
}
]
}
},
"controller_type" : "vive_tracker_right_hand",
"description" : "",
"name" : "RightHand",
"options" : {},
"simulated_actions" : []
}
{
"alias_info" : {},
"bindings" : {
"/actions/default" : {
"poses" : [
{
"output" : "/actions/default/in/pose",
"path" : "/user/knee/right/pose/raw"
}
]
}
},
"controller_type" : "vive_tracker_right_knee",
"description" : "",
"name" : "RightKnee",
"options" : {},
"simulated_actions" : []
}
{
"alias_info" : {},
"bindings" : {
"/actions/default" : {
"poses" : [
{
"output" : "/actions/default/in/pose",
"path" : "/user/shoulder/right/pose/raw"
}
]
}
},
"controller_type" : "vive_tracker_right_shoulder",
"description" : "",
"name" : "RightShoulder",
"options" : {},
"simulated_actions" : []
}
{
"alias_info" : {},
"bindings" : {
"/actions/default" : {
"poses" : [
{
"output" : "/actions/default/in/pose",
"path" : "/user/waist/pose/raw"
}
]
}
},
"controller_type" : "vive_tracker_waist",
"description" : "",
"name" : "Waist",
"options" : {},
"simulated_actions" : []
}
// SteamVR 2.x Tracker Role Pose Example
// MIT License
// Copyright (c) 2021 sh_akira
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using Valve.VR;
namespace akr.Avatar.Tracking
{
public class SteamVRTracker : MonoBehaviour
{
//外部からTransformを指定されたときはそちらをそのまま使用する。無い場合は自動で作成して割り当てる
public TrackerTarget[] TrackerTargets = new TrackerTarget[]
{
new TrackerTarget { TrackerPosition = TrackerPositions.Head },
new TrackerTarget { TrackerPosition = TrackerPositions.LeftHand },
new TrackerTarget { TrackerPosition = TrackerPositions.RightHand },
new TrackerTarget { TrackerPosition = TrackerPositions.Waist },
new TrackerTarget { TrackerPosition = TrackerPositions.LeftFoot },
new TrackerTarget { TrackerPosition = TrackerPositions.RightFoot },
new TrackerTarget { TrackerPosition = TrackerPositions.LeftElbow },
new TrackerTarget { TrackerPosition = TrackerPositions.RightElbow },
new TrackerTarget { TrackerPosition = TrackerPositions.LeftKnee },
new TrackerTarget { TrackerPosition = TrackerPositions.RightKnee },
};
// "/actions/default/in/Pose"
public SteamVR_Action_Pose PoseAction = SteamVR_Input.GetAction<SteamVR_Action_Pose>("Pose");
private static float framesAhead = 2;
private ETrackingUniverseOrigin universeOrigin = ETrackingUniverseOrigin.TrackingUniverseRawAndUncalibrated;
private uint poseActionData_size = 0;
private ulong actionHandle = 0;
// enum TrackerPositionsとstring InputSourcePathとの対応表
private readonly string[] TrackerPositionsToPath = new string[]
{
"/unrestricted",
OpenVR.k_pchPathUserHandLeft,
OpenVR.k_pchPathUserHandRight,
OpenVR.k_pchPathUserFootLeft,
OpenVR.k_pchPathUserFootRight,
OpenVR.k_pchPathUserShoulderLeft,
OpenVR.k_pchPathUserShoulderRight,
OpenVR.k_pchPathUserWaist,
OpenVR.k_pchPathUserChest,
OpenVR.k_pchPathUserHead,
OpenVR.k_pchPathUserGamepad,
OpenVR.k_pchPathUserCamera,
OpenVR.k_pchPathUserKeyboard,
OpenVR.k_pchPathUserTreadmill,
OpenVR.k_pchPathUserElbowLeft,
OpenVR.k_pchPathUserElbowRight,
OpenVR.k_pchPathUserKneeLeft,
OpenVR.k_pchPathUserKneeRight,
OpenVR.k_pchPathUserStylus,
};
/// <summary>
/// ActionのフルパスからHandle取得
/// </summary>
/// <param name="fullPath"></param>
/// <returns></returns>
private ulong GetActionHandle(string fullPath)
{
ulong newHandle = 0;
EVRInputError err = OpenVR.Input.GetActionHandle(fullPath.ToLowerInvariant(), ref newHandle);
if (err != EVRInputError.None)
Debug.LogError("GetActionHandle (" + fullPath.ToLowerInvariant() + ") error: " + err.ToString());
return newHandle;
}
/// <summary>
/// 指定したTrackerPositionsのInputSourceHandleを取得
/// </summary>
/// <param name="trackerPosition"></param>
/// <returns></returns>
private ulong GetTrackerInputSourceHandle(TrackerPositions trackerPosition)
=> GetTrackerInputSourceHandle(TrackerPositionsToPath[(int)trackerPosition]);
/// <summary>
/// 指定したInputSourcePathのInputSourceHandleを取得
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private ulong GetTrackerInputSourceHandle(string path)
{
ulong handle = 0;
EVRInputError err = OpenVR.Input.GetInputSourceHandle(path, ref handle);
if (err != EVRInputError.None)
Debug.LogError("GetInputSourceHandle (" + path + ") error: " + err.ToString());
return handle;
}
/// <summary>
/// 指定したInputSourceHandleからトラッカーのPoseを取得
/// </summary>
/// <param name="inputSourceHandle"></param>
/// <returns></returns>
private InputPoseActionData_t GetPoseByHandle(ulong inputSourceHandle)
{
var poseActionData = new InputPoseActionData_t();
EVRInputError err = OpenVR.Input.GetPoseActionDataRelativeToNow(actionHandle, universeOrigin, framesAhead * (Time.timeScale / SteamVR.instance.hmd_DisplayFrequency), ref poseActionData, poseActionData_size, inputSourceHandle);
if (err != EVRInputError.None)
{
Debug.LogError("GetPoseActionDataRelativeToNow error: " + err.ToString() + " ActionHandle: " + actionHandle.ToString() + ". Input source: " + inputSourceHandle.ToString());
}
return poseActionData;
}
private void Awake()
{
universeOrigin = SteamVR_Settings.instance.trackingSpace;
poseActionData_size = (uint)Marshal.SizeOf(typeof(InputPoseActionData_t));
}
private void Start()
{
actionHandle = GetActionHandle(PoseAction.fullPath);
foreach(var trackerTarget in TrackerTargets)
{
if (trackerTarget.TargetTransform == null)
{
var newTarget = new GameObject(trackerTarget.TrackerPosition.ToString());
newTarget.transform.SetParent(transform, false);
trackerTarget.TargetTransform = newTarget.transform;
}
trackerTarget.InputSourceHandle = GetTrackerInputSourceHandle(trackerTarget.TrackerPosition);
}
}
private void Update()
{
foreach (var trackerTarget in TrackerTargets)
{
var poseActionData = GetPoseByHandle(trackerTarget.InputSourceHandle);
if (poseActionData.bActive)
{
trackerTarget.TargetTransform.localPosition = poseActionData.pose.mDeviceToAbsoluteTracking.GetPosition();
trackerTarget.TargetTransform.localRotation = poseActionData.pose.mDeviceToAbsoluteTracking.GetRotation();
}
}
}
}
[Serializable]
public class TrackerTarget
{
public TrackerPositions TrackerPosition;
public Transform TargetTransform;
[NonSerialized]
public ulong InputSourceHandle;
}
/// <summary>
/// SteamVRで割り当て可能なトラッカー位置(拡張SteamVR_Input_Sources)
/// </summary>
public enum TrackerPositions
{
Any,
LeftHand,
RightHand,
LeftFoot,
RightFoot,
LeftShoulder,
RightShoulder,
Waist,
Chest,
Head,
Gameoad,
Camera,
Keyboard,
Treadmill,
LeftElbow,
RightElbow,
LeftKnee,
RightKnee,
Stylus,
}
}
@sh-akira
Copy link
Author

sh-akira commented Feb 1, 2021

最低限InのActionにPoseが追加されている必要があります。
image

@sh-akira
Copy link
Author

SteamVRの設定にはLeft KneeやRight Elbow設定が可能にもかかわらず、SteamVR Pluginに定義が存在しない為、拡張SteamVR_Input_Sourcesを自前で持っています。SteamVR Pluginには定義がないが、OpenVRの定義には存在しているので直接k_pchPathUserKneeLeft等を使用しています。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment