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,130 @@
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
using UnityEngine;
namespace VirtualGrasp.Onboarding
{
/**
* AssembleArticulationBody shows as a tutorial on how to use VG to
* assemble and dissemble objects through Unity's ArticulationBody.
*/
[LIBVIRTUALGRASP_UNITY_SCRIPT]
[HelpURL("https://docs.virtualgrasp.com/unity_vgonboarding_task4." + VG_Version.__VG_VERSION__ + ".html")]
public class AssembleArticulationBody : MonoBehaviour
{
public Transform m_newParent = null;
public Transform m_desiredPose = null;
public float m_assembleDistance = 0.05f;
public float m_disassembleDistance = 0.5f;
public ArticulationJointType m_jointType = ArticulationJointType.FixedJoint;
public bool m_matchAnchors = true;
public Vector3 m_anchorPosition = Vector3.zero;
public Vector3 m_anchorRotation = Vector3.zero;
public Vector3 m_parentAnchorPosition = Vector3.zero;
public Vector3 m_parentAnchorRotation = Vector3.zero;
public AudioSource m_turnWheelEffect;
private ArticulationBody m_this_ab;
private ArticulationBody m_parent_ab;
private float timeAtDisassemble = 0.0F;
private float assembleDelay = 1.0F;
private float m_state = 0;
void Start()
{
gameObject.TryGetComponent<ArticulationBody>(out m_this_ab);
if (m_newParent != null)
{
if (!m_newParent.TryGetComponent<ArticulationBody>(out m_parent_ab))
{
Debug.LogWarning("New parent " + m_newParent.name + " should have Articulation Body component, will add one in script");
m_parent_ab = m_newParent.gameObject.AddComponent<ArticulationBody>();
}
}
else
Debug.LogError("Need to specify assembling New Parent!");
// Uncomment for sound effect
if (m_turnWheelEffect != null)
InvokeRepeating("turnWheelEffect", 0.0F, .5F);
}
void LateUpdate()
{
assembleArticulationBody();
dissembleArticluationBody();
}
void assembleArticulationBody()
{
if (m_this_ab == null || m_parent_ab == null)
{
Debug.LogError("Object do no have articulation body, so can't do articulation body based assembling!");
return;
}
if ((Time.realtimeSinceStartup - timeAtDisassemble) > assembleDelay
&& (m_desiredPose.position - transform.position).magnitude < m_assembleDistance
&& transform.parent != m_newParent)
{
m_desiredPose.gameObject.SetActive(false);
// Project object rotation axis to align to desired rotation axis.
transform.SetPositionAndRotation(m_desiredPose.position, Quaternion.LookRotation(m_desiredPose.forward, transform.up));
transform.SetParent(m_newParent);
m_this_ab.jointType = m_jointType;
#if UNITY_2021_2_OR_NEWER
m_this_ab.matchAnchors = m_matchAnchors;
#elif UNITY_2021_1
m_this_ab.computeParentAnchor = m_matchAnchors;
#endif
m_this_ab.anchorPosition = m_anchorPosition;
m_this_ab.anchorRotation = Quaternion.Euler(m_anchorRotation);
m_this_ab.parentAnchorPosition = m_parentAnchorPosition;
m_this_ab.parentAnchorRotation = Quaternion.Euler(m_parentAnchorRotation);
}
}
void turnWheelEffect()
{
if (transform.parent == m_newParent)
{
float newState = m_this_ab.jointPosition[0];
if (Mathf.Abs(newState - m_state) > .3 && !m_turnWheelEffect.isPlaying)
{
if (!m_turnWheelEffect.isPlaying)
m_turnWheelEffect.Play();
}
else if (Mathf.Abs(newState - m_state) < .3 && m_turnWheelEffect.isPlaying)
{
m_turnWheelEffect.Stop();
}
m_state = newState;
}
}
void dissembleArticluationBody()
{
foreach (VG_HandStatus hand in VG_Controller.GetHands())
{
if (hand.m_selectedObject == transform && hand.IsHolding() && transform.parent == m_newParent)
{
VG_Controller.GetSensorPose(hand.m_avatarID, hand.m_side, out Vector3 sensor_pos, out Quaternion sensor_rot);
if ((sensor_pos - hand.m_hand.position).magnitude > m_disassembleDistance)
{
m_desiredPose.gameObject.SetActive(true);
transform.SetParent(m_newParent.parent);
timeAtDisassemble = Time.realtimeSinceStartup;
}
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,40 @@
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
using UnityEngine;
namespace VirtualGrasp.Onboarding
{
/**
* ChangeSelectionWeight shows as a tutorial on how to runtime change object
* selection weight to affect how easy an object can be selected for interaction with VG.
*/
[LIBVIRTUALGRASP_UNITY_SCRIPT]
[HelpURL("https://docs.virtualgrasp.com/unity_vgonboarding_task3." + VG_Version.__VG_VERSION__ + ".html")]
public class ChangeSelectionWeight : MonoBehaviour
{
public Transform m_dependent_object;
public float m_releasedWeight = 1.0f;
public float m_graspedWeight = 2.0f;
void Start()
{
VG_Controller.OnObjectFullyReleased.AddListener(ObjectReleased);
VG_Controller.OnObjectGrasped.AddListener(ObjectGrasped);
if (m_dependent_object == null)
m_dependent_object = transform.parent;
}
void ObjectReleased(VG_HandStatus hand)
{
if (hand.m_selectedObject == m_dependent_object)
VG_Controller.SetObjectSelectionWeight(transform, m_releasedWeight);
}
void ObjectGrasped(VG_HandStatus handStatus)
{
if (handStatus.m_selectedObject == m_dependent_object)
VG_Controller.SetObjectSelectionWeight(transform, m_graspedWeight);
}
}
}

View File

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

View File

@@ -0,0 +1,117 @@
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
using System.Collections.Generic;
using UnityEngine;
namespace VirtualGrasp.Onboarding
{
/**
* ManageContainerObject shows as a tutorial on how to use the VG_Controller.OnObjectFullyReleased
* and VG_Controller.OnObjectGrasped combined with Unity's physical joints to manage a
* container object to hold the contained physical objects stably without falling off.
*/
[LIBVIRTUALGRASP_UNITY_SCRIPT]
[HelpURL("https://docs.virtualgrasp.com/unity_vgonboarding_task3." + VG_Version.__VG_VERSION__ + ".html")]
public class ManageContainerObject : MonoBehaviour
{
/// A set off objects that are actively colliding with this one.
private HashSet<Transform> m_collisions = new HashSet<Transform>();
/// A map of objects with ArticulationBody to their original parents.
private Dictionary<Transform, Transform> m_parentCache = new Dictionary<Transform, Transform>();
/// A map of objects with Rigidbody to the fixed joints connecting to this container object
private Dictionary<Transform, FixedJoint> m_attachJoints = new Dictionary<Transform, FixedJoint>();
/// If dot product between velocity and down is large enough (ie. vectors are aligned).
public float m_dropAlignment = 0.8f;
private void Start()
{
// Register the some grasp event listeners
VG_Controller.OnObjectFullyReleased.AddListener(OnObjectFullyReleased);
VG_Controller.OnObjectGrasped.AddListener(OnObjectGrasped);
}
private void OnCollisionEnter(Collision collision)
{
// See if the object in collision is actually held by a hand (and is not a hand itself).
bool valid_object = true;
foreach (VG_HandStatus hand in VG_Controller.GetHands())
{
if (hand.m_hand == collision.transform)
valid_object &= false;
if (hand.m_selectedObject == collision.transform && hand.IsHolding())
valid_object &= false;
}
if (valid_object && // If it's valid ...
(collision.rigidbody != null || collision.gameObject.TryGetComponent(out ArticulationBody ab)) && // and has a rigid body or articulation body ...
Vector3.Dot(collision.relativeVelocity.normalized, Vector3.down) > m_dropAlignment) // .. and if the object is dropped from somewhat above.
{
Attach(collision.transform);
m_collisions.Add(collision.transform);
}
}
private void OnCollisionExit(Collision collision)
{
m_collisions.Remove(collision.transform);
}
private void OnObjectFullyReleased(VG_HandStatus hand)
{
if (m_collisions.Contains(hand.m_selectedObject))
Attach(hand.m_selectedObject);
}
private void OnObjectGrasped(VG_HandStatus hand)
{
Unattach(hand.m_selectedObject);
}
void Attach(Transform attachedObject)
{
if (attachedObject.gameObject.TryGetComponent<Rigidbody>(out Rigidbody rb))
{
if (!attachedObject.gameObject.TryGetComponent<FixedJoint>(out FixedJoint joint))
{
joint = attachedObject.gameObject.AddComponent<FixedJoint>();
m_attachJoints[attachedObject] = joint;
if (transform.gameObject.TryGetComponent<Rigidbody>(out Rigidbody container_rb))
joint.connectedBody = container_rb;
else if (transform.gameObject.TryGetComponent<ArticulationBody>(out ArticulationBody container_ab))
joint.connectedArticulationBody = container_ab;
}
}
else if (attachedObject.gameObject.TryGetComponent<ArticulationBody>(out ArticulationBody ab))
{
if (transform.gameObject.TryGetComponent<ArticulationBody>(out ArticulationBody container_ab))
{
m_parentCache[attachedObject] = attachedObject.parent;
attachedObject.SetParent(transform);
ab.jointType = ArticulationJointType.FixedJoint;
}
else
Debug.LogError("Can not attach object " + attachedObject.name + " with ArticulationBody to " + transform.name + " without ArticulationBody.");
}
}
void Unattach(Transform attachedObject)
{
if (attachedObject.gameObject.TryGetComponent<Rigidbody>(out Rigidbody rb))
{
if (!m_attachJoints.ContainsKey(attachedObject))
return;
DestroyImmediate(m_attachJoints[attachedObject]);
m_attachJoints.Remove(attachedObject);
}
else if (attachedObject.gameObject.TryGetComponent<ArticulationBody>(out ArticulationBody ab))
{
if (!transform.gameObject.TryGetComponent<ArticulationBody>(out ArticulationBody container_ab))
return;
if (attachedObject.parent != transform)
return;
attachedObject.SetParent(m_parentCache[attachedObject]);
}
}
}
}

View File

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

View File

@@ -0,0 +1,34 @@
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
using UnityEngine;
namespace VirtualGrasp.Onboarding
{
public class MetalImpact : MonoBehaviour
{
public AudioSource plateCollisionEffect;
public AudioSource tableCollisionEffect;
private float verticalVelocityThreshold = 1.0F;
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.name.Contains("plate"))
{
if (collision.relativeVelocity.magnitude > verticalVelocityThreshold)
{
plateCollisionEffect.Play();
}
}
else if (collision.gameObject.name.Contains("SM_Factory1001"))
{
if (collision.relativeVelocity.magnitude > verticalVelocityThreshold)
{
tableCollisionEffect.Play();
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,50 @@
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
using UnityEngine;
namespace VirtualGrasp.Onboarding
{
public class SimpleImpact : MonoBehaviour
{
public AudioSource collisionEffect;
private float unityVelocityThreshold = 1.0F;
private float calculatedVelocityThreshold = .1F;
ArticulationBody ownAB = null;
Rigidbody ownRB = null;
private void Start()
{
gameObject.TryGetComponent<Rigidbody>(out ownRB);
gameObject.TryGetComponent<ArticulationBody>(out ownAB);
}
private void OnCollisionEnter(Collision collision)
{
if (collision.relativeVelocity.magnitude > 0) // sometimes we're lucky. unity calculates speed for us
{
if (collision.relativeVelocity.magnitude > unityVelocityThreshold)
collisionEffect.Play();
}
else if (
#if UNITY_2020_3_16_OR_NEWER
collision.body != null &&
#endif
(ownRB != null || ownAB != null))
{ // sometimes we're not lucky, have to calculate
Vector3 ownSpeed = ownRB != null ? ownRB.velocity : ownAB.velocity;
Vector3 colliderSpeed = Vector3.zero;
#if UNITY_2020_3_16_OR_NEWER
if (collision.rigidbody != null) colliderSpeed = collision.rigidbody.velocity;
else if (collision.articulationBody != null) colliderSpeed = collision.articulationBody.velocity;
#else
if (collision.rigidbody != null) colliderSpeed = collision.rigidbody.velocity;
#endif
if ((ownSpeed - colliderSpeed).magnitude > calculatedVelocityThreshold)
collisionEffect.Play();
}
}
}
}

View File

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

View File

@@ -0,0 +1,25 @@
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
using UnityEngine;
using VirtualGrasp;
namespace VirtualGrasp.Onboarding
{
public class SoundOnGraspEvents : MonoBehaviour
{
public AudioSource graspSoundEffect;
private int avatarID = 0;
private void Start()
{
VG_Controller.GetSensorControlledAvatarID(out avatarID);
VG_Controller.OnGraspTriggered.AddListener(PlayGraspSound);
}
public void PlayGraspSound(VG_HandStatus hand)
{
if (hand.m_avatarID == avatarID)
graspSoundEffect.Play();
}
}
}

View File

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

View File

@@ -0,0 +1,23 @@
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
using UnityEngine;
namespace VirtualGrasp.Onboarding
{
public class SoundOnPushEvents : MonoBehaviour
{
public AudioSource pushSoundEffect;
// Start is called before the first frame update
void Start()
{
VG_Controller.OnObjectPushed.AddListener(PlayPushSound);
}
public void PlayPushSound(VG_HandStatus hand)
{
if (hand.m_selectedObject != null && hand.m_selectedObject == transform)
pushSoundEffect.Play();
}
}
}

View File

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

View File

@@ -0,0 +1,61 @@
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
using UnityEngine;
namespace VirtualGrasp.Onboarding
{
/**
* ToggleLight shows as a tutorial on a non-physical two-stage button setup
* through VG_Articulation and how to use VG_Controller.GetObjectJointState to toggle light on and off.
*/
[LIBVIRTUALGRASP_UNITY_SCRIPT]
[HelpURL("https://docs.virtualgrasp.com/unity_vgonboarding_task1.html")]
public class ToggleLight : MonoBehaviour
{
public GameObject m_light = null;
public GameObject m_light2 = null;
private VG_Articulation m_articulation = null;
public AudioSource m_audioSourceOn;
public AudioSource m_audioSourceOff;
private float m_state;
private bool m_binState = false;
void Start()
{
if (TryGetComponent<VG_Articulation>(out m_articulation))
{
VG_Controller.GetObjectJointState(transform, out m_state);
EvaluateState(m_state);
}
}
void Update()
{
VG_Controller.GetObjectJointState(transform, out float newState);
if (newState != m_state)
EvaluateState(newState);
m_state = newState;
}
void EvaluateState(float state)
{
if (state == m_articulation.m_min && m_binState)
{
m_binState = false;
m_light.SetActive(false);
m_light2.SetActive(false);
m_audioSourceOff.Play();
}
else if (state == m_articulation.m_max && !m_binState)
{
m_binState = true;
m_light.SetActive(true);
m_light2.SetActive(true);
m_audioSourceOn.Play();
}
}
}
}

View File

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