주요 콘텐츠로 건너뛰기
버전: 2.0.0

기본 힘과 위치 튜토리얼

이 가이드에서는 힘을 가하고 Inverse3 커서의 움직임을 시각화하는 간단한 데모를 제공합니다. 마지막에는 Inverse3가 가상의 고무줄로 시작 위치에 묶여 있는 느낌을 시뮬레이션하고 구형 게임 오브젝트가 커서의 위치를 표시합니다.

소개

빠른 시작 안내서에서 Inverse3 객체와 그 기능, 일정한 힘을 생성하는 방법을 소개했습니다. 여기서 우리의 목표는 커서에 고무줄 효과를 시뮬레이션하는 것입니다. 고무줄은 스프링과 유사하게 작동하므로 힘은 강성과 두 끝점 사이의 거리 모두에 영향을 받습니다. 따라서 위치와 강성이 주어지면 커서가 원점에서 멀어지지 않도록 저항하는 힘을 생성하는 함수를 고안하는 것이 목표입니다.

장면 설정

게임 오브젝트 > 햅리 메뉴를 통해 햅틱 릭(한 손) 을 생성하여 시작합니다.

ForceAndPosition 컴포넌트

를 선택하고 햅틱 오리진 게임 오브젝트에서 새 스크립트를 추가합니다. ForceAndPosition.cs 를 클릭하고 ForceAndPosition 클래스에 다음 코드를 추가합니다:

[SerializeField]
private Inverse3 inverse3 = null;

[SerializeField, Range(0, 400)]
private float stiffness = 100;

private Vector3 _initialPosition = Vector3.zero;

private Vector3 ForceCalculation(in Vector3 position)
{
if (_initialPosition == Vector3.zero)
{
// Save the initial device effector position
_initialPosition = position;
}
// Return force opposing movement from the initial position
return (_initialPosition - position) * stiffness;
}

이 세그먼트는 강성을 100N/m(뉴턴/미터)로 설정하여 비교적 부드러운 스프링을 시뮬레이션합니다. 또한 다음을 소개합니다. _initialPosition커서의 시작 위치를 캡처하는 벡터입니다. 벡터의 ForceCalculation 메서드는 처음 실행되는 동안 초기 위치를 기록하고 이후 커서의 움직임에 반대되는 힘 출력을 계산합니다.

통합 OnDeviceStateChanged 콜백의 OnEnable 그리고 OnDisable 메서드에 설명된 대로 빠른 시작 가이드:

protected void OnEnable()
{
inverse3.DeviceStateChanged += OnDeviceStateChanged;
}

protected void OnDisable()
{
inverse3.DeviceStateChanged -= OnDeviceStateChanged;
}

게임 플레이

Inverse3 커서를 누른 상태에서 재생 모드를 활성화하고 디바이스를 조작해 봅니다. 커서를 움직이면 힘이 발생하는 것을 확인할 수 있습니다. 커서가 시작 위치에서 더 멀리 이동할수록 이 힘은 더 뚜렷해집니다.

커서 이동

소스 파일

이 예제에서 사용된 최종 씬과 모든 관련 파일은 Unity 패키지 관리자의 튜토리얼 샘플에서 임포트할 수 있습니다.

ForceAndPosition.cs

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

using Haply.Inverse.Unity;
using UnityEngine;

namespace Haply.Samples.Tutorials._1_ForceAndPosition
{
/// <summary>
/// Demonstrates the application of force to maintain the cursor at its initial position.
/// </summary>
public class ForceAndPosition : MonoBehaviour
{
// Must be assigned in inspector
public Inverse3 inverse3;

[Range(0, 400)]
// Stiffness of the force feedback.
public float stiffness = 100;

// Stores the initial position of the cursor.
private Vector3 _initialPosition = Vector3.zero;

/// <summary>
/// Subscribes to the DeviceStateChanged event when the component is enabled.
/// </summary>
protected void OnEnable()
{
inverse3.DeviceStateChanged += OnDeviceStateChanged;
}

/// <summary>
/// Unsubscribes from the DeviceStateChanged event and reset the force when the component is disabled.
/// </summary>
protected void OnDisable()
{
inverse3.DeviceStateChanged -= OnDeviceStateChanged;
}

/// <summary>
/// Calculates the force required to maintain the cursor at its initial position.
/// </summary>
/// <param name="position">The current position of the cursor.</param>
/// <returns>The calculated force vector.</returns>
private Vector3 ForceCalculation(in Vector3 position)
{
if (_initialPosition == Vector3.zero)
{
// save the first device effector position
_initialPosition = position;
}
// return opposite force to stay at initial position
return (_initialPosition - position) * stiffness;
}

/// <summary>
/// Event handler that calculates and send the force to the device when the cursor's position changes.
/// </summary>
/// <param name="device">The Inverse3 device instance.</param>
private void OnDeviceStateChanged(Inverse3 device)
{
// Calculate the force.
var force = ForceCalculation(device.LocalPosition);

// Apply the force to the cursor.
inverse3.CursorSetLocalForce(force);
}
}
} // namespace Haply.Samples.Tutorials._1_ForceAndPosition