first commit

This commit is contained in:
2026-04-07 03:14:32 +03:00
commit b3992fec6b
1026 changed files with 366769 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
using System;
using System.Collections.Generic;
using UnityEngine;
namespace VirtualGrasp.Controllers
{
/**
* This is an external controller class that supports a Mouse controller as an external controller.
* Please refer to https://docs.virtualgrasp.com/controllers.html for the definition of an external controller for VG.
*/
[LIBVIRTUALGRASP_UNITY_SCRIPT]
[HelpURL("https://docs.virtualgrasp.com/unity_vg_cp_generic." + VG_Version.__VG_VERSION__ + ".html")]
public class VG_EC_Generic : VG_ExternalController
{
[Serializable]
public class HandMapping : VG_BoneMapping
{
public override void Initialize(int avatarID, VG_HandSide side)
{
base.Initialize(avatarID, side);
m_BoneToTransform = new Dictionary<int, Transform>()
{
{ 0, Hand_WristRoot },
{ 1, Hand_Thumb1 },
{ 2, Hand_Thumb2 },
{ 3, Hand_Thumb3 },
{ 4, Hand_Index1 },
{ 5, Hand_Index2 },
{ 6, Hand_Index3 },
{ 7, Hand_Middle1 },
{ 8, Hand_Middle2 },
{ 9, Hand_Middle3 },
{ 10, Hand_Ring1 },
{ 11, Hand_Ring2 },
{ 12, Hand_Ring3 },
{ 13, Hand_Pinky1 },
{ 14, Hand_Pinky2 },
{ 15, Hand_Pinky3 }
};
}
}
public VG_EC_Generic(int avatarID, VG_HandSide side, Transform origin)
{
m_avatarID = avatarID;
m_handType = side;
m_origin = origin;
m_zeroOffsets = true; // the generic hand works on the Unity transforms, so it can't use offsets.
Initialize();
}
public new void Initialize()
{
m_mapping = new HandMapping();
base.Initialize();
m_enabled = true;
}
public override bool Compute()
{
for (int bone = 0; bone < m_mapping.GetNumBones(); bone++)
{
if (!m_mapping.GetTransform(bone, out Transform pose)) continue;
SetPose(bone, Matrix4x4.TRS(pose.position, pose.rotation, Vector3.one));
}
return true;
}
public override float GetGrabStrength()
{
return 0.0f;
}
public override Color GetConfidence()
{
return Color.yellow;
}
public override void HapticPulse(VG_HandStatus hand, float amplitude = 0.5F, float duration = 0.015F, int finger = 5)
{
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8ba28b8b076ea2a45a4f03b9f332ec23
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,205 @@
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
//#define VG_USE_LEAP_CONTROLLER
using System;
using System.Collections.Generic;
using UnityEngine;
#if VG_USE_LEAP_CONTROLLER
using Leap.Unity;
#endif
namespace VirtualGrasp.Controllers
{
/**
* This is an external controller class that supports the LeapMotion controller as an external controller.
* Please refer to https://docs.virtualgrasp.com/controllers.html for the definition of an external controller for VG.
*
* The following requirements have to be met to be able to enable the #define VG_USE_LEAP_CONTROLLER above and use the controller:
* - You have a Core Assets plugin from https://developer.leapmotion.com/unity imported into your Unity project.
* - Note that Core Assets > 4.4.0 are for LeapMotion SDK 4, older are for LeapMotion SDK 3 (lastest CA 4.3.4).
* - You have the corresponding LeapMotion SDK (https://developer.leapmotion.com/sdk-leap-motion-controller/) installed on your computer.
*/
[LIBVIRTUALGRASP_UNITY_SCRIPT]
[HelpURL("https://docs.virtualgrasp.com/unity_vg_ec_leap." + VG_Version.__VG_VERSION__ + ".html")]
public class VG_EC_Leap : VG_ExternalController
{
#if VG_USE_LEAP_CONTROLLER
static LeapProvider m_provider = null;
Leap.Hand m_hand = null;
static public int LeapBoneToInt(int finger, int bone)
{
return 4 * finger + bone + 1;
}
static public int LeapBoneToInt(Leap.Finger.FingerType finger, Leap.Bone.BoneType bone)
{
return LeapBoneToInt((int)finger, (int)bone);
}
static public void IntToLeapBone(int id, out int finger, out Leap.Bone.BoneType bone)
{
bone = (Leap.Bone.BoneType)((id - 1) % 4);
finger = (id - (int)bone) / 4;
}
#endif
[Serializable]
public class HandMapping : VG_BoneMapping
{
public override void Initialize(int avatarID, VG_HandSide side)
{
base.Initialize(avatarID, side);
m_BoneToTransform = new Dictionary<int, Transform>()
{
#if VG_USE_LEAP_CONTROLLER
{ 0, Hand_WristRoot },
{ LeapBoneToInt(0, 0), null },
{ LeapBoneToInt(0, 1), Hand_Thumb1 },
{ LeapBoneToInt(0, 2), Hand_Thumb2 },
{ LeapBoneToInt(0, 3), Hand_Thumb3 },
{ LeapBoneToInt(1, 0), null },
{ LeapBoneToInt(1, 1), Hand_Index1 },
{ LeapBoneToInt(1, 2), Hand_Index2 },
{ LeapBoneToInt(1, 3), Hand_Index3 },
{ LeapBoneToInt(2, 0), null },
{ LeapBoneToInt(2, 1), Hand_Middle1 },
{ LeapBoneToInt(2, 2), Hand_Middle2 },
{ LeapBoneToInt(2, 3), Hand_Middle3 },
{ LeapBoneToInt(3, 0), null },
{ LeapBoneToInt(3, 1), Hand_Ring1 },
{ LeapBoneToInt(3, 2), Hand_Ring2 },
{ LeapBoneToInt(3, 3), Hand_Ring3 },
{ LeapBoneToInt(4, 0), null },
{ LeapBoneToInt(4, 1), Hand_Pinky1 },
{ LeapBoneToInt(4, 2), Hand_Pinky2 },
{ LeapBoneToInt(4, 3), Hand_Pinky3 }
#endif
};
m_BoneToParent = new Dictionary<int, int>()
{
};
#if VG_USE_LEAP_CONTROLLER
m_BoneToParent[LeapBoneToInt(0, 0)] = 0;
m_BoneToParent[LeapBoneToInt(0, 1)] = LeapBoneToInt(0, 0);
m_BoneToParent[LeapBoneToInt(0, 2)] = LeapBoneToInt(0, 1);
m_BoneToParent[LeapBoneToInt(0, 3)] = LeapBoneToInt(0, 2);
m_BoneToParent[LeapBoneToInt(1, 0)] = 0;
m_BoneToParent[LeapBoneToInt(1, 1)] = LeapBoneToInt(1, 0);
m_BoneToParent[LeapBoneToInt(1, 2)] = LeapBoneToInt(1, 1);
m_BoneToParent[LeapBoneToInt(1, 3)] = LeapBoneToInt(1, 2);
m_BoneToParent[LeapBoneToInt(2, 0)] = 0;
m_BoneToParent[LeapBoneToInt(2, 1)] = LeapBoneToInt(2, 0);
m_BoneToParent[LeapBoneToInt(2, 2)] = LeapBoneToInt(2, 1);
m_BoneToParent[LeapBoneToInt(2, 3)] = LeapBoneToInt(2, 2);
m_BoneToParent[LeapBoneToInt(3, 0)] = 0;
m_BoneToParent[LeapBoneToInt(3, 1)] = LeapBoneToInt(3, 0);
m_BoneToParent[LeapBoneToInt(3, 2)] = LeapBoneToInt(3, 1);
m_BoneToParent[LeapBoneToInt(3, 3)] = LeapBoneToInt(3, 2);
m_BoneToParent[LeapBoneToInt(4, 0)] = 0;
m_BoneToParent[LeapBoneToInt(4, 1)] = LeapBoneToInt(4, 0);
m_BoneToParent[LeapBoneToInt(4, 2)] = LeapBoneToInt(4, 1);
m_BoneToParent[LeapBoneToInt(4, 3)] = LeapBoneToInt(4, 2);
#endif
}
}
public VG_EC_Leap(int avatarID, VG_HandSide side, Transform origin)
{
m_avatarID = avatarID;
m_handType = side;
m_origin = origin;
m_enablingDefine = "VG_USE_LEAP_CONTROLLER";
#if VG_USE_LEAP_CONTROLLER
m_enabled = true;
#else
PrintNotEnabledError();
m_enabled = false;
#endif
}
public new void Initialize()
{
#if VG_USE_LEAP_CONTROLLER
if (m_provider == null)
{
m_provider = GameObject.FindObjectOfType<VG_MainScript>().gameObject.AddComponent<LeapServiceProvider>();
}
if (m_provider != null)
{
m_mapping = new HandMapping();
base.Initialize();
}
m_initialized = (m_provider != null);
#endif
}
public override bool Compute()
{
#if VG_USE_LEAP_CONTROLLER
if (!m_enabled) return false;
if (!m_initialized || m_mapping == null) { Initialize(); return false; }
if (m_provider == null) return false;
Leap.Frame frame = m_provider.CurrentFrame;
if (frame == null) return false;
m_hand = null;
foreach (Leap.Hand hand in frame.Hands)
{
if (hand.IsLeft && m_handType == VG_HandSide.LEFT) { m_hand = hand; break; }
if (!hand.IsLeft && m_handType == VG_HandSide.RIGHT) { m_hand = hand; break; }
}
if (m_hand == null) return false;
for (int boneId = 0; boneId < GetNumBones(); boneId++)
{
if (boneId == 0)
{
SetPose(boneId, Matrix4x4.TRS(m_hand.WristPosition, m_hand.Rotation, Vector3.one));
}
else
{
IntToLeapBone(boneId, out int finger, out Leap.Bone.BoneType bone);
Leap.Bone b = m_hand.Fingers[finger].Bone(bone);
SetPose(boneId, Matrix4x4.TRS(b.NextJoint, b.Rotation, Vector3.one));
}
}
return true;
#else
return false;
#endif
}
public override float GetGrabStrength()
{
#if VG_USE_LEAP_CONTROLLER
// Get grab strength from Leap if available
//return m_hand != null ? m_hand.GrabStrength : 0.0f;
return -1.0f; // let VG decide from full DOF
#else
return 0.0f;
#endif
}
public override Color GetConfidence()
{
#if VG_USE_LEAP_CONTROLLER
if (m_hand != null) return Color.black;
return m_hand.Confidence > 0.5f ? Color.green : Color.red;
#else
return Color.yellow;
#endif
}
public override void HapticPulse(VG_HandStatus hand, float amplitude = 0.5F, float duration = 0.015F, int finger = 5)
{
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c735f357c234e0b4e9a5c8db5e88f37c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,413 @@
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
//#define VG_USE_MANUS_CONTROLLER
using System;
using System.Collections.Generic;
using UnityEngine;
#if VG_USE_MANUS_CONTROLLER
using System.Linq;
using Manus;
using Manus.Skeletons;
using Manus.Utility;
#endif
namespace VirtualGrasp.Controllers
{
/**
* This is an external controller class that supports the Manus Glove controller as an external controller.
* Please refer to https://docs.virtualgrasp.com/controllers.html for the definition of an external controller for VG.
*
* The following requirements have to be met to be able to enable the #define VG_USE_MANUS_CONTROLLER above and use the controller:
* - You have the corresponding Manus Core SDK (https://resources.manus-meta.com/downloads) installed on your computer.
* - You have the Unity Plugin for Manus Core from https://resources.manus-meta.com/downloads imported into your Unity project.
* - You have a Manus Pro License assigned to your SDK to use the Unity Plugin.
*/
[LIBVIRTUALGRASP_UNITY_SCRIPT]
[HelpURL("https://docs.virtualgrasp.com/unity_vg_ec_manus." + VG_Version.__VG_VERSION__ + ".html")]
public class VG_EC_Manus : VG_ExternalController
{
#if VG_USE_MANUS_CONTROLLER
private Skeleton m_skeleton = null;
private CoreSDK.SkeletonStream m_skeletonData;
private int m_id = -1;
private static uint MANUS_SKELETON_ID = 0;
private void onSkeletonData(CoreSDK.SkeletonStream data)
{
m_skeletonData = data;
}
protected void IntFromManusBone(uint nodeId, out int boneId)
{
boneId = (int)nodeId;
}
static private void PrintNode(CoreSDK.SkeletonNode node)
{
Debug.Log("CNode " + node.ToString());
}
static private void PrintNode(Node node)
{
Debug.Log("Node " + node.id + " (" + node.name + "|" + node.nodeName + ")" +
node.unityTransform.name + " (type: " + node.type + "; parent: " + node.parentID + ")"
);
}
static private void PrintChain(Chain chain)
{
string str = "";
foreach (uint id in chain.nodeIds)
str += id + ",";
Debug.Log("Chain " + chain.id + " (" + chain.name + "|" + chain.dataSide + ")"
+ " (type: " + chain.type + "; hand: " + chain.settings.finger.handChainId + "); meta " + chain.settings.finger.metacarpalBoneId
+ "; " + str);
}
#endif
[Serializable]
public class HandMapping : VG_BoneMapping
{
public override void Initialize(int avatarID, VG_HandSide side)
{
base.Initialize(avatarID, side);
m_BoneToTransform = new Dictionary<int, Transform>()
{
#if VG_USE_MANUS_CONTROLLER
{ 0, Hand_WristRoot },
{ 1, Hand_Thumb1 },
{ 2, Hand_Thumb2 },
{ 3, Hand_Thumb3 },
{ 4, null },
{ 5, null },
{ 6, Hand_Index1 },
{ 7, Hand_Index2 },
{ 8, Hand_Index3 },
{ 9, null },
{ 10, null },
{ 11, Hand_Middle1 },
{ 12, Hand_Middle2 },
{ 13, Hand_Middle3 },
{ 14, null },
{ 15, null },
{ 16, Hand_Ring1 },
{ 17, Hand_Ring2 },
{ 18, Hand_Ring3 },
{ 19, null },
{ 20, null },
{ 21, Hand_Pinky1 },
{ 22, Hand_Pinky2 },
{ 23, Hand_Pinky3 },
{ 24, null },
#endif
};
m_BoneToParent = new Dictionary<int, int>()
{
};
#if VG_USE_MANUS_CONTROLLER
m_BoneToParent[0] = -1;
m_BoneToParent[1] = 0;
m_BoneToParent[2] = 1;
m_BoneToParent[3] = 2;
m_BoneToParent[4] = 3;
m_BoneToParent[5] = 0;
m_BoneToParent[6] = 5;
m_BoneToParent[7] = 6;
m_BoneToParent[8] = 7;
m_BoneToParent[9] = 8;
m_BoneToParent[10] = 0;
m_BoneToParent[11] = 10;
m_BoneToParent[12] = 11;
m_BoneToParent[13] = 12;
m_BoneToParent[14] = 13;
m_BoneToParent[15] = 0;
m_BoneToParent[16] = 15;
m_BoneToParent[17] = 16;
m_BoneToParent[18] = 17;
m_BoneToParent[19] = 18;
m_BoneToParent[20] = 0;
m_BoneToParent[21] = 20;
m_BoneToParent[22] = 21;
m_BoneToParent[23] = 22;
m_BoneToParent[24] = 23;
#endif
}
#if VG_USE_MANUS_CONTROLLER
// Function to setup nodes for metacarpals and tips properly in Manus SDK.
// (They are not considered in VG controllers.)
private void FillUnassignedNodes(List<Node> nodes)
{
for (int nodeId = 0; nodeId < nodes.Count; nodeId++)
{
Node node = nodes[nodeId];
if (node.unityTransform == null)
{
// metacarpals
if (new List<int>() { 5, 10, 15, 20 }.Contains(nodeId))
{
Node next_node = nodes[nodeId + 1];
node.unityTransform = next_node.unityTransform.parent;
node.nodeName = (node.unityTransform == null) ? "n/a" : node.unityTransform.name;
node.name = node.nodeName;
}
else // tips
{
Node prev_node = nodes[nodeId - 1];
node.unityTransform = prev_node.unityTransform.GetChild(0);
node.nodeName = (node.unityTransform == null) ? "n/a" : node.unityTransform.name;
node.name = node.nodeName;
}
}
}
}
private bool ComputeFingerChainIds(out List<uint> chainIds)
{
chainIds = new List<uint>();
foreach (Transform child in Hand_WristRoot.transform)
{
List<Transform> children = child.GetComponentsInChildren<Transform>().ToList<Transform>();
if (children.Contains(Hand_Thumb1))
chainIds.Add(2);
else if (children.Contains(Hand_Index1))
chainIds.Add(3);
else if (children.Contains(Hand_Middle1))
chainIds.Add(4);
else if (children.Contains(Hand_Ring1))
chainIds.Add(5);
else if (children.Contains(Hand_Pinky1))
chainIds.Add(6);
// Check if we have properly ordered fingers.
int count = chainIds.Count;
if (count > 1 && chainIds[count - 1] < chainIds[count - 2])
return false;
}
return true;
}
public bool FillSkeletonFromMapping(Skeleton skeleton, VG_HandSide side)
{
skeleton.skeletonData = new SkeletonData();
skeleton.skeletonData.type = CoreSDK.SkeletonType.Hand;
skeleton.skeletonData.name = skeleton.name;
skeleton.skeletonData.settings.targetType = CoreSDK.SkeletonTargetType.UserIndexData;
skeleton.skeletonData.nodes.Clear();
skeleton.skeletonData.chains.Clear();
// Hand chain
Chain chain1 = new Chain();
chain1.id = 1;
chain1.type = CoreSDK.ChainType.Hand;
chain1.appliedDataType = chain1.type;
chain1.dataSide = (side == VG_HandSide.LEFT) ? CoreSDK.Side.Left : CoreSDK.Side.Right;
chain1.nodeIds.Add(0);
chain1.settings.finger.handChainId = 0;
chain1.settings.finger.metacarpalBoneId = 0;
chain1.settings.hand.fingerChainIds = new[] { 2, 3, 4, 5, 6 };
skeleton.skeletonData.chains.Add(chain1);
// Add all nodes from VG mapping.
foreach (KeyValuePair<int, Transform> boneTransform in m_BoneToTransform)
{
Node node = new Node();
node.unityTransform = boneTransform.Value;
node.nodeName = (node.unityTransform == null) ? "n/a" : node.unityTransform.name;
node.name = node.nodeName;
node.type = CoreSDK.NodeType.Joint;
node.id = (uint)boneTransform.Key;
node.parentID = m_BoneToParent.ContainsKey(boneTransform.Key) ?
(uint)m_BoneToParent[boneTransform.Key] : 0;
node.transform = new TransformValues();
node.transform.scale = Vector3.one;
skeleton.skeletonData.nodes.Add(node);
}
// Fill in nodes for bones that don't exist in VG skeleton
FillUnassignedNodes(skeleton.skeletonData.nodes);
// Finger chains (chain to bones)
// Note: the chains need to be exactly ordered as in the hierarchy.
if (!ComputeFingerChainIds(out List<uint> chainIds))
{
Debug.LogError($"Please assure that the finger chains (children of {Hand_WristRoot.name}) are sorted as:" +
"(Thumb, Index, Middle, Ring, Pinky)", Hand_WristRoot);
return false;
}
foreach (uint chainId in chainIds)
{
Chain chain = new Chain();
chain.name = "Finger " + chainId;
chain.id = chainId;
chain.type = (CoreSDK.ChainType)chainId + 3;
chain.appliedDataType = chain.type;
chain.dataSide = (side == VG_HandSide.LEFT) ? CoreSDK.Side.Left : CoreSDK.Side.Right;
chain.nodeIds = new List<uint>();
chain.settings.finger.handChainId = 1;
if (chainId == 2) // thumb
{
chain.settings.finger.metacarpalBoneId = -1;
chain.nodeIds = new List<uint> { 1, 2, 3, 4 };
}
else
{
chain.settings.finger.metacarpalBoneId = (int)(5 * (chainId - 2));
chain.nodeIds = new List<uint>();
for (int i = chain.settings.finger.metacarpalBoneId; i < chain.settings.finger.metacarpalBoneId + 5; i++)
chain.nodeIds.Add((uint)i);
}
skeleton.skeletonData.chains.Add(chain);
}
/*
// Just for debugging
foreach (Node node in skeleton.skeletonData.nodes)
PrintNode(node);
foreach (Chain chain in skeleton.skeletonData.chains)
PrintChain(chain);
*/
return true;
}
#endif
}
public VG_EC_Manus(int avatarID, VG_HandSide side, Transform origin)
{
m_avatarID = avatarID;
m_handType = side;
m_origin = origin;
m_enablingDefine = "VG_USE_MANUS_CONTROLLER";
#if VG_USE_MANUS_CONTROLLER
m_enabled = true;
#else
PrintNotEnabledError();
m_enabled = false;
#endif
}
public new void Initialize()
{
#if VG_USE_MANUS_CONTROLLER
if (m_mapping == null)
{
m_mapping = new HandMapping();
base.Initialize();
}
// Note: need to disable GO first so Skeleton constructor does not fail
// due to uninitialized data structures (FillSkeletonFromMapping).
GameObject go = m_mapping.Hand_WristRoot.gameObject;
bool oldActive = go.activeSelf;
go.SetActive(false);
if (!go.TryGetComponent<Skeleton>(out m_skeleton))
m_skeleton = go.AddComponent<Skeleton>();
// Note: paused needs to be modified to public so Manus API does not apply bone poses,
// but let's VG do this.
m_skeleton.m_Paused = true;
m_initialized = false;
if (!(m_mapping as HandMapping).FillSkeletonFromMapping(m_skeleton, m_handType))
{
this.m_enabled = false;
return;
}
try { go.SetActive(oldActive); }
catch (Exception) { return; }
// Note: ManusManager is static and managing the gloves
m_skeleton.SetupMeshes();
m_skeleton.SetupNodes();
m_skeleton.SendSkeleton();
m_skeleton.skeletonData.id = MANUS_SKELETON_ID++;
m_id = (int)m_skeleton.skeletonData.id;
ManusManager.communicationHub?.onSkeletonData.AddListener(this.onSkeletonData);
m_initialized = true;
#endif
}
public override bool Compute()
{
#if VG_USE_MANUS_CONTROLLER
if (!m_enabled) return false;
if (!m_initialized || m_mapping == null) { Initialize(); return false; }
if (m_skeletonData.skeletons == null || m_skeletonData.skeletons.Count == 0) return false;
foreach (CoreSDK.SkeletonNode node in m_skeletonData.skeletons[m_id].nodes)
{
IntFromManusBone(node.id, out int boneId);
//Debug.Log("VG " + m_handType + ":" + m_id + " (" + boneId + "/" + GetNumBones() + "); MAN: " + node.id + "/" + m_skeletonData.skeletons[0].nodes.Length + "):\n" + node.transform.rotation.FromManus());
if (boneId == 0)
{
SetPose(boneId, Matrix4x4.TRS(
node.transform.position.FromManus(),
node.transform.rotation.FromManus().normalized,
Vector3.one));
}
else
{
SetPose(boneId, m_poses[m_mapping.GetParent(boneId)] *
Matrix4x4.TRS(
node.transform.position.FromManus(),
node.transform.rotation.FromManus().normalized,
Vector3.one));
}
}
return true;
#else
return false;
#endif
}
public override float GetGrabStrength()
{
#if VG_USE_MANUS_CONTROLLER
// No grab strength from Manus API is available, so
// let VG decide from full DOF.
return -1.0f;
#else
return 0.0f;
#endif
}
public override Color GetConfidence()
{
#if VG_USE_MANUS_CONTROLLER
// No confidence value of the tracked data in Manus API.
return Color.yellow;
#else
return Color.yellow;
#endif
}
public override void HapticPulse(VG_HandStatus hand, float amplitude = 0.5F, float duration = 0.015F, int finger = 5)
{
#if VG_USE_MANUS_CONTROLLER
float[] amplitudes = new float[] { amplitude, amplitude, amplitude, amplitude, amplitude};
ManusManager.communicationHub?.SendHapticDataForSkeleton(m_skeleton.skeletonData.id, m_handType == VG_HandSide.LEFT ? CoreSDK.Side.Left : CoreSDK.Side.Right, amplitudes);
#endif
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 506abf992f64c0845b2a9c27d0f3e8fc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,109 @@
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
using System;
using System.Collections.Generic;
using UnityEngine;
#if VG_ENABLE_INPUT_SYSTEM // && !ENABLE_LEGACY_INPUT_MANAGER
using UnityEngine.InputSystem;
#endif
namespace VirtualGrasp.Controllers
{
/**
* This is an external controller class that supports a Mouse controller as an external controller.
* Please refer to https://docs.virtualgrasp.com/controllers.html for the definition of an external controller for VG.
*/
[LIBVIRTUALGRASP_UNITY_SCRIPT]
[HelpURL("https://docs.virtualgrasp.com/unity_vg_ec_mouse." + VG_Version.__VG_VERSION__ + ".html")]
public class VG_EC_Mouse : VG_ExternalController
{
private int mouse_held = 0;
private int filter = 15;
private float depth = .5f;
private Vector3 rotation = Vector3.zero;
#if VG_ENABLE_INPUT_SYSTEM
private float rotationSpeed = 0.5f;
#endif
[Serializable]
public class HandMapping : VG_BoneMapping
{
public override void Initialize(int avatarID, VG_HandSide side)
{
base.Initialize(avatarID, side);
m_BoneToTransform = new Dictionary<int, Transform>()
{
{ 0, Hand_WristRoot }
};
}
}
public VG_EC_Mouse(int avatarID, VG_HandSide side, Transform origin)
{
m_avatarID = avatarID;
m_handType = side;
m_origin = origin;
m_enabled = true;
}
public new void Initialize()
{
m_initialized = (Camera.main != null);
if (!m_initialized) return;
m_mapping = new HandMapping();
base.Initialize();
if (Camera.main.stereoTargetEye != StereoTargetEyeMask.None)
{
Debug.LogWarning("VG_EC_MouseHand uses single GameView camera, but a stereo camera is activated. Deactivating Stereo view.");
Camera.main.stereoTargetEye = StereoTargetEyeMask.None;
}
}
public override bool Compute()
{
if (!m_enabled || !Application.isFocused) return false;
if (!m_initialized || m_mapping == null) { Initialize(); return false; }
#if VG_ENABLE_INPUT_SYSTEM // && !ENABLE_LEGACY_INPUT_MANAGER
if (Keyboard.current.leftShiftKey.isPressed && m_handType == VG_HandSide.RIGHT ||
Keyboard.current.rightShiftKey.isPressed && m_handType == VG_HandSide.LEFT)
return true;
if (Keyboard.current.xKey.IsPressed()) rotation.x += rotationSpeed;
if (Keyboard.current.yKey.IsPressed()) rotation.y += rotationSpeed;
if (Keyboard.current.zKey.IsPressed()) rotation.z += rotationSpeed;
if (m_handType == VirtualGrasp.VG_HandSide.LEFT ? Mouse.current.leftButton.isPressed : Mouse.current.rightButton.isPressed)
mouse_held = Mathf.Min(filter, mouse_held + 1);
else mouse_held = Mathf.Max(0, mouse_held - 1);
depth = Mathf.Clamp(depth + Mouse.current.scroll.y.ReadValue() / 100.0f, .01f, 1.0f);
Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
#else
if (Input.GetMouseButton(m_handType == VirtualGrasp.VG_HandSide.LEFT ? 0 : 1)) mouse_held = Mathf.Min(filter, mouse_held + 1);
else mouse_held = Mathf.Max(0, mouse_held - 1);
depth = Mathf.Clamp(depth + Input.mouseScrollDelta.y / 10.0f, .5f, 3.0f);
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
#endif
Quaternion q = Camera.main.transform.rotation;
Vector3 p = ray.origin + depth * ray.direction + q * (m_handType == VirtualGrasp.VG_HandSide.LEFT ? Vector3.left : Vector3.right) * .1f;
q = q * Quaternion.Euler(rotation);
SetPose(0, Matrix4x4.TRS(p, q, Vector3.one));
return true;
}
public override float GetGrabStrength()
{
return (float)mouse_held / filter;
}
public override Color GetConfidence()
{
return Color.yellow;
}
public override void HapticPulse(VG_HandStatus hand, float amplitude = 0.5F, float duration = 0.015F, int finger = 5)
{
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fb4ba4cb1ca48424ca180c73ac0d42cc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,115 @@
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
//#define VG_USE_OVRHAND_CONTROLLER // Please read below instructions and requirements before activating.
using UnityEngine;
namespace VirtualGrasp.Controllers
{
/**
* NOTE: this is an experimental controller only for the OculusIntegration sample.
* We recommend to not use OVRHand / OVRCustomSkeleton but use one of the
* various finger controllers that come with VirtualGrasp.
*
* This is an external controller class that supports a generic overlay controller for the OVRHand class as an external controller.
* Please refer to https://docs.virtualgrasp.com/controllers.html for the definition of an external controller for VG.
*
* The following requirements have to be met to be able to enable the #define VG_USE_OVRHAND_CONTROLLER above and use the controller:
* - You have the Oculus SDK (https://www.oculus.com/setup/) installed on your computer.
* - You have the Oculus Integration plugin from https://developer.oculus.com/downloads/package/unity-integration/ imported into your Unity project.
* - You are using a handmodel / rig that is based on the OVRHand / OVRCustomSkeleton classes.
*/
[LIBVIRTUALGRASP_UNITY_SCRIPT]
[HelpURL("https://docs.virtualgrasp.com/unity_vg_ec_ovr." + VG_Version.__VG_VERSION__ + ".html")]
public class VG_EC_OVR : VG_ExternalController
{
#if VG_USE_OVRHAND_CONTROLLER
private OVRCustomSkeleton m_skeleton = null;
private OVRHand m_hand = null;
#endif
public VG_EC_OVR(int avatarID, VG_HandSide side, Transform origin)
{
m_avatarID = avatarID;
m_handType = side;
m_zeroOffsets = true; // the generic hand works on the Unity transforms, so it can't use offsets.
m_origin = origin;
m_enablingDefine = "VG_USE_OVRHAND_CONTROLLER";
#if VG_USE_OVRHAND_CONTROLLER
Initialize();
m_enabled = true;
#else
PrintNotEnabledError();
m_enabled = false;
#endif
}
public new void Initialize()
{
m_mapping = new VG_EC_Oculus.HandMapping();
#if VG_USE_OVRHAND_CONTROLLER
foreach (OVRCustomSkeleton hand in GameObject.FindObjectsOfType<OVRCustomSkeleton>()) {
if (hand.GetSkeletonType() == OVRSkeleton.SkeletonType.HandLeft && m_handType == VG_HandSide.LEFT ||
hand.GetSkeletonType() == OVRSkeleton.SkeletonType.HandRight && m_handType == VG_HandSide.RIGHT) {
m_skeleton = hand;
m_hand = hand.gameObject.GetComponent<OVRHand>();
}
}
if (m_skeleton == null)
{
m_initialized = false;
return;
}
base.Initialize();
m_initialized = true;
#else
m_initialized = false;
#endif
}
public override bool Compute()
{
if (!m_enabled) return false;
if (!m_initialized) { Initialize(); return false; }
#if VG_USE_OVRHAND_CONTROLLER
if (!m_skeleton.IsDataValid) return false;
int offset = (int)m_skeleton.GetCurrentStartBoneId();
for (int bone = 0; bone < m_mapping.GetNumBones(); bone++)
{
Transform pose = (bone != 1) ?
m_skeleton.CustomBones[offset + bone].transform :
m_skeleton.CustomBones[offset].transform; // we map forearm stub to wrist
SetPose(bone, Matrix4x4.TRS(pose.position, pose.rotation, Vector3.one));
}
return true;
#else
return false;
#endif
}
public override float GetGrabStrength() {
#if VG_USE_OVRHAND_CONTROLLER
return -1.0f;
//return m_hand.GetFingerPinchStrength(OVRHand.HandFinger.Index);
#else
return -1.0f;
#endif
}
public override Color GetConfidence()
{
return Color.yellow;
}
public override void HapticPulse(VG_HandStatus hand, float amplitude = 0.5F, float duration = 0.015F, int finger = 5) {
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 65dd4ebfbffd7b740a91055a7bf4353f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,200 @@
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
//#define VG_USE_OCULUS_CONTROLLER // Please read below instructions and requirements before activating.
using System;
using System.Collections.Generic;
using UnityEngine;
namespace VirtualGrasp.Controllers
{
/**
* This is an external controller class that supports the Oculus Finger Tracking controller as an external controller.
* Please refer to https://docs.virtualgrasp.com/controllers.html for the definition of an external controller for VG.
*
* The following requirements have to be met to be able to enable the #define VG_USE_OCULUS_CONTROLLER above and use the controller:
* - You have the Oculus SDK (https://www.oculus.com/setup/) installed on your computer.
* - You have the Oculus Integration plugin from https://developer.oculus.com/downloads/package/unity-integration/ imported into your Unity project.
* - You have the same Oculus Integration plugin version as the one on your headset AND Oculus App.
* - You use Oculus through "Legacy OVR" (Oculus -> Tools -> OVR Utilitites Plugin -> Set OVR to Legacy LibOVR)
* - You have setup the AndroidManifest.xml properly, i.e. they need to include
* <uses-permission android:name="com.oculus.permission.HAND_TRACKING" />
* <uses-feature android:name="oculus.software.handtracking" android:required="false" />
*/
[LIBVIRTUALGRASP_UNITY_SCRIPT]
[HelpURL("https://docs.virtualgrasp.com/unity_vg_ec_oculus." + VG_Version.__VG_VERSION__ + ".html")]
public class VG_EC_Oculus : VG_ExternalController
{
#if VG_USE_OCULUS_CONTROLLER
private OVRPlugin.Skeleton m_skeleton = new OVRPlugin.Skeleton();
private OVRPlugin.HandState m_currentState = new OVRPlugin.HandState();
#endif
[Serializable]
public class HandMapping : VG_BoneMapping
{
public override void Initialize(int avatarID, VG_HandSide side)
{
base.Initialize(avatarID, side);
m_BoneToTransform = new Dictionary<int, Transform>() {
#if VG_USE_OCULUS_CONTROLLER
{ (int)OVRPlugin.BoneId.Hand_WristRoot, Hand_WristRoot },
{ (int)OVRPlugin.BoneId.Hand_ForearmStub, null }, // this is a child of wrist, but towards the arm
{ (int)OVRPlugin.BoneId.Hand_Thumb0, null },
{ (int)OVRPlugin.BoneId.Hand_Thumb1, Hand_Thumb1 },
{ (int)OVRPlugin.BoneId.Hand_Thumb2, Hand_Thumb2 },
{ (int)OVRPlugin.BoneId.Hand_Thumb3, Hand_Thumb3 },
{ (int)OVRPlugin.BoneId.Hand_Index1, Hand_Index1 },
{ (int)OVRPlugin.BoneId.Hand_Index2, Hand_Index2 },
{ (int)OVRPlugin.BoneId.Hand_Index3, Hand_Index3 },
{ (int)OVRPlugin.BoneId.Hand_Middle1, Hand_Middle1 },
{ (int)OVRPlugin.BoneId.Hand_Middle2, Hand_Middle2 },
{ (int)OVRPlugin.BoneId.Hand_Middle3, Hand_Middle3 },
{ (int)OVRPlugin.BoneId.Hand_Ring1, Hand_Ring1 },
{ (int)OVRPlugin.BoneId.Hand_Ring2, Hand_Ring2 },
{ (int)OVRPlugin.BoneId.Hand_Ring3, Hand_Ring3 },
{ (int)OVRPlugin.BoneId.Hand_Pinky0, null },
{ (int)OVRPlugin.BoneId.Hand_Pinky1, Hand_Pinky1 },
{ (int)OVRPlugin.BoneId.Hand_Pinky2, Hand_Pinky2 },
{ (int)OVRPlugin.BoneId.Hand_Pinky3, Hand_Pinky3 },
{ (int)OVRPlugin.BoneId.Hand_ThumbTip, null },
{ (int)OVRPlugin.BoneId.Hand_IndexTip, null },
{ (int)OVRPlugin.BoneId.Hand_MiddleTip, null },
{ (int)OVRPlugin.BoneId.Hand_RingTip, null },
{ (int)OVRPlugin.BoneId.Hand_PinkyTip, null }
#endif
};
m_BoneToParent = new Dictionary<int, int>();
#if VG_USE_OCULUS_CONTROLLER
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_ForearmStub] = (int)OVRPlugin.BoneId.Hand_WristRoot;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_Thumb0] = (int)OVRPlugin.BoneId.Hand_WristRoot;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_Thumb1] = (int)OVRPlugin.BoneId.Hand_Thumb0;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_Thumb2] = (int)OVRPlugin.BoneId.Hand_Thumb1;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_Thumb3] = (int)OVRPlugin.BoneId.Hand_Thumb2;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_ThumbTip] = (int)OVRPlugin.BoneId.Hand_Thumb3;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_Index1] = (int)OVRPlugin.BoneId.Hand_WristRoot;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_Index2] = (int)OVRPlugin.BoneId.Hand_Index1;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_Index3] = (int)OVRPlugin.BoneId.Hand_Index2;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_IndexTip] = (int)OVRPlugin.BoneId.Hand_Index3;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_Middle1] = (int)OVRPlugin.BoneId.Hand_WristRoot;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_Middle2] = (int)OVRPlugin.BoneId.Hand_Middle1;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_Middle3] = (int)OVRPlugin.BoneId.Hand_Middle2;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_MiddleTip] = (int)OVRPlugin.BoneId.Hand_Middle3;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_Ring1] = (int)OVRPlugin.BoneId.Hand_WristRoot;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_Ring2] = (int)OVRPlugin.BoneId.Hand_Ring1;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_Ring3] = (int)OVRPlugin.BoneId.Hand_Ring2;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_RingTip] = (int)OVRPlugin.BoneId.Hand_Ring3;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_Pinky0] = (int)OVRPlugin.BoneId.Hand_WristRoot;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_Pinky1] = (int)OVRPlugin.BoneId.Hand_Pinky0;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_Pinky2] = (int)OVRPlugin.BoneId.Hand_Pinky1;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_Pinky3] = (int)OVRPlugin.BoneId.Hand_Pinky2;
m_BoneToParent[(int)OVRPlugin.BoneId.Hand_PinkyTip] = (int)OVRPlugin.BoneId.Hand_Pinky3;
#endif
}
}
public VG_EC_Oculus(int avatarID, VG_HandSide side, Transform origin)
{
m_avatarID = avatarID;
m_handType = side;
m_origin = origin;
m_enablingDefine = "VG_USE_OCULUS_CONTROLLER";
#if VG_USE_OCULUS_CONTROLLER
m_enabled = true;
#else
PrintNotEnabledError();
m_enabled = false;
#endif
}
public new void Initialize()
{
#if VG_USE_OCULUS_CONTROLLER
m_mapping = new HandMapping();
if (OVRPlugin.GetSkeleton(
(m_handType == VG_HandSide.LEFT) ? OVRPlugin.SkeletonType.HandLeft :
(m_handType == VG_HandSide.RIGHT) ? OVRPlugin.SkeletonType.HandRight : OVRPlugin.SkeletonType.None,
out m_skeleton))
{
base.Initialize();
m_initialized = true;
}
else m_initialized = false;
#endif
}
public override float GetGrabStrength()
{
#if VG_USE_OCULUS_CONTROLLER
if (m_initialized && m_currentState.Status.HasFlag(OVRPlugin.HandStatus.HandTracked))
return -1.0f; // let VG decide from full DOF
//return (m_currentState.PinchStrength[0] + m_currentState.PinchStrength[1] + m_currentState.PinchStrength[2]) / 3.0f;
#endif
return 0.0f;
}
private bool IsTracking()
{
#if VG_USE_OCULUS_CONTROLLER
return OVRPlugin.GetHandState(OVRPlugin.Step.Render, m_handType == VG_HandSide.LEFT ? OVRPlugin.Hand.HandLeft : OVRPlugin.Hand.HandRight, ref m_currentState)
&& m_currentState.Status.HasFlag(OVRPlugin.HandStatus.HandTracked);
#else
return false;
#endif
}
public override bool Compute()
{
if (!m_enabled) return false;
if (!m_initialized) { Initialize(); return false; }
#if VG_USE_OCULUS_CONTROLLER
if (!IsTracking()) return false;
for (int boneId = 0; boneId < GetNumBones(); ++boneId)
{
if (boneId == 0)
{
SetPose(boneId, Matrix4x4.TRS(
m_currentState.RootPose.Position.FromFlippedZVector3f(),
m_currentState.RootPose.Orientation.FromFlippedZQuatf(),
Vector3.one));
}
else SetPose(boneId, m_poses[m_mapping.GetParent(boneId)] *
Matrix4x4.TRS(
m_skeleton.Bones[boneId].Pose.Position.FromFlippedZVector3f(),
m_currentState.BoneRotations[boneId].FromFlippedZQuatf(),
Vector3.one));
}
return true;
#else
return false;
#endif
}
public override Color GetConfidence()
{
#if VG_USE_OCULUS_CONTROLLER
if (!m_initialized) return Color.black;
switch (m_currentState.HandConfidence)
{
case OVRPlugin.TrackingConfidence.High:
return Color.green;
case OVRPlugin.TrackingConfidence.Low:
return Color.red;
}
#endif
return Color.black;
}
public override void HapticPulse(VG_HandStatus hand, float amplitude = 0.5F, float duration = 0.015F, int finger = 5)
{
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a6adfc75fbb3e8944a213eb006c326c6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,90 @@
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using UnityEngine;
namespace VirtualGrasp.Controllers
{
/**
* This is an external controller class that supports a Script/GUI controller as an external controller.
* Please refer to https://docs.virtualgrasp.com/controllers.html for the definition of an external controller for VG.
*/
[LIBVIRTUALGRASP_UNITY_SCRIPT]
[HelpURL("https://docs.virtualgrasp.com/unity_vg_ec_script." + VG_Version.__VG_VERSION__ + ".html")]
public class VG_EC_Script : VG_ExternalController
{
private Transform m_wrist = null;
private float m_grabStrength = 0.0f;
/**
* The wrist transform strength can be set and received from another Script/GUI.
* Changes in the wrist transform will affect the controller through Compute().
*/
public Transform WristTransform
{
get { return m_wrist; }
set { m_wrist = value; }
}
/**
* The grab strength can be set and received from another Script/GUI.
* Changes in the grab strength will affect the controller through GetGrabStrength().
*/
public float GrabStrength
{
get { return m_grabStrength; }
set { m_grabStrength = Mathf.Clamp01(value); }
}
[Serializable]
public class HandMapping : VG_BoneMapping
{
public override void Initialize(int avatarID, VG_HandSide side)
{
base.Initialize(avatarID, side);
m_BoneToTransform = new Dictionary<int, Transform>()
{
{ 0, Hand_WristRoot }
};
}
}
public VG_EC_Script(int avatarID, VG_HandSide side, Transform origin)
{
m_avatarID = avatarID;
m_handType = side;
m_origin = origin;
m_enabled = true;
Initialize();
}
public new void Initialize()
{
m_mapping = new HandMapping();
base.Initialize();
}
public override bool Compute()
{
if (!m_enabled || m_wrist == null) return false;
SetPose(0, Matrix4x4.TRS(m_wrist.position, m_wrist.rotation, Vector3.one));
return true;
}
public override float GetGrabStrength()
{
return m_grabStrength;
}
public override Color GetConfidence()
{
return Color.yellow;
}
public override void HapticPulse(VG_HandStatus hand, float amplitude = 0.5F, float duration = 0.015F, int finger = 5)
{
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7187da2e8079f68459c7737612322b4e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,214 @@
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
//#define VG_USE_STEAMVR_CONTROLLER
#if UNITY_ANDROID && !UNITY_EDITOR // SteamVR is not supported on Android
#undef VG_USE_STEAMVR_CONTROLLER
#endif
using System;
using System.Collections.Generic;
using UnityEngine;
#if VG_USE_STEAMVR_CONTROLLER
using Valve.VR;
#endif
namespace VirtualGrasp.Controllers
{
/**
* This is an external controller class that supports the Steam Knuckles controller as an external controller.
* Please refer to https://docs.virtualgrasp.com/controllers.html for the definition of an external controller for VG.
*
* The following requirements have to be met to be able to enable the #define VG_USE_STEAMVR_CONTROLLER above and use the controller:
* - You have the SteamVR Unity plugin from https://assetstore.unity.com/packages/tools/integration/steamvr-plugin-32647 imported into your Unity project.
* - You have Steam and the corresponding SteamVR SDK (https://store.steampowered.com/app/250820/SteamVR/) installed on your computer.
* - You have OpenVR Loader selected in Unity XR Management Project Settings.
*/
[LIBVIRTUALGRASP_UNITY_SCRIPT]
[HelpURL("https://docs.virtualgrasp.com/unity_vg_ec_steam." + VG_Version.__VG_VERSION__ + ".html")]
public class VG_EC_Steam : VG_ExternalController
{
#if VG_USE_STEAMVR_CONTROLLER
private SteamVR_Action_Skeleton m_skeleton = null;
private bool m_skeletonActive = false;
#endif
[Serializable]
public class SteamHandMapping : VG_BoneMapping
{
public override void Initialize(int avatarID, VG_HandSide side)
{
base.Initialize(avatarID, side);
m_BoneToTransform = new Dictionary<int, Transform>()
{
#if VG_USE_STEAMVR_CONTROLLER
{ SteamVR_Skeleton_JointIndexes.root, null },
{ SteamVR_Skeleton_JointIndexes.wrist, Hand_WristRoot },
{ SteamVR_Skeleton_JointIndexes.thumbProximal, Hand_Thumb1 },
{ SteamVR_Skeleton_JointIndexes.thumbMiddle, Hand_Thumb2 },
{ SteamVR_Skeleton_JointIndexes.thumbDistal, Hand_Thumb3 },
{ SteamVR_Skeleton_JointIndexes.thumbTip, null },
{ SteamVR_Skeleton_JointIndexes.indexMetacarpal, null },
{ SteamVR_Skeleton_JointIndexes.indexProximal, Hand_Index1 },
{ SteamVR_Skeleton_JointIndexes.indexMiddle, Hand_Index2 },
{ SteamVR_Skeleton_JointIndexes.indexDistal, Hand_Index3 },
{ SteamVR_Skeleton_JointIndexes.indexTip, null },
{ SteamVR_Skeleton_JointIndexes.middleMetacarpal, null },
{ SteamVR_Skeleton_JointIndexes.middleProximal, Hand_Middle1 },
{ SteamVR_Skeleton_JointIndexes.middleMiddle, Hand_Middle2 },
{ SteamVR_Skeleton_JointIndexes.middleDistal, Hand_Middle3 },
{ SteamVR_Skeleton_JointIndexes.middleTip, null },
{ SteamVR_Skeleton_JointIndexes.ringMetacarpal, null },
{ SteamVR_Skeleton_JointIndexes.ringProximal, Hand_Ring1 },
{ SteamVR_Skeleton_JointIndexes.ringMiddle, Hand_Ring2 },
{ SteamVR_Skeleton_JointIndexes.ringDistal, Hand_Ring3 },
{ SteamVR_Skeleton_JointIndexes.ringTip, null },
{ SteamVR_Skeleton_JointIndexes.pinkyMetacarpal, null },
{ SteamVR_Skeleton_JointIndexes.pinkyProximal, Hand_Pinky1 },
{ SteamVR_Skeleton_JointIndexes.pinkyMiddle, Hand_Pinky2 },
{ SteamVR_Skeleton_JointIndexes.pinkyDistal, Hand_Pinky3 },
{ SteamVR_Skeleton_JointIndexes.pinkyTip, null }
#endif
};
m_BoneToParent = new Dictionary<int, int>()
{
};
#if VG_USE_STEAMVR_CONTROLLER
m_BoneToParent[SteamVR_Skeleton_JointIndexes.wrist] = SteamVR_Skeleton_JointIndexes.root;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.thumbProximal] = SteamVR_Skeleton_JointIndexes.wrist;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.thumbMiddle] = SteamVR_Skeleton_JointIndexes.thumbProximal;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.thumbDistal] = SteamVR_Skeleton_JointIndexes.thumbMiddle;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.thumbTip] = SteamVR_Skeleton_JointIndexes.thumbDistal;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.indexMetacarpal] = SteamVR_Skeleton_JointIndexes.wrist;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.indexProximal] = SteamVR_Skeleton_JointIndexes.indexMetacarpal;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.indexMiddle] = SteamVR_Skeleton_JointIndexes.indexProximal;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.indexDistal] = SteamVR_Skeleton_JointIndexes.indexMiddle;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.indexTip] = SteamVR_Skeleton_JointIndexes.indexDistal;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.middleMetacarpal] = SteamVR_Skeleton_JointIndexes.wrist;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.middleProximal] = SteamVR_Skeleton_JointIndexes.middleMetacarpal;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.middleMiddle] = SteamVR_Skeleton_JointIndexes.middleProximal;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.middleDistal] = SteamVR_Skeleton_JointIndexes.middleMiddle;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.middleTip] = SteamVR_Skeleton_JointIndexes.middleDistal;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.ringMetacarpal] = SteamVR_Skeleton_JointIndexes.wrist;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.ringProximal] = SteamVR_Skeleton_JointIndexes.ringMetacarpal;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.ringMiddle] = SteamVR_Skeleton_JointIndexes.ringProximal;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.ringDistal] = SteamVR_Skeleton_JointIndexes.ringMiddle;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.ringTip] = SteamVR_Skeleton_JointIndexes.ringDistal;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.pinkyMetacarpal] = SteamVR_Skeleton_JointIndexes.wrist;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.pinkyProximal] = SteamVR_Skeleton_JointIndexes.pinkyMetacarpal;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.pinkyMiddle] = SteamVR_Skeleton_JointIndexes.pinkyProximal;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.pinkyDistal] = SteamVR_Skeleton_JointIndexes.pinkyMiddle;
m_BoneToParent[SteamVR_Skeleton_JointIndexes.pinkyTip] = SteamVR_Skeleton_JointIndexes.pinkyDistal;
#endif
}
}
public VG_EC_Steam(int avatarID, VG_HandSide side, Transform origin)
{
m_avatarID = avatarID;
m_handType = side;
m_origin = origin;
m_enablingDefine = "VG_USE_STEAMVR_CONTROLLER";
#if VG_USE_STEAMVR_CONTROLLER
m_enabled = true;
#else
PrintNotEnabledError();
m_enabled = false;
#endif
}
public new void Initialize()
{
#if VG_USE_STEAMVR_CONTROLLER
m_mapping = new SteamHandMapping();
base.Initialize();
SteamVR.Initialize();
m_skeleton = SteamVR_Input.GetAction<SteamVR_Action_Skeleton>(m_handType == VG_HandSide.LEFT ? "SkeletonLeftHand" : "SkeletonRightHand");
m_skeleton.SetRangeOfMotion(EVRSkeletalMotionRange.WithoutController);
//m_skeleton.SetSkeletalTransformSpace(Valve.VR.EVRSkeletalTransformSpace.Model);
m_initialized = true;
if (GetNumBones() == 0)
{
Debug.LogError("Could not find bone skeleton root (boneCount=" + GetNumBones() + "; skeleton active=" + m_skeletonActive + ").");
m_initialized = false;
}
#endif
}
public override float GetGrabStrength()
{
#if VG_USE_STEAMVR_CONTROLLER
if (m_skeleton == null) return 0.0f;
return (m_skeleton.fingerCurls[0] + m_skeleton.fingerCurls[1] + m_skeleton.fingerCurls[2]) / 3.0f;
#else
return 0.0f;
#endif
}
public override bool Compute()
{
#if VG_USE_STEAMVR_CONTROLLER
if (!m_enabled) return false;
if (!m_initialized) { Initialize(); return false; }
ETrackingResult res = m_skeleton.GetTrackingResult(m_handType == VG_HandSide.LEFT ? SteamVR_Input_Sources.LeftHand : SteamVR_Input_Sources.RightHand);
if (res == 0) return false;
m_skeletonActive = m_skeleton.GetActive();
for (int boneId = 0; boneId < (m_skeletonActive ? GetNumBones() : 2); ++boneId)
{
if (boneId == 0) // root
{
SetPose(boneId, Matrix4x4.identity);
}
else if (boneId == 1) // wrist
{
SetPose(boneId, Matrix4x4.TRS(m_skeleton.GetLocalPosition(), m_skeleton.GetLocalRotation(), Vector3.one));
}
else
{
SetPose(boneId, m_poses[m_mapping.GetParent(boneId)] * // When transform space is local / Parent
Matrix4x4.TRS(m_skeleton.bonePositions[boneId], m_skeleton.boneRotations[boneId], Vector3.one));
}
}
#endif
return true;
}
public override void HapticPulse(VG_HandStatus hand, float amplitude = 0.5F, float duration = 0.01F, int finger = 5)
{
#if VG_USE_STEAMVR_CONTROLLER
SteamVR_Actions.default_Haptic[hand.m_side == VG_HandSide.LEFT ? SteamVR_Input_Sources.LeftHand : SteamVR_Input_Sources.RightHand].Execute(0, duration, 10, amplitude);
#endif
}
public override Color GetConfidence()
{
#if VG_USE_STEAMVR_CONTROLLER
EVRSkeletalTrackingLevel skeletalTrackingLevel = EVRSkeletalTrackingLevel.VRSkeletalTracking_Estimated;
if (m_skeleton == null || OpenVR.Input.GetSkeletalTrackingLevel(m_skeleton.handle, ref skeletalTrackingLevel) != EVRInputError.None)
return Color.black;
switch (skeletalTrackingLevel)
{
case EVRSkeletalTrackingLevel.VRSkeletalTracking_Full:
return Color.green;
case EVRSkeletalTrackingLevel.VRSkeletalTracking_Partial:
return Color.yellow;
case EVRSkeletalTrackingLevel.VRSkeletalTracking_Estimated:
return Color.red;
}
#endif
return Color.black;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 35987637c5dd86e4082679c5c048d825
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,107 @@
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
//#define VG_USE_UNITYXR_CONTROLLER
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
namespace VirtualGrasp.Controllers
{
/**
* This is an external controller class that supports the UnityXR controller (such as provided by Pico or Oculus integrations) as an external controller.
* Please refer to https://docs.virtualgrasp.com/controllers.html for the definition of an external controller for VG.
*
* The following requirements have to be met to be able to enable the #define VG_USE_UNITYXR_CONTROLLER above and use the controller:
* - You have the Unity XR Management package installed into your Unity project.
*/
[LIBVIRTUALGRASP_UNITY_SCRIPT]
[HelpURL("https://docs.virtualgrasp.com/unity_vg_ec_unityxr." + VG_Version.__VG_VERSION__ + ".html")]
public class VG_EC_UnityXR : VG_ExternalController
{
private InputDevice m_device;
[Serializable]
public class HandMapping : VG_BoneMapping
{
public override void Initialize(int avatarID, VG_HandSide side)
{
base.Initialize(avatarID, side);
m_BoneToTransform = new Dictionary<int, Transform>()
{
{ 0, Hand_WristRoot }
};
}
}
public VG_EC_UnityXR(int avatarID, VG_HandSide side, Transform origin)
{
m_avatarID = avatarID;
m_handType = side;
m_origin = origin;
m_enabled = true;
Initialize();
}
public new void Initialize()
{
m_mapping = new HandMapping();
base.Initialize();
m_initialized = true;
}
public override bool Compute()
{
if (!m_enabled) return false;
if (!m_initialized) { Initialize(); return false; }
if (!m_device.isValid)
{
m_device = InputDevices.GetDeviceAtXRNode(m_handType == VG_HandSide.LEFT ? XRNode.LeftHand : XRNode.RightHand);
return false;
}
if (m_device.TryGetFeatureValue(CommonUsages.devicePosition, out Vector3 p) &&
m_device.TryGetFeatureValue(CommonUsages.deviceRotation, out Quaternion q))
{
SetPose(0, Matrix4x4.TRS(p, q, Vector3.one));
return true;
}
return false;
}
public override float GetGrabStrength()
{
if (!m_initialized || !m_device.isValid) return 0.0f;
float trigger = 0.0f;
switch (VG_Controller.GetGraspButton())
{
case VG_VrButton.TRIGGER:
m_device.TryGetFeatureValue(CommonUsages.trigger, out trigger); break;
case VG_VrButton.GRIP:
m_device.TryGetFeatureValue(CommonUsages.grip, out trigger); break;
case VG_VrButton.GRIP_OR_TRIGGER:
m_device.TryGetFeatureValue(CommonUsages.trigger, out trigger);
m_device.TryGetFeatureValue(CommonUsages.grip, out float trigger2);
trigger = Mathf.Max(trigger, trigger2);
break;
}
return trigger;
}
public override Color GetConfidence()
{
return Color.yellow;
}
public override void HapticPulse(VG_HandStatus hand, float amplitude = 0.5F, float duration = 0.015F, int finger = 5)
{
if (!m_initialized || !m_device.isValid) return;
HapticCapabilities capabilities;
if (m_device.TryGetHapticCapabilities(out capabilities) && capabilities.supportsImpulse)
m_device.SendHapticImpulse(0, amplitude, duration);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 482d610d95177f04a9bb38d20d6539c8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,193 @@
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
//#define VG_USE_XRHANDS_CONTROLLER
using System;
using System.Collections.Generic;
using UnityEngine;
#if VG_USE_XRHANDS_CONTROLLER
using UnityEngine.XR.Hands;
using UnityEngine.XR.Management;
#endif
namespace VirtualGrasp.Controllers
{
/**
* This is an external controller class that supports the Unity XRHands controller as an external controller.
* Please refer to https://docs.virtualgrasp.com/controllers.html for the definition of an external controller for VG.
*
* The following requirements have to be met to be able to enable the #define VG_USE_XRHANDS_CONTROLLER above and use the controller:
* - You have followed the installation instructions of the Unity XRHands package,
* from https://docs.unity3d.com/Packages/com.unity.xr.hands@1.1/manual/
*/
[LIBVIRTUALGRASP_UNITY_SCRIPT]
[HelpURL("https://docs.virtualgrasp.com/unity_vg_ec_unityxrhands." + VG_Version.__VG_VERSION__ + ".html")]
public class VG_EC_UnityXRHands : VG_ExternalController
{
#if VG_USE_XRHANDS_CONTROLLER
XRHandSubsystem m_Subsystem = null;
XRHand m_hand;
XRHandSubsystem.UpdateSuccessFlags m_updateSuccessFlags = XRHandSubsystem.UpdateSuccessFlags.None;
#endif
[Serializable]
public class OpenXRHandMapping : VG_BoneMapping
{
public override void Initialize(int avatarID, VG_HandSide side)
{
base.Initialize(avatarID, side);
m_BoneToTransform = new Dictionary<int, Transform>()
{
#if VG_USE_XRHANDS_CONTROLLER
{ XRHandJointID.Wrist.ToIndex(), Hand_WristRoot },
{ XRHandJointID.Palm.ToIndex(), null },
{ XRHandJointID.ThumbMetacarpal.ToIndex(), Hand_Thumb1 },
{ XRHandJointID.ThumbProximal.ToIndex(), Hand_Thumb2 },
{ XRHandJointID.ThumbDistal.ToIndex(), Hand_Thumb3 },
{ XRHandJointID.ThumbTip.ToIndex(), null },
{ XRHandJointID.IndexMetacarpal.ToIndex(), null },
{ XRHandJointID.IndexProximal.ToIndex(), Hand_Index1 },
{ XRHandJointID.IndexIntermediate.ToIndex(), Hand_Index2 },
{ XRHandJointID.IndexDistal.ToIndex(), Hand_Index3 },
{ XRHandJointID.IndexTip.ToIndex(), null },
{ XRHandJointID.MiddleMetacarpal.ToIndex(), null },
{ XRHandJointID.MiddleProximal.ToIndex(), Hand_Middle1 },
{ XRHandJointID.MiddleIntermediate.ToIndex(), Hand_Middle2 },
{ XRHandJointID.MiddleDistal.ToIndex(), Hand_Middle3 },
{ XRHandJointID.MiddleTip.ToIndex(), null },
{ XRHandJointID.RingMetacarpal.ToIndex(), null },
{ XRHandJointID.RingProximal.ToIndex(), Hand_Ring1 },
{ XRHandJointID.RingIntermediate.ToIndex(), Hand_Ring2 },
{ XRHandJointID.RingDistal.ToIndex(), Hand_Ring3 },
{ XRHandJointID.RingTip.ToIndex(), null },
{ XRHandJointID.LittleMetacarpal.ToIndex(), null },
{ XRHandJointID.LittleProximal.ToIndex(), Hand_Pinky1 },
{ XRHandJointID.LittleIntermediate.ToIndex(), Hand_Pinky2 },
{ XRHandJointID.LittleDistal.ToIndex(), Hand_Pinky3 },
{ XRHandJointID.LittleTip.ToIndex(), null }
#endif
};
m_BoneToParent = new Dictionary<int, int>()
{
};
#if VG_USE_XRHANDS_CONTROLLER
m_BoneToParent[XRHandJointID.Palm.ToIndex()] = XRHandJointID.Wrist.ToIndex();
m_BoneToParent[XRHandJointID.ThumbMetacarpal.ToIndex()] = XRHandJointID.Wrist.ToIndex();
m_BoneToParent[XRHandJointID.ThumbProximal.ToIndex()] = XRHandJointID.ThumbMetacarpal.ToIndex();
m_BoneToParent[XRHandJointID.ThumbDistal.ToIndex()] = XRHandJointID.ThumbProximal.ToIndex();
m_BoneToParent[XRHandJointID.ThumbTip.ToIndex()] = XRHandJointID.ThumbDistal.ToIndex();
m_BoneToParent[XRHandJointID.IndexMetacarpal.ToIndex()] = XRHandJointID.Wrist.ToIndex();
m_BoneToParent[XRHandJointID.IndexProximal.ToIndex()] = XRHandJointID.IndexMetacarpal.ToIndex();
m_BoneToParent[XRHandJointID.IndexIntermediate.ToIndex()] = XRHandJointID.IndexProximal.ToIndex();
m_BoneToParent[XRHandJointID.IndexDistal.ToIndex()] = XRHandJointID.IndexIntermediate.ToIndex();
m_BoneToParent[XRHandJointID.IndexTip.ToIndex()] = XRHandJointID.IndexDistal.ToIndex();
m_BoneToParent[XRHandJointID.MiddleMetacarpal.ToIndex()] = XRHandJointID.Wrist.ToIndex();
m_BoneToParent[XRHandJointID.MiddleProximal.ToIndex()] = XRHandJointID.MiddleMetacarpal.ToIndex();
m_BoneToParent[XRHandJointID.MiddleIntermediate.ToIndex()] = XRHandJointID.MiddleProximal.ToIndex();
m_BoneToParent[XRHandJointID.MiddleDistal.ToIndex()] = XRHandJointID.MiddleIntermediate.ToIndex();
m_BoneToParent[XRHandJointID.MiddleTip.ToIndex()] = XRHandJointID.MiddleDistal.ToIndex();
m_BoneToParent[XRHandJointID.RingMetacarpal.ToIndex()] = XRHandJointID.Wrist.ToIndex();
m_BoneToParent[XRHandJointID.RingProximal.ToIndex()] = XRHandJointID.RingMetacarpal.ToIndex();
m_BoneToParent[XRHandJointID.RingIntermediate.ToIndex()] = XRHandJointID.RingProximal.ToIndex();
m_BoneToParent[XRHandJointID.RingDistal.ToIndex()] = XRHandJointID.RingIntermediate.ToIndex();
m_BoneToParent[XRHandJointID.RingTip.ToIndex()] = XRHandJointID.RingDistal.ToIndex();
m_BoneToParent[XRHandJointID.LittleMetacarpal.ToIndex()] = XRHandJointID.Wrist.ToIndex();
m_BoneToParent[XRHandJointID.LittleProximal.ToIndex()] = XRHandJointID.LittleMetacarpal.ToIndex();
m_BoneToParent[XRHandJointID.LittleIntermediate.ToIndex()] = XRHandJointID.LittleProximal.ToIndex();
m_BoneToParent[XRHandJointID.LittleDistal.ToIndex()] = XRHandJointID.LittleIntermediate.ToIndex();
m_BoneToParent[XRHandJointID.LittleTip.ToIndex()] = XRHandJointID.LittleDistal.ToIndex();
#endif
}
}
public VG_EC_UnityXRHands(int avatarID, VG_HandSide side, Transform origin)
{
m_avatarID = avatarID;
m_handType = side;
m_origin = origin;
m_enablingDefine = "VG_USE_XRHANDS_CONTROLLER";
#if VG_USE_XRHANDS_CONTROLLER
m_enabled = true;
#else
PrintNotEnabledError();
m_enabled = false;
#endif
}
public new void Initialize()
{
#if VG_USE_XRHANDS_CONTROLLER
m_mapping = new OpenXRHandMapping();
base.Initialize();
m_Subsystem = XRGeneralSettings.Instance?.Manager?.activeLoader?.GetLoadedSubsystem<XRHandSubsystem>();
if (m_Subsystem != null)
{
if (m_handType == VG_HandSide.LEFT)
{
m_hand = m_Subsystem.leftHand;
m_updateSuccessFlags = XRHandSubsystem.UpdateSuccessFlags.LeftHandRootPose | XRHandSubsystem.UpdateSuccessFlags.LeftHandJoints;
}
else
{
m_hand = m_Subsystem.rightHand;
m_updateSuccessFlags = XRHandSubsystem.UpdateSuccessFlags.RightHandRootPose | XRHandSubsystem.UpdateSuccessFlags.RightHandJoints;
}
if (!m_Subsystem.running) m_Subsystem.Start();
base.Initialize();
m_initialized = true;
}
else m_initialized = false;
#endif
}
public override float GetGrabStrength()
{
return -1.0f; // let VG decide from full DOF
}
public override bool Compute()
{
if (!m_enabled) return false;
if (!m_initialized) { Initialize(); return false; }
#if VG_USE_XRHANDS_CONTROLLER
if (!m_Subsystem.running) return false;
if (!m_Subsystem.TryUpdateHands(XRHandSubsystem.UpdateType.Dynamic).HasFlag(m_updateSuccessFlags))
return false;
for (int boneId = 0; boneId < GetNumBones(); ++boneId)
{
if (m_hand.GetJoint(XRHandJointIDUtility.FromIndex(boneId)).TryGetPose(out Pose pose))
{
//if (m_origin != null) pose = pose.GetTransformedBy(m_origin);
SetPose(boneId, Matrix4x4.TRS(
pose.position,
pose.rotation, Vector3.one));
}
}
return true;
#else
return false;
#endif
}
public override void HapticPulse(VG_HandStatus hand, float amplitude = 0.5F, float duration = 0.01F, int finger = 5)
{
}
public override Color GetConfidence()
{
if (!m_initialized) return Color.black;
return Color.yellow;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f9e2dc4556c290f4a88a6b4573b61556
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,201 @@
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
//#define VG_USE_UNITYXRINTERACTION_HAND
using System;
using System.Collections.Generic;
using UnityEngine;
#if VG_USE_UNITYXRINTERACTION_HAND
using UnityEngine.InputSystem;
using UnityEngine.XR.Interaction.Toolkit;
using UnityEngine.XR.Interaction.Toolkit.Inputs;
#endif
namespace VirtualGrasp.Controllers
{
/**
* This is an external controller class that supports the action-based Unity XR Interaction toolkit controller as an external controller.
* Please refer to https://docs.virtualgrasp.com/controllers.html for the definition of an external controller for VG, and to
* https://docs.unity3d.com/Packages/com.unity.xr.interaction.toolkit@2.0/manual/index.html for the plugin itself.
*
* The following requirements have to be met to be able to enable the #define VG_USE_UNITYINTERACTION_HAND above and use the controller:
* - You have the "XR Plugin Management" package installed into your Unity project.
* - You have the "XR Interaction Toolkit" package installed into your Unity project.
* - The current setup does not seem to work for OpenXR as an XR plugin provider, you must have Oculus XR package installed into your Unity project.
* - if you use Oculus, you use it through "OpenXR" (Oculus -> Tools -> OVR Utilities Plugin -> Set OVR to OpenXR)
*/
[LIBVIRTUALGRASP_UNITY_SCRIPT]
[HelpURL("https://docs.virtualgrasp.com/unity_vg_ec_unityxrinteraction." + VG_Version.__VG_VERSION__ + ".html")]
public class VG_EC_UnityXRInteraction : VG_ExternalController
{
#if VG_USE_UNITYXRINTERACTION_HAND
private const string XRI_RESOURCE = "VG_XRI_Entries"; //"XRI Default Input Actions";
private const string XRI_ACTIONMAP = "Player";
private static VG_XRI_Entries m_xriEntries = null;
static InputActionManager m_provider = null;
private ActionBasedController m_controller = null;
#endif
[Serializable]
public class HandMapping : VG_BoneMapping
{
public override void Initialize(int avatarID, VG_HandSide side)
{
base.Initialize(avatarID, side);
m_BoneToTransform = new Dictionary<int, Transform>()
{
{ 0, Hand_WristRoot }
};
}
}
public VG_EC_UnityXRInteraction(int avatarID, VG_HandSide side, Transform origin)
{
m_avatarID = avatarID;
m_handType = side;
m_origin = origin;
m_enabled = true;
m_enablingDefine = "VG_USE_UNITYXRINTERACTION_HAND";
#if VG_USE_UNITYXRINTERACTION_HAND
m_enabled = true;
#else
PrintNotEnabledError();
m_enabled = false;
#endif
}
public void DisposeController()
{
#if VG_USE_UNITYXRINTERACTION_HAND
if (m_controller != null)
GameObject.Destroy(m_controller.gameObject);
#endif
}
public new void Initialize()
{
#if VG_USE_UNITYXRINTERACTION_HAND
if (m_provider == null) m_provider = GameObject.FindObjectOfType<InputActionManager>();
if (m_xriEntries == null)
m_xriEntries = Resources.Load<VG_XRI_Entries>(XRI_RESOURCE);
if (m_xriEntries == null)
{
Debug.LogError("Could not find " + XRI_RESOURCE);
return;
}
else
{
m_xriEntries.Initialize();
//Debug.Log(m_xriEntries);
}
InputActionAsset inputActionAsset = null;
if (m_provider == null)
{
m_provider = GameObject.FindObjectOfType<VG_MainScript>().gameObject.AddComponent<InputActionManager>();
inputActionAsset = Resources.Load<InputActionAsset>(m_xriEntries.Get(VG_XRI_Entries.XRI_Entry.RESOURCE));
if (inputActionAsset != null)
{
m_provider.actionAssets = new List<InputActionAsset>{ inputActionAsset };
m_provider.EnableInput();
}
else Debug.Log("Could not load input actions.");
}
if (m_provider != null && m_provider.actionAssets.Count > 0 && m_provider.actionAssets[0] != null)
{
m_mapping = new HandMapping();
base.Initialize();
string handSide = (m_handType == VG_HandSide.LEFT) ? "Left" : "Right";
// We put the ActionBasedController components on dummy GameObjects so they do not
// affect the wrist transforms per se (this can't be disabled in the XRController it seems).
GameObject controller = new(handSide + "Controller_ID" + m_avatarID);
controller.transform.SetParent(m_provider.transform);
m_controller = controller.AddComponent<ActionBasedController>();
// Bind Position and Rotation Signals
InputActionMap inputMap = m_provider.actionAssets[0].FindActionMap(XRI_ACTIONMAP);
if (inputMap == null) Debug.LogError("Could not find map " + XRI_ACTIONMAP);
else
{
m_controller.enableInputTracking = true;
m_controller.updateTrackingType = XRBaseController.UpdateType.Update;
foreach (VG_XRI_Entries.XRI_Entry entry in new List<VG_XRI_Entries.XRI_Entry> { VG_XRI_Entries.XRI_Entry.POSITION, VG_XRI_Entries.XRI_Entry.ROTATION, VG_XRI_Entries.XRI_Entry.TRIGGER, VG_XRI_Entries.XRI_Entry.GRAB, VG_XRI_Entries.XRI_Entry.HAPTICS })
{
string actionName = m_xriEntries.Get(entry, handSide);
InputAction inputAction = inputMap.FindAction(actionName);
if (inputAction == null)
{
Debug.LogWarning("Could not find action " + actionName + " in " + XRI_ACTIONMAP + ".");
continue;
}
switch (entry)
{
case VG_XRI_Entries.XRI_Entry.POSITION:
m_controller.positionAction = new InputActionProperty(inputAction); break;
case VG_XRI_Entries.XRI_Entry.ROTATION:
m_controller.rotationAction = new InputActionProperty(inputAction); break;
case VG_XRI_Entries.XRI_Entry.TRIGGER:
m_controller.activateAction = new InputActionProperty(inputAction); break;
case VG_XRI_Entries.XRI_Entry.GRAB:
m_controller.selectAction = new InputActionProperty(inputAction); break;
case VG_XRI_Entries.XRI_Entry.HAPTICS:
m_controller.hapticDeviceAction = new InputActionProperty(inputAction); break;
}
}
}
}
m_initialized = (m_provider != null && m_controller != null);
#endif
}
public override bool Compute()
{
#if VG_USE_UNITYXRINTERACTION_HAND
if (!m_enabled) return false;
if (!m_initialized) { Initialize(); return false; }
SetPose(0, Matrix4x4.TRS(m_controller.currentControllerState.position, m_controller.currentControllerState.rotation, Vector3.one));
#endif
return true;
}
public override float GetGrabStrength()
{
float trigger = 0.0f;
#if VG_USE_UNITYXRINTERACTION_HAND
if (!m_initialized) return 0.0f;
switch (VG_Controller.GetGraspButton())
{
case VG_VrButton.TRIGGER:
trigger = m_controller.currentControllerState.activateInteractionState.value; break;
case VG_VrButton.GRIP:
trigger = m_controller.currentControllerState.selectInteractionState.value; break;
case VG_VrButton.GRIP_OR_TRIGGER:
trigger = Mathf.Max(m_controller.currentControllerState.activateInteractionState.value,
m_controller.currentControllerState.selectInteractionState.value);
break;
}
#endif
return trigger;
}
public override Color GetConfidence()
{
return Color.yellow;
}
public override void HapticPulse(VG_HandStatus hand, float amplitude = 0.5F, float duration = 0.015F, int finger = 5)
{
#if VG_USE_UNITYXRINTERACTION_HAND
m_controller.SendHapticImpulse(amplitude, duration);
#endif
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8ec2bbae109cbf34b994dac2f101fb30
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,63 @@
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
using System;
using System.Collections.Generic;
using UnityEngine;
namespace VirtualGrasp.Controllers
{
[Serializable, CreateAssetMenu(fileName = "VG_XRI_Entries", menuName = "VirtualGrasp/VG_XRI_Entries")]
public class VG_XRI_Entries : ScriptableObject
{
public enum XRI_Entry
{
RESOURCE,
POSITION,
ROTATION,
TRIGGER,
GRAB,
HAPTICS
}
public void Initialize()
{
m_entries.Clear();
TryAdd(XRI_Entry.RESOURCE, m_resourceName);
TryAdd(XRI_Entry.POSITION, m_positionAction);
TryAdd(XRI_Entry.ROTATION, m_rotationAction);
TryAdd(XRI_Entry.TRIGGER, m_triggerAction);
TryAdd(XRI_Entry.GRAB, m_grabAction);
TryAdd(XRI_Entry.HAPTICS, m_hapticsAction);
}
public void TryAdd(XRI_Entry key, string value)
{
if (value != "")
m_entries.Add(key, value);
}
public string Get(XRI_Entry key, string suffix = "")
{
if (!m_entries.TryGetValue(key, out string value))
return "null";
return value + suffix;
}
public override string ToString()
{
string str = "Valid Entries:\n";
foreach (var entry in m_entries) { str += entry.ToString() + "\n"; }
return str;
}
public string m_resourceName = "";
public string m_positionAction = "";
public string m_rotationAction = "";
public string m_triggerAction = "";
public string m_grabAction = "";
public string m_hapticsAction = "";
private Dictionary<XRI_Entry, string> m_entries = new();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7f5008351c8d5fa4590d077c163cd0cc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: