Skip to content

Commit

Permalink
feat(inputModule): Support to Unity XR Input
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgejgnz committed Jan 22, 2021
1 parent 5aad738 commit 3b2ce46
Show file tree
Hide file tree
Showing 44 changed files with 2,979 additions and 252 deletions.
16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
# HPTK [![](https://img.shields.io/badge/unity-2019.4%20or%20later-green.svg)](https://unity3d.com/es/get-unity/download/archive) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/jorgejgnz/HPTK/blob/master/LICENSE.md) [![version](https://img.shields.io/badge/version-0.4.0-blue)](https://github.com/jorgejgnz/HPTK/releases) [![](https://img.shields.io/twitter/follow/jorgejgnz.svg?label=Follow&style=social)](https://twitter.com/intent/follow?screen_name=jorgejgnz)

Hand Physics Toolkit (HPTK) is a toolkit to build physical hand-driven interactions in a modular and scalable way. Hand physics and hover/touch/grab detection are modules included. This toolkit can be combined with [MRTK-Quest](https://github.com/provencher/MRTK-Quest) for UI interactions. Only Oculus Quest is supported at the moment.
Hand Physics Toolkit (HPTK) is a toolkit to build physical hand-driven interactions in a modular and scalable way. Platform-independent. Input-independent. This toolkit can be combined with [MRTK-Quest](https://github.com/provencher/MRTK-Quest) for UI interactions.

## Main features
- Data model to access hand components and lerp values to compose gestures and trigger actions.
- State-of-the-art hand physics that can be configured in detail through configuration assets.
- Hover/Touch/Grab detection with support to interactions involving multiple objects and hands.
- Code architecture based on isolated modules. Support to custom modules. ([Wiki](https://github.com/jorgejgnz/HPTK/wiki/Custom-modules)).
- Input abstraction. RelativeSkeletonTracker included to mimic other hands. ([Wiki](https://github.com/jorgejgnz/HPTK/wiki/Modules-overview)).
- Data model to access hand parts, components or calculated values with very little code.
- Code architecture based on MVC-like modules. ([Wiki](https://github.com/jorgejgnz/HPTK/wiki/Modules-overview)). Support to custom modules. ([Wiki](https://github.com/jorgejgnz/HPTK/wiki/Custom-modules)).
- State-of-the-art hand physics. Configurable in detail through configuration assets.
- Platform-independent. Tested on VR/AR/non-XR applications
- Input-independent. Use handtracking or controllers.
- Scale-independent. Valid for any hand size.
- Define strategies to deal with loss of tracking.
- Physics-based touch/grab detection.
- Tracking noise smoothing.

## Example project
- You can clone a ready-to-go project at [HPTK-Sample](https://github.com/jorgejgnz/HPTK-Sample).
Expand Down
98 changes: 91 additions & 7 deletions Runtime/Components/AutomaticHandSetup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public class AutomaticHandSetup : MonoBehaviour
public Anchors generateArmatureAnchors = Anchors.None;
public bool generateMasterOffset = true;
public bool generateRays = true;
public bool cloneMaster = true;
public bool generateSlave = true;
public bool generateGhost = true;

Expand All @@ -84,6 +85,7 @@ public class AutomaticHandSetup : MonoBehaviour
float gizmoDirSize = 0.2f;
float gizmoSphereSize = 0.005f;

#if UNITY_EDITOR
public void Setup()
{
// Check errors
Expand Down Expand Up @@ -149,6 +151,7 @@ void SetupMasterObjects()
{
// CustomHand > Objects > Master
masterRootObject = BasicHelpers.InstantiateEmptyChild(objects);

masterRootObject.name = "Master." + handType.ToString();

// CustomHand > Objects > Master > (content)
Expand All @@ -171,16 +174,44 @@ void SetupMasterObjects()
}

// Spawn wrist
masterWrist = BasicHelpers.InstantiateEmptyChild(masterRootObject, "Wrist");
masterWrist.transform.position = wrist.position;
if (cloneMaster)
{
masterWrist = BasicHelpers.InstantiateEmptyChild(masterRootObject);
masterWrist.transform.position = wrist.position;
}
else
{
masterWrist = wrist.gameObject;
}

masterWrist.name = "Wrist." + handType.ToString();

masterFingersRoot = masterWrist.gameObject;

// Create offset (if needed)
if (generateMasterOffset)
{
List<Transform> children = new List<Transform>();

if (!cloneMaster)
{
foreach (Transform child in masterWrist.transform)
{
children.Add(child);
}
}

masterWristOffset = BasicHelpers.InstantiateEmptyChild(masterWrist, "Offset");
masterWristOffset.transform.position = masterWrist.transform.position;
masterFingersRoot = masterWristOffset;

if (!cloneMaster)
{
foreach(Transform child in children)
{
child.parent = masterFingersRoot.transform;
}
}
}

// Armature wrist anchor
Expand Down Expand Up @@ -209,10 +240,17 @@ void SetupMasterObjects()

for (int b = 0; b < _fingers[f].Length; b++)
{
Transform bone = BasicHelpers.InstantiateEmptyChild(masterFingersRoot).transform;
Transform bone;

if (cloneMaster)
bone = BasicHelpers.InstantiateEmptyChild(masterFingersRoot).transform;
else
bone = _fingers[f][b];

if (b==0 && _fingers[f][b].childCount == 0)
bone.name = "Extra.Bone";
else if (b == _fingers[f].Length - 1)
bone.name = "Finger" + f + ".Tip";
else
bone.name = "Finger" + f + ".Bone" + b;

Expand Down Expand Up @@ -308,7 +346,14 @@ void SetupGhostObjects()
void SetupProxyHandModule()
{
// CustomHand > [Modules] > ProxyHandModule
GameObject proxyHandModule = Instantiate(proxyHandModulePrefab, modules.transform.position, modules.transform.rotation);
string prefabPath = AssetDatabase.GetAssetPath(proxyHandModulePrefab);
Object prefab = AssetDatabase.LoadAssetAtPath(prefabPath, typeof(GameObject));

GameObject proxyHandModule = PrefabUtility.InstantiatePrefab(prefab) as GameObject;

proxyHandModule.transform.position = modules.transform.position;
proxyHandModule.transform.rotation = modules.transform.rotation;

proxyHandModule.transform.parent = modules.transform;
proxyHandModule.transform.name = "ProxyHandModule." + handType.ToString();

Expand Down Expand Up @@ -464,6 +509,17 @@ void SetupMasterHandModel(MasterHandModel handModel, Transform masterWrist, Game
fingerModel.name = "Pinky";
handModel.pinky = fingerModel;
}
else
{
fingerModel.name = "Unidentified";
}

for (int b = 0; b < fingerModel.bones.Length; b++)
{
fingerModel.bones[b].transformRef.name = fingerModel.name + b;
}

fingerModel.fingerTip.name = fingerModel.name + ".Tip";
}

// Homogeneus order for .fingers
Expand Down Expand Up @@ -580,6 +636,17 @@ void SetupSlaveHandModel(SlaveHandModel handModel, Transform slaveWrist)
fingerModel.name = "Pinky";
handModel.pinky = fingerModel;
}
else
{
fingerModel.name = "Unidentified";
}

for (int b = 0; b < fingerModel.bones.Length; b++)
{
fingerModel.bones[b].transformRef.name = fingerModel.name + b;
}

fingerModel.fingerTip.name = fingerModel.name + ".Tip";

// Increase finger counter
f++;
Expand Down Expand Up @@ -609,7 +676,7 @@ void SetupSlaveHandModel(SlaveHandModel handModel, Transform slaveWrist)
Debug.LogError("Trying to access a non-existing finger!");

else if (b > handModel.proxyHand.master.fingers[f].bones.Length - 1)
Debug.LogError("Trying to access a non-existing bone!");
Debug.LogError("Trying to access a non-existing bone! Bone " + b + " is unreachable as fingers[" + f + "].bones.Length = " + handModel.proxyHand.master.fingers[f].bones.Length);

else if (handModel.proxyHand.master.fingers[f] != null && handModel.proxyHand.master.fingers[f].bones[b] != null)
slaveBone.masterBone = handModel.proxyHand.master.fingers[f].bones[b] as MasterBoneModel;
Expand Down Expand Up @@ -705,6 +772,17 @@ void SetupGhostHandModel(HandModel handModel, Transform ghostWrist)
fingerModel.name = "Pinky";
handModel.pinky = fingerModel;
}
else
{
fingerModel.name = "Unidentified";
}

for (int b = 0; b < fingerModel.bones.Length; b++)
{
fingerModel.bones[b].transformRef.name = fingerModel.name + b;
}

fingerModel.fingerTip.name = fingerModel.name + ".Tip";
}

// Homogeneus order for .fingers
Expand Down Expand Up @@ -966,6 +1044,12 @@ bool AllSystemsNominal()
return false;
}

if (!proxyHandModulePrefab)
{
Debug.LogError("Proxy hand module prefab is required!");
return false;
}

return true;
}

Expand Down Expand Up @@ -1386,7 +1470,6 @@ private void OnDrawGizmos()
thumbDir = new Vector3(0.0f, 0.0f, gizmoDirSize);
}

# if UNITY_EDITOR
// Draw finger direction
Handles.color = Color.blue;
Handles.Label(wrist.position + fingerDir, "Fingers");
Expand Down Expand Up @@ -1419,9 +1502,10 @@ private void OnDrawGizmos()
gizmoDirSize,
EventType.Repaint
);
#endif

}
}
#endif
}


Expand Down
4 changes: 3 additions & 1 deletion Runtime/Components/SMRMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,19 @@ public class SMRMapper : MonoBehaviour

public void Read()
{
if (!skinnedMeshRenderer) skinnedMeshRenderer = GetComponent<SkinnedMeshRenderer>();
bones = skinnedMeshRenderer.bones;
}
public void Write()
{
if (!skinnedMeshRenderer) skinnedMeshRenderer = GetComponent<SkinnedMeshRenderer>();
skinnedMeshRenderer.bones = bones;
}

}

#if UNITY_EDITOR
[CustomEditor(typeof(SMRMapper))]
[CustomEditor(typeof(SMRMapper)), CanEditMultipleObjects]
public class SMRMapperEditor : Editor
{
public override void OnInspectorGUI()
Expand Down
2 changes: 1 addition & 1 deletion Runtime/Helpers/PhysHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ public static void SetBonePhysics(SlaveBoneModel bone, bool enabled)
{
if (bone.rigidbodyRef)
{
if (bone.rigidbodyRef.isKinematic)
if (enabled)
{
bone.rigidbodyRef.isKinematic = false;
bone.rigidbodyRef.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
Expand Down
90 changes: 90 additions & 0 deletions Runtime/Input/AbstractTsf.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace HPTK.Input
{
[Serializable]
public class AbstractTsf
{
public string name;

public Vector3 position;
public Quaternion rotation;
public Space space;

public Vector3 localScale;

public AbstractTsf(Vector3 position, Quaternion rotation, Space space, Vector3 localScale, string name)
{
this.position = position;
this.rotation = rotation;
this.space = space;

this.localScale = localScale;
this.name = name;
}

public AbstractTsf(string name, Space space)
{
this.space = space;
this.name = name;
this.position = Vector3.zero;
this.rotation = Quaternion.identity;
this.localScale = Vector3.one;
}

public AbstractTsf(Transform tsf, Space space)
{
this.name = tsf.name;
this.space = space;

if (space == Space.World)
{
this.position = tsf.position;
this.rotation = tsf.rotation;
}
else
{
this.position = tsf.localPosition;
this.rotation = tsf.localRotation;
}

this.localScale = tsf.localScale;
}

public AbstractTsf(AbstractTsf abstractTsf)
{
this.name = abstractTsf.name;
this.space = abstractTsf.space;
this.position = abstractTsf.position;
this.rotation = abstractTsf.rotation;
}

public static void Copy(AbstractTsf from, AbstractTsf to)
{
to.name = from.name;
to.space = from.space;
to.position = from.position;
to.rotation = from.rotation;
to.localScale = from.localScale;
}

public static void ApplyTransform(AbstractTsf bonePose, Transform receiverTsf)
{
if (bonePose.space == Space.World)
{
receiverTsf.position = bonePose.position;
receiverTsf.rotation = bonePose.rotation;
}
else
{
receiverTsf.localPosition = bonePose.position;
receiverTsf.localRotation = bonePose.rotation;
}

receiverTsf.localScale = bonePose.localScale;
}
}
}
11 changes: 11 additions & 0 deletions Runtime/Input/AbstractTsf.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 3b2ce46

Please sign in to comment.