Zum Hauptinhalt springen

VerseGrip Tutorial zur Positionssteuerung

Dieses Tutorial zeigt, wie Sie die Rotation des VerseGrip nutzen, um die Cursorposition eines Inverse3-Geräts direkt zu steuern, und dabei den Hauptthread von Unity für hochfrequente Aktualisierungen umgehen.

Einführung​

Anders als bei der Methode aus der Anleitung „Erste Schritte“, die mit einer üblichen Aktualisierungsfrequenz (60Hz) arbeitet, zielt dieses Tutorial darauf ab, die Cursorposition des Inverse3 dynamisch anhand der Rotation des VerseGrip-Geräts mit einer höheren Frequenz (1~4kHz) anzupassen. Dies wird erreicht, indem das Ereignis DeviceStateChanged genutzt wird, das vom haptischen Thread ausgelöst wird.

Szenen-Setup​

Beginnen Sie, indem Sie einen Haptic Rig erstellen: GameObject > Haply > Haptic Rig (one hand), wie in der Anleitung „Erste Schritte“ beschrieben.

Komponente VerseGripPositionControl​

Erstellen Sie ein neues C#-Skript namens VerseGripPositionControl.cs und hängen Sie es an das GameObject Haptic Origin an. Definieren Sie in der Klasse VerseGripPositionControl die folgenden Eigenschaften:

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: Verweis auf das Inverse3-Gerät, der im Inspector festgelegt wird.
  • verseGrip: Verweis auf das VerseGrip-Gerät, das für die Cursorsteuerung verwendet wird.
  • speed: Geschwindigkeit, mit der sich der Cursor bewegt.
  • movementLimitRadius: Maximaler Abstand, den der Cursor von seiner Ausgangsposition entfernt sein darf.
  • _targetPosition: Zielposition, auf die sich der Cursor zubewegt.

Methode Awake​

Registrieren Sie in der Methode Awake das Ereignis Ready, um die Zielposition des Cursors anhand des Mittelpunkts des Arbeitsraums des Inverse3-Geräts zu initialisieren:

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

Bevor das Gerät betriebsbereit ist, steht der Mittelpunkt des Arbeitsraums noch nicht zur Verfügung, da die Händigkeit noch nicht bestimmt ist.

Implementieren Sie die Methode OnDeviceStateChanged, um die Zielposition des Cursors anhand der Rotation des VerseGrip und der Tastereingabe zu berechnen:

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);
}

Registrieren Sie das Ereignis DeviceStateChanged in OnEnable und heben Sie die Registrierung in OnDisable wieder auf.

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

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

Gameplay​

  • Befestigen Sie das Gerät Inverse3 und stellen Sie sicher, dass es genügend Platz für die Bewegung hat.
  • Starten Sie den Play Mode und halten Sie den Inverse3-Cursor.
  • Drehen Sie das Gerät VerseGrip, um die Bewegung des Cursors in der Unity-Szene zu beobachten, die direkt der Ausrichtung von VerseGrip entspricht.
  • Durch Drücken der Taste von VerseGrip kann sich der Inverse3-Cursor in Richtung der Drehung von VerseGrip bewegen. Dies demonstriert die Steuerung in Echtzeit.

Sich bewegender Ball mit versegrip

Die Abbildung zeigt das Cursor-Modell mit seiner hervorgehobenen Vorwärtsachse zur besseren Übersicht. Weitere Details zur Anpassung des Cursor-Modells finden Sie in der Cursor-Dokumentation.

Quelldateien​

Die fertige Szene und alle zugehörigen Dateien dieses Beispiels können über das Beispiel Tutorials im Paketmanager von Unity importiert werden.

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);
}
}
}