본문으로 건너뛰기

기본적인 힘과 위치에 관한 튜토리얼

이 가이드에서는 힘을 가해 Inverse3 커서의 움직임을 시각화하는 간단한 데모를 소개합니다. 이 튜토리얼의 마지막 부분에서는Inverse3 가 마치 가상의 고무줄로 시작 위치에 연결된 듯한 느낌을 시뮬레이션하고, 구형 GameObject가 커서의 위치를 표시합니다.

서문​

입문 가이드에서는,Inverse3 객체와 그 기능, 그리고 일정한 힘을 생성하는 방법을 소개했습니다. 여기서의 목적은 커서에 고무줄 효과를 시뮬레이션하는 것입니다. 고무줄은 스프링과 마찬가지로 작동하며, 그 힘은 양 끝점 사이의 강성과 거리 모두에 영향을 받습니다. 따라서 위치와 강성을 주면, 커서가 원점에서 멀어지는 움직임에 저항하는 힘을 생성하는 함수를 고안하는 것을 목표로 합니다.

장면 설정​

‘GameObjects > Haply ’ 메뉴에서 ‘Haptic Rig (one hand) ’를 생성하여 시작합니다.

ForceAndPosition 컴포넌트​

햅틱 오리진 GameObject를 선택하고,ForceAndPosition.cs 라는 이름의 새로운 스크립트를 추가하고, 다음 코드를 사용하여 ForceAndPosition 클래스를 정의합니다:

[SerializeField]
private Inverse3 inverse3 = null;

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

private void OnDeviceStateChanged(object sender, Inverse3EventArgs args)
{
var inverse3 = args.DeviceController;

// Calculate the force.
var force = (inverse3.WorkspaceCenterLocalPosition - inverse3.CursorLocalPosition) * stiffness;

// Apply the force to the cursor.
inverse3.SetCursorLocalForce(force);
}

이 코드 조각에서는 강성을 100 뉴턴/미터(N/m)로 설정하여 비교적 부드러운 스프링을 시뮬레이션합니다. 또한, 작업 공간의 중심을 반환하는 속성인 inverse3.WorkspaceCenterLocalPosition 을 도입합니다. 이 메서드는 워크스페이스의 중심에서 커서 위치를 뺀 값을 바탕으로 힘을 계산하고, 그 결과에 강성을 곱합니다. 마지막으로,inverse3.SetCursorLocalForce 을 사용하여 그 힘을 커서에 적용합니다.

입문 가이드 에서 자세히 설명된 바와 같이,OnEnable 그리고 OnDisable 메서드에 OnDeviceStateChanged 콜백을 구현합니다:

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

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

게임 플레이​

Inverse3 커서를 잡고 ‘Play Mode’를 활성화한 후, 장치를 조작해 보세요. 커서를 움직이면 힘이 발생하는 것을 확인할 수 있습니다. 커서를 시작 위치에서 멀리 이동시킬수록 이 힘은 더욱 뚜렷해집니다.

커서 이동

소스 파일​

이 예제에서 사용되는 최종 장면과 관련 파일은 모두 Unity 패키지 관리자의 ‘Tutorials’ 샘플에서 가져올 수 있습니다.

ForceAndPosition.cs​

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

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

namespace Haply.Samples.Tutorials._1_ForceAndPosition
{
/// <summary>
/// Demonstrates the application of force to maintain the cursor at its center position.
/// </summary>
public class ForceAndPosition : MonoBehaviour
{
public Inverse3Controller inverse3;

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

private void Awake()
{
inverse3 ??= FindObjectOfType<Inverse3Controller>();
}

/// <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;
inverse3.Release();
}

/// <summary>
/// Event handler that calculates and send the force to the device when the cursor's position changes.
/// </summary>
/// <param name="sender">The Inverse3 data object.</param>
/// <param name="args">The event arguments containing the device data.</param>
private void OnDeviceStateChanged(object sender, Inverse3EventArgs args)
{
var inverse3 = args.DeviceController;

// Calculate the force.
var force = (inverse3.WorkspaceCenterLocalPosition - inverse3.CursorLocalPosition) * stiffness;

// Apply the force to the cursor.
inverse3.SetCursorLocalForce(force);
}
}
}