We have a series of VG onboarding tasks to show how to tackle different practical use cases using VirtualGrasp in a VR application. In VirtualGrasp SDK, they are packed in VirtualGrasp\Scenes\onboarding.

Task Description

Interaction behaviors wanted

  • We want to close the water bottle with the cap screwed on.
  • Neither the water bottle nor the cap are physical object, so can not use Unity’s physical joint support.

Tips for VR developers

  • VG_Articulation support creating joints on non-physical objects (objects without Rigidbody or ArticulationBody).

Solution

In VirtualGrasp SDK, we packed the solution of this task in VirtualGrasp/Scenes/onboarding.

VirtualGrasp/Scenes/onboarding/VG_Onboarding.unity
//VirtualGrasp/Scenes/onboarding/Scripts/AssembleVGArticulation.cs:

using UnityEngine;
using VirtualGrasp;
using System.Collections.Generic;

/** 
 * AssembleVGArticulation shows as a tutorial on how to use the VG_Controller.ChangeObjectJoint function for
 * assemble and dissemble non-physical objects (objects without rigid body or articulation body).
 */
public class AssembleVGArticulation : MonoBehaviour
{
    public Transform m_newParent = null;
    public Transform m_desiredPose = null;
    public float m_assembleDistance = 0.05f;
    public float m_disassembleDistance = 0.5f;
    public VG_Articulation m_assembleArticulation = null;

    private float timeAtDisassemble = 0.0F;
    private float assembleDelay = 1.0F;

    void Start()
    {
        
    }

    void Update()
    {
        assembleByJointChange();
        dessembleByJointChange();
    }

    void assembleByJointChange()
    {
        if ((Time.realtimeSinceStartup - timeAtDisassemble) > assembleDelay
           && (m_desiredPose.position - this.transform.position).magnitude < m_assembleDistance
           && VG_Controller.GetObjectJointType(this.transform, false) == VG_JointType.FLOATING)
        {
            m_desiredPose.gameObject.SetActive(false);
            this.transform.SetPositionAndRotation(m_desiredPose.position, m_desiredPose.rotation);

            if (m_newParent != null)
                this.transform.SetParent(m_newParent);

            VG_Controller.ChangeObjectJoint(transform, m_assembleArticulation);
        }
    }

    void dessembleByJointChange()
    {
        foreach (VG_HandStatus hand in VG_Controller.GetHands())
        {
            if (hand.m_selectedObject == transform && hand.IsHolding()
                && VG_Controller.GetObjectJointType(transform) != VG_JointType.FLOATING)
            {
                VG_Controller.GetSensorPose(hand.m_avatarID, hand.m_side, out Vector3 sensor_pos, out Quaternion sensor_rot);
               
                if (VG_Controller.GetObjectJointState(transform) == 0.0f
                    && (sensor_pos - hand.m_hand.position).magnitude > m_disassembleDistance)
                {
                    m_desiredPose.gameObject.SetActive(true);
                    VG_Controller.RecoverObjectJoint(transform);
                    transform.SetParent(m_newParent.parent);

                    timeAtDisassemble = Time.realtimeSinceStartup;
                }
            }
        }
    }
}

is the script showing how to use API function ChangeObjectJoint and RecoverObjectJoint to attach and unattach the cap on to the bottle.