VerseGrip 位置制御チュートリアル
このチュートリアルでは、VerseGripの回転機能を利用して、Inverse3 デバイスのカーソル位置を直接制御し、その際にUnityのメインスレッドを迂回して高頻度な更新を行う方法について解説します。
はじめに
前述の方法とは異なり、 「はじめに」のガイド、通常の更新周波数(60Hz)で動作するInverse3 のカーソル位置を、VerseGripデバイスの回転に基づいて、より高い周波数(1~4kHz)で動的に調整することを、このチュートリアルでは目指しています。
これは、イベント DeviceStateChanged ハプティックスレッドによってトリガーされるものが使用されます。
シーンの設定
まず、「ハプティック・リグ」を作成することから始めましょう。「ハプティック・リグ」の作成方法は、「はじめに」のガイドに記載されている通り、「GameObject 」 >「Haply 」>「Haptic Rig (one hand) 」の順に選択します。
コンポーネント VerseGripPositionControl
「」という名前の新しい C# スクリプトを作成してください。 VerseGripPositionControl.cs そして、それをGameObjectにアタッチしてください ハプティック・オリジン an.
クラス内で次のように定義してください VerseGripPositionControl 以下の特徴:
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: インスペクタで指定される「Inverse3 」デバイスへの参照。
- verseGrip:カーソル操作に使用されるVerseGripデバイスを指します。
- speed:カーソルの移動速度。
- movementLimitRadius: カーソルが開始位置から離れてよい最大距離。
- _targetPosition: カーソルが移動する先の目標位置。
メソッド・アウェイク
メソッド内で登録してください Awake その出来事 Ready、Inverse3 デバイスの作業領域の中心を基準にしてカーソルの目標位置を初期化するには:
private void Awake()
{
inverse3.Ready.AddListener((inverse3Controller, args) =>
{
_targetPosition = inverse3Controller.WorkspaceCenterLocalPosition;
});
}
装置が稼働可能になるまでは、利き手がまだ決定されていないため、作業領域の中心点は利用できません。
メソッドを実装してください OnDeviceStateChanged、VerseGripの回転とボタン操作に基づいてカーソルの目標位置を計算するために:
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);
}
イベントを登録してください DeviceStateChanged で OnEnable そして、登録を OnDisable 再び。
/// Subscribes to the DeviceStateChanged event.
private void OnEnable()
{
verseGrip.DeviceStateChanged += OnDeviceStateChanged;
}
/// Unsubscribes from the DeviceStateChanged event.
private void OnDisable()
{
verseGrip.DeviceStateChanged -= OnDeviceStateChanged;
}
ゲームプレイ
- 本機をInverse3 に固定し、動作に必要な十分なスペースを確保してください。
- プレイモードを起動し、Inverse3 のカーソルを長押ししてください。
- VerseGrip本体を回転させると、Unityシーン内でカーソルの動きが、VerseGripの向きにそのまま連動して変化するのが確認できます。
- VerseGripのボタンを押すと、Inverse3 のカーソルがVerseGripの回転方向に移動します。これにより、リアルタイムでの制御が実演されます。

この図は、より見やすくするために、前方軸が強調表示されたカーソルモデルを示しています。 カーソルモデルのカスタマイズに関する詳細については、カーソルのドキュメントをご覧ください。
ソースファイル
この例の完成したシーンおよび関連するすべてのファイルは、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);
}
}
}