Aller au contenu principal

Tutoriel VerseGrip sur le contrôle de position

Ce tutoriel explique comment utiliser la rotation du VerseGrip pour contrôler directement la position du curseur d'un appareil Inverse3, tout en contournant le thread principal de Unity pour les mises à jour à haute fréquence.

Introduction​

Contrairement à la méthode décrite dans la Guide « Premiers pas », qui fonctionne à une fréquence de rafraîchissement standard (60 Hz), ce tutoriel a pour objectif d'ajuster dynamiquement la position du curseur de l'Inverse3 en fonction de la rotation de l'appareil VerseGrip, à une fréquence plus élevée (1 à 4 kHz). Pour ce faire, on utilise l'événement DeviceStateChanged qui est déclenchée par le fil haptique.

Mise en place des scènes​

Commencez par créer un « Haptic Rig » : GameObject > « Haply » > « Haptic Rig (one hand) », comme indiqué dans le guide « Premiers pas ».

Composant VerseGripPositionControl​

Créez un nouveau script C# nommé VerseGripPositionControl.cs et attachez-le au GameObject Origine haptique an. Définissez dans la classe VerseGripPositionControl les caractéristiques suivantes :

public Inverse3 inverse3;
public VerseGrip verseGrip;

[Range(0, 1)]
public float speed = 0.5f;

[Range(0, 0.2f)]
public float movementLimitRadius = 0.2f;

private Vector3 _targetPosition;
  • inverse3: Référence à l'appareil « Inverse3 », définie dans l'Inspecteur.
  • verseGrip: référence à l'appareil VerseGrip utilisé pour le contrôle du curseur.
  • vitesse: vitesse à laquelle se déplace le curseur.
  • movementLimitRadius: distance maximale à laquelle le curseur peut s'éloigner de sa position initiale.
  • _targetPosition: position cible vers laquelle se déplace le curseur.

Méthode Awake​

Enregistrez-vous dans la méthode Awake l'événement Ready, afin d'initialiser la position cible du curseur en fonction du centre de l'espace de travail du périphérique « Inverse3 » :

private void Awake()
{
inverse3.Ready.AddListener((inverse3Controller, args) =>
{
_targetPosition = inverse3Controller.WorkspaceCenterLocalPosition;
});
}

Avant que l'appareil ne soit opérationnel, le centre de l'espace de travail n'est pas encore disponible, car la direction d'utilisation n'a pas encore été déterminée.

Implémentez la méthode OnDeviceStateChanged, afin de calculer la position cible du curseur à partir de la rotation du VerseGrip et de la saisie au clavier :

private void OnDeviceStateChanged(object sender, VerseGripEventArgs args)
{
var verseGrip = args.DeviceController;
// Calculate the direction based on the VerseGrip's rotation
var direction = verseGrip.Orientation * Vector3.forward;

// Check if the VerseGrip button is pressed down
if (verseGrip.GetButtonDown())
{
// Initialize target position
_targetPosition = inverse3.CursorLocalPosition;
}

// Check if the VerseGrip button is being held down
if (verseGrip.GetButton())
{
// Move the target position toward the grip direction
_targetPosition += direction * (0.0001f * speed);

// Clamp the target position within the movement limit radius
var workspaceCenter = inverse3.WorkspaceCenterLocalPosition;
_targetPosition = Vector3.ClampMagnitude(_targetPosition - workspaceCenter, movementLimitRadius)
+ workspaceCenter;
}
// Move cursor to new position
inverse3.SetCursorLocalPosition(_targetPosition);
}

Enregistrez l'événement DeviceStateChanged dans OnEnable et effectuez l'enregistrement dans OnDisable à nouveau.

/// Subscribes to the DeviceStateChanged event.
private void OnEnable()
{
verseGrip.DeviceStateChanged += OnDeviceStateChanged;
}

/// Unsubscribes from the DeviceStateChanged event.
private void OnDisable()
{
verseGrip.DeviceStateChanged -= OnDeviceStateChanged;
}

Gameplay​

  • Fixez l'appareil Inverse3 et assurez-vous qu'il dispose de suffisamment d'espace pour bouger.
  • Lancez le mode Lecture et maintenez le curseur « Inverse3 » enfoncé.
  • Faites pivoter l'appareil VerseGrip pour observer le déplacement du curseur dans la scène Unity, qui correspond exactement à l'orientation du VerseGrip.
  • En appuyant sur le bouton du VerseGrip, le curseur « Inverse3 » peut se déplacer dans le sens de la rotation du VerseGrip. Cela permet de visualiser le contrôle en temps réel.

Balle mobile avec poignée « Versegrip »

L'illustration présente le modèle de curseur avec son axe avant mis en évidence pour plus de clarté. Vous trouverez plus de détails sur la personnalisation du modèle de curseur dans la documentation relative au curseur.

Fichiers source​

La scène terminée et tous les fichiers associés à cet exemple peuvent être importés via la section « Exemples de tutoriels » du gestionnaire de paquets de Unity.

VerseGripPositionControl.cs​

/*
* Copyright 2024 Haply Robotics Inc. All rights reserved.
*/

using Haply.Inverse.DeviceControllers;
using Haply.Inverse.DeviceData;
using UnityEngine;

namespace Haply.Samples.Tutorials._6_VerseGripPositionControl
{
/// <summary>
/// Demonstrates how to control the device cursor position using the VerseGrip.
/// </summary>
public class VerseGripPositionControl : MonoBehaviour
{
public Inverse3Controller inverse3;
public VerseGripController verseGrip;

[Tooltip("Cursor moving speed")]
[Range(0, 1)]
public float speed = 0.5f;

[Tooltip("Maximum radius for cursor movement")]
[Range(0, 0.1f)]
public float movementLimitRadius = 0.075f;

private Vector3 _targetPosition; // Target position for the cursor

private void Awake()
{
inverse3.Ready.AddListener((inverse3Controller, args) =>
{
_targetPosition = inverse3Controller.WorkspaceCenterLocalPosition;
});
}

/// <summary>
/// Subscribes to the DeviceStateChanged event.
/// </summary>
private void OnEnable()
{
verseGrip.DeviceStateChanged += OnDeviceStateChanged;
}

/// <summary>
/// Unsubscribes from the DeviceStateChanged event.
/// </summary>
private void OnDisable()
{
verseGrip.DeviceStateChanged -= OnDeviceStateChanged;
inverse3.Release();
}

private void OnDeviceStateChanged(object sender, VerseGripEventArgs args)
{
var verseGrip = args.DeviceController;
// Calculate the direction based on the VerseGrip's rotation
var direction = verseGrip.Orientation * Vector3.forward;

// Check if the VerseGrip button is pressed down
if (verseGrip.GetButtonDown())
{
// Initialize target position
_targetPosition = inverse3.CursorLocalPosition;
}

// Check if the VerseGrip button is being held down
if (verseGrip.GetButton())
{
// Move the target position toward the grip direction
_targetPosition += direction * (0.0001f * speed);

// Clamp the target position within the movement limit radius
var workspaceCenter = inverse3.WorkspaceCenterLocalPosition;
_targetPosition = Vector3.ClampMagnitude(_targetPosition - workspaceCenter, movementLimitRadius)
+ workspaceCenter;
}
// Move cursor to new position
inverse3.SetCursorLocalPosition(_targetPosition);
}
}
}