Search Unity

Hand Animation in XR Interaction Toolkit

Discussion in 'XR Interaction Toolkit and Input' started by Epic_Cube, Nov 11, 2021.

  1. Epic_Cube

    Epic_Cube

    Joined:
    Jul 3, 2012
    Posts:
    100
    Hi all,
    I'm creating a VR game with XR Interaction Toolkit. At the moment I'm interacting with virtual object with a laser interactor. I'd like to use human hands that animate properly when I press specific buttons on my controller (Oculus Quest trigger, and lateral button).

    Oculus quest sample projects (not using XT Interaction Toolkit) allows to achieve that with 2 hands controlled by an animator for each one. Is there something similar for XR Interaction toolkit too?
    Any sample project?

    Thank you
     
  2. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    I'm not aware of a ready to use solution, but you can make something like this from scratch without much difficulty. The simplest implementation is just a basic blend tree with multiple hand poses.
     
  3. Epic_Cube

    Epic_Cube

    Joined:
    Jul 3, 2012
    Posts:
    100
    the oculus plugin contains rigged hands with some poses and blend tree, but it could be quite difficult to control it with XR Interaction Toolkit.
    Does anyone did it?
     
  4. Epic_Cube

    Epic_Cube

    Joined:
    Jul 3, 2012
    Posts:
    100
  5. whart

    whart

    Joined:
    Feb 13, 2020
    Posts:
    1
    I'm posting a update to this tutorial, because I wanted to use it with the new input system so I needed to edit the script.
    I used the XRI Default Input Actions included with Unity's XR Interaction Toolkit plugin in the Starter Assets Samples. The only other thing I did was add make a separate Thumb Touched button action in both Hand Interaction Action Maps of the XRI Default Input Action.inputactions, I filled it with bindings like secondaryTouched, primaryTouched, thumbstickTouched, thumbtouch, and thumbresttouch.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.InputSystem;
    3. using System.Linq;
    4.  
    5. /// <summary>
    6. /// This is an adaption of both Oculus's HandPose and Hand scripts (located in Oculus' Inegration SDK's SampleFramework https://developer.oculus.com/downloads/package/unity-integration/) and Kyle Pastor's Oculus Integration Hand Animations HandAnim script found:
    7. /// https://medium.com/datastuffplus/using-oculus-integration-hand-animations-with-unity-xr-kit-e707b6acb0a2 I've adapted it to use Unity's XR interaction system. I used the XRI Default Input Actions included with Unity's XR Interaction Toolkit plugin in the
    8. /// Starter Assets Samples. The only other thing I did was make a separate Thumb Touched button action in both Hand Interaction Action Maps of the XRI Default Input Action.inputactions, I filled it with bindings  like secondaryTouched, primaryTouched,
    9. /// thumbstickTouched, thumbtouch, and thumbresttouch.
    10. /// </summary>
    11.  
    12. public class HandAnim : MonoBehaviour
    13. {
    14.     [SerializeField] private Animator m_animator = null;
    15.     [SerializeField] private InputActionReference selectValueAction, activateValueAction, thumbTouchedAction;
    16.  
    17.     private const string ANIM_LAYER_NAME_POINT = "Point Layer", ANIM_LAYER_NAME_THUMB = "Thumb Layer", ANIM_PARAM_NAME_FLEX = "Flex", ANIM_PARAM_NAME_POSE = "Pose", ANIM_PARAM_NAME_PINCH = "Pinch";
    18.     private const float INPUT_RATE_CHANGE = 20.0f;
    19.     private int m_animLayerIndexThumb = -1, m_animLayerIndexPoint = -1, m_animParamIndexFlex = -1, m_animParamIndexPose = -1, m_animParamIndexPinch = -1;
    20.     private bool m_isPointing = false, m_isGivingThumbsUp = false;
    21.     private float m_pointBlend = 0.0f, m_thumbsUpBlend = 0.0f;
    22.     private Collider[] m_colliders = null;
    23.  
    24.     private enum HandPoseId
    25.     {
    26.         Default, //0
    27.         Generic, //1
    28.         PingPongBall, //2
    29.         Controller //3
    30.     }
    31.  
    32.     // Start is called before the first frame update
    33.     private void Start()
    34.     {
    35.         m_colliders = GetComponentsInChildren<Collider>().Where(childCollider => !childCollider.isTrigger).ToArray();
    36.         for (int i = 0; i < m_colliders.Length; ++i)
    37.         {
    38.             m_colliders[i].enabled = false;
    39.         }
    40.  
    41.         m_animLayerIndexPoint = m_animator.GetLayerIndex(ANIM_LAYER_NAME_POINT);
    42.         m_animLayerIndexThumb = m_animator.GetLayerIndex(ANIM_LAYER_NAME_THUMB);
    43.         m_animParamIndexFlex = Animator.StringToHash(ANIM_PARAM_NAME_FLEX);
    44.         m_animParamIndexPose = Animator.StringToHash(ANIM_PARAM_NAME_POSE);
    45.         m_animParamIndexPinch = Animator.StringToHash(ANIM_PARAM_NAME_PINCH);
    46.  
    47.         selectValueAction.action.performed += OnGrip;
    48.         activateValueAction.action.performed += OnPointOrPinch;
    49.         thumbTouchedAction.action.started += OnThumbTouch;
    50.         thumbTouchedAction.action.canceled += OnThumbTouch;
    51.     }
    52.  
    53.     private void OnDestroy()
    54.     {
    55.         selectValueAction.action.performed -= OnGrip;
    56.         activateValueAction.action.performed -= OnPointOrPinch;
    57.         thumbTouchedAction.action.started -= OnThumbTouch;
    58.         thumbTouchedAction.action.canceled -= OnThumbTouch;
    59.     }
    60.     // Update is called once per frame
    61.     private void Update()
    62.     {
    63.         m_animator.SetInteger(m_animParamIndexPose, (int)HandPoseId.Default);
    64.  
    65.         m_pointBlend = Mathf.Clamp01(m_pointBlend + (Time.deltaTime * INPUT_RATE_CHANGE) * (m_isPointing ? 1.0f : -1.0f));
    66.         m_thumbsUpBlend = Mathf.Clamp01(m_thumbsUpBlend + (Time.deltaTime * INPUT_RATE_CHANGE) * (m_isGivingThumbsUp ? 1.0f : -1.0f));
    67.         m_animator.SetLayerWeight(m_animLayerIndexPoint, m_pointBlend);
    68.         m_animator.SetLayerWeight(m_animLayerIndexThumb, m_thumbsUpBlend);
    69.     }
    70.  
    71.     private void OnGrip(InputAction.CallbackContext ctx)
    72.     {
    73.         m_animator.SetFloat(m_animParamIndexFlex, ctx.ReadValue<float>());
    74.     }
    75.  
    76.     private void OnPointOrPinch(InputAction.CallbackContext ctx)
    77.     {
    78.         m_isPointing = !ctx.ReadValueAsButton();
    79.         m_animator.SetFloat(m_animParamIndexPinch, ctx.ReadValue<float>());
    80.     }
    81.  
    82.     private void OnThumbTouch(InputAction.CallbackContext ctx)
    83.     {
    84.         m_isGivingThumbsUp = !ctx.ReadValueAsButton();
    85.     }