VerseGrip 위치 제어 튜토리얼
이 튜토리얼에서는 VerseGrip의 회전 기능을 활용하여 Unity의 메인 스레드를 우회함으로써, Inverse3 기기의 커서 위치를 고주파수로 직접 제어하는 방법을 설명합니다.
소개
에서 소개된 방법과는 달리 시작 가이드, 표준 재생 빈도(60Hz)로 작동하는 이 튜토리얼은 VerseGrip 기기의 회전 각도에 따라 커서 Inverse3 의 위치를 더 높은 주파수(1~4kHz)로 동적으로 조정하는 방법을 다룹니다.
이는 다음 이벤트를 활용하여 구현됩니다. DeviceStateChanged, 햅틱 스레드에 의해 촉발된.
장면 설정
시작 가이드에 설명된 대로, 먼저 ‘Haptic Rig’를 생성하세요: GameObject > Haply > Haptic Rig (one hand).
VerseGripPositionControl 구성 요소
다음과 같은 이름의 새로운 C# 스크립트를 만드세요. VerseGripPositionControl.cs 그리고 이를 게임 오브젝트에 연결하세요 햅틱 오리진.
클래스에서 다음 속성을 정의하십시오. 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 장치를 가리킵니다.
- 속도: 커서의 이동 속도.
- 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 dans OnEnable et 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 패키지 관리자의 ‘Tutorials’ 예제에서 가져올 수 있습니다.
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);
}
}
}