EasyCastleUNITY

Haptics SDK for Unity 탐구 본문

Oculus VR 탐구

Haptics SDK for Unity 탐구

EasyCastleT 2023. 11. 19. 19:26

https://developer.oculus.com/experimental/exp-haptics-unity/

 

Haptics SDK for Unity | Oculus Developers

 

developer.oculus.com

이 글은 위 링크의 문서를 바탕으로 만들고 작성했으며, Oculus Integration SDK 57.0버전을 기준으로 작성되었습니다. 참고하여 주시기 바랍니다.

Overview

참고사항: 

1. Unity 용 Haptics SDK는 완성도가 높고 Production 앱을 사용할 준비가 된 것으로 간주합니다. Public Experiment tag는 Unity 및 Unread SDK에 집합적으로 적용됩니다. 2023년 후반에 Unreal SDK가 프로덕션으로 전환되면 이 사항은 제거됩니다. 

2. 여러분은 Oculus Store 및 AppLab에서 Unity용 Haptics SDK로 제작된 앱을 배포하는 것이 허용됩니다.

3. 이 SDK를 사용하기 위해 장치를 Experimental Mode 로 설정할 필요는 없습니다. 

 

유니티용 Haptics SDK는 Quest 컨트롤러의 Haptics Studio 에서 제작된 Haptic 클립을 재생하기 위한 높은 수준의 미디어 기반 API를 제공합니다. Haptic 클립을 재생하면 클립에 저장된 진동 패턴에 따라 컨트롤러가 진동합니다.

 

Haptics SDK는 연결된 Quest 컨트롤러의 Haptics Studio에서 제작된 Haptic 클립을 재생하기 위한 높은 수준의 미디어 기반 API를 제공합니다. Haptic 클립을 재생하면 클립에 저장된 진동 패턴에 따라 컨트롤러가 진동합니다. 

 

Haptics SDK는 연결된 Quest 컨트롤러 유형에 관계없이 통합된 Haptic API를 제공합니다. SDK는 런타임 시 컨트롤러를 감지하고 Haptic 패턴을 최적화하여 컨트롤러의 기능을 최대화합니다. 이 기능을 사용하면 Haptic 클립이 Quest 장치와 역호환 및 호환이 가능합니다.

 

Haptic SDK 다운로드

 

Process

Haptics SDK는 애플리케이션에서 Haptic 패턴을 재생하여 해당 .haptic 형식의 Haptic 클립을 재생하여 컨트롤러를 진동시킵니다.

 

절차는 다음과 같습니다. 

1. Haptics Studio에서 Haptic 클립을 디자인하거난 내보낸 .haptic 파일에서 시작합니다.

2. SDK는 Haptic 클립을 연결된 컨트롤러에 최적화된 진동 패턴으로 변환합니다. 

3. 진동 패턴이 컨트롤러로 전송되어 컨트롤러가 진동하도록 트리거 됩니다. 

Touch 컨트롤러에는 Touch Pro 및 Touch Plus 컨트롤러보다 덜 발전된  haptic actuators 가 있습니다. 진동 데이터에 대한 샘플링 속도가 더 낮으며 고정된 진동 주파수만 지원합니다. 따라서 Haptic 클립은 Touch 컨트롤러에서 진동 fidelity가 낮은 상태로 재생되며 사용자는 주파수 변화를 느끼지 못할 것입니다. Haptics SDK는 이러한 차이점을 투명하게 처리합니다. 

 

대부분의 Haptic 이벤트에는 동시에 재생되어야 하는 일치하는 오디오가 수반됩니다. 이 경우 SDK는 오디오 재생을 위한 api 를 제공하지 않으므로 기존 오디오 재생 API를 사용해야 합니다. 

Prerequisites(전제 조건)

Haptics SDK를 사용하려면 다음 사항이 있는지 확인하세요. 

  • 펌웨어 – SDK는 Quest 2, Quest Pro 및 Quest 3 헤드셋에서 작동합니다. 헤드셋은 펌웨어 버전 v47 이상을 실행해야 합니다.
  • 컨트롤러 – 헤드셋은 Touch, Touch Pro 또는 Touch Plus 컨트롤러와 페어링될 수 있습니다.
  • Unity 버전 – Unity용 Haptics SDK는 macOS 및 Windows에서 Unity 2020.3.26 LTS부터 지원됩니다. Unity에서 Meta Quest 개발을 시작하려면 가이드를 따르세요 .
  • Oculus Utilities : Oculus Integration SDK(v47+)의  Oculus Utilities package 가 있어야 합니다. Oculus Integration SDK의 나머지 부분은 필요하지 않습니다. 보다 구체적으로 말하면 OVRPlugin 기본 라이브러리만 필요합니다. 
  • XR Provider : Oculus XR provider를 사용합니다. OpenXR Provider를 포함한 다른 Provider는 지원되지 않습니다.
  • Oculus Backend : Oculus XR Provider의 OpenXR Backend를 선택합니다. legacy VrAPI backend 는 지원되지 않습니다. 

Setup

설치 및 가져오기(Installation and Import)

Meta Quest 다운로드 페이지에서 Haptics SDK를 다운로드 할 수 있습니다. Unity 설명서에 따라 로컬 패키지로 설치하세요. 설치 후 Packages 디렉터리에 Meta XR Haptics SDK 폴더가 표시됩니다 .

Contents of the asset (asset 내용물)

Asset 콘텐츠에서 아무것도 제거하지 않는 것이 좋지만 필요한 경우 각 폴더 콘텐츠에 대한 개요는 다음과 같습니다. 

 

  • Editor : 햅틱 클립을 가져오는 데 필요한 스크립트입니다. 이 폴더는 햅틱 클립 작업을 위해 필수적입니다.
  • HapticSamples : 시작할 수 있도록 Meta에서 디자인한 작은 Haptic Clip 컬렉션입니다. 자신만의 Haptic을 디자인하고 샘플이 필요하지 않은 경우, 이 폴더를 제거하는 것이 안전합니다. 
  • 플러그인 : 핵심 기능을 제공하는 Quest(Android), macOS 및 Windows용 Unity 라이브러리용 Haptics SDK. 
  • 런타임 :  Haptic 재생을 트리거하는 데 필요한 모든 스크립트입니다. 이 폴더는 Haptic 재생에 필수적 입니다. 
  • 참고 : .cs 파일에는 추가 정보를 제공할 수 있는 API 문서가 포함되어 있습니다. 

Minimal integration example (최소 통합 예)

최소 통합 예제를 사용하면 Unity를 사용하여 Quest에서 Haptic을 빠르게 시작할 수 있습니다. 위에 설명된 대로 프로젝트를 설정한 후에는 패키지 관리자 창의 Meta XR Haptics SDK 패키지 샘플 섹션 내 가져오기 버튼을 눌러 최소 통합 예제를 가져올 수 있습니다. 

 

샘플을 Unity 프로젝트로 가져온 후 예제 장면 HapticsSampleScene.unity 를 로드할 수 있습니다 .

예제 장면에는 다음 구성요소가 포함되어 있습니다.

  • OVRCameraRig (Meta XR Core): 컨트롤러와 눈에 공간 앵커를 제공합니다 .
  • HapticsSdkPlaySample : 예제 스크립트 HapticsSdkPlaySample.cs를 보유하는 빈 게임 개체입니다.
  • HapticsSdkGuidanceText : 예제에 대한 지침입니다.

예제 앱을 구축하려면 여기 가이드를 따르세요. 기기에서 애플리케이션이 실행되면 화면의 지시를 따를 수 있습니다.

Haptic이 이 샘플에 어떻게 통합되었는지 확인하려면 샘플의 Assets/Scripts 폴더에 있는 HapticsSdkPlaySample.cs 스크립트를 확인 하세요. 

Integrating haptics (Haptic 통합)

Haptics Studio에서 내보낸 파일을 원하는 폴더에 놓아 통합할 수 있습니다. Unity용 Haptics SDK는 .haptic파일을 선택하여 Unity의 자산 데이터베이스로 가져옵니다. 또는 HapticSamples 폴더 햅틱 에 제공된 샘플을 사용하여 작업할 수 있습니다 .

 

이제 파일을 가져왔으므로 HapticClip  HapticClipPlayer.haptic 클래스를 사용하여 게임에서 파일을 재생할 수 있습니다 .

HapticClip 인스턴스화

프로젝트의 모든 햅틱 클립은 Unity 에셋 데이터베이스에서 HapticClip 으로 표시됩니다. 인스턴스화하는 방법에는 여러 가지가 있습니다.

  1. Unity 편집기에서 MonoBehaviour 스크립트 중 하나에 공개 데이터 멤버를 연결합니다 (아래 예 참조).
  2. Asset에 Asset Database를 만듭니다. 
 

Unity - Scripting API: AssetDatabase.CreateAsset

Use this method to create a native Unity asset. Native assets are those created by Unity (either in the editor or via script), and are in Unity’s serialized format. If an asset already exists the path you specify it will be overwritten with your new asse

docs.unity3d.com

3. HapticClip  ScriptableObject 로 인스턴스화 합니다. 

Controlling haptics

Play haptics

HapticClip을 생성한 후에는 HapticClipPlayer를 사용하여 특정 Quest 컨트롤러(왼쪽, 오른쪽 또는 둘 다)에서 재생할 수 있습니다 .

재생이 저절로 끝나도록 하거나 전화를 걸어 Stop()재생을 일찍 종료할 수 있습니다.

HapticClipPlayer 에서 사용하는 클립을 교체하려면 setter 를 사용 clip하고 재생할 새 클립을 할당하면 됩니다. 클립이 현재 재생 중인 경우 이 호출로 클립이 중지됩니다.

여러 개의 HapticClipPlayer 개체가 동시에 존재할 수 있습니다. 아래의 재생 우선순위 섹션에서는 햅틱 출력이 이들 사이에서 어떻게 해결되는지 설명합니다.

클립 플레이어가 더 이상 필요하지 않으면 Dispose()이를 사용하여 해제하세요.

다음은 Unity 에디터에서 HapticClip을 연결하여 인스턴스화하는 예입니다 .

using Oculus.Haptics;

public class MyClass : MonoBehaviour
{
    // Assign both clips in the Unity editor
    public HapticClip clip1;
    public HapticClip clip2;
    private HapticClipPlayer player;

    void Awake()
    {
        player = new HapticClipPlayer(clip1);
    }

    public void PlayHapticClip1()
    {
       player.Play(Controller.Left);
    }

    public void PlayHapticClip2()
    {
        // Setting a new clip will stop the current playback
        player.clip = clip2;
        // Let's start the player again with the new clip loaded
        player.Play(Controller.Left);
    }

    public void StopHaptics()
    {
        player.Stop();
    }

    void OnDestroy()
    {
        // Free the HapticClipPlayer
        player.Dispose();
    }

    void OnApplicationQuit()
    {
        // Free the Haptics runtime
        Haptics.Instance.Dispose();
    }
}

Playback priority (재생 우선순위)

주어진 순간에 하나의 HapticClipPlayer 만 각 컨트롤러에서 진동을 트리거할 수 있습니다. 여러 명의 플레이어가 동일한 컨트롤러에서 동시에 플레이하도록 설정한 경우 우선 순위가 가장 높은 플레이어만 진동을 유발합니다. 일부 플레이어의 우선순위가 동일한 경우 마지막으로 시작한 플레이어가 진동을 유발합니다. 속성을 사용하여 플레이어의 우선순위를 설정할 수 있습니다

 

HapticClipPlayer 가 재생을 시작하면 우선순위가 같거나 낮은 현재 활성 플레이어를 중단합니다. 플레이어가 재생을 마치면 다음으로 높은 우선순위를 가진 플레이어가 진동 트리거를 재개합니다.

 

Loop haptics (햅틱 반복)

 isLooping속성을 사용하여 클립 재생 반복을 활성화하거나 비활성화합니다. 재생 전이나 재생 중에 호출할 수 있습니다. 반복 재생은 다시 호출하거나 Stop()반복을 비활성화할 때까지 무한정 계속됩니다.

 

Modulate haptics (햅틱 변조)

amplitude및 속성 을 설정하여 재생 중에 진동의 강도나 빈도를 변경할 수 있습니다 frequencyShift. 재생 전과 재생 중에 이러한 속성을 설정할 수 있습니다. 재생 중에 이러한 속성을 여러 번 조정하면 시간이 지남에 따라 진폭과 주파수를 지속적으로 변경할 수 있습니다.

다음은 HapticClipPlayer 에서 루핑, 진폭 및 주파수 변조를 사용할 수 있는 방법을 보여주는 간단한 구동 예입니다 .

 

using Oculus.Haptics;

public class DriveCar : MonoBehaviour
{
    public HapticClip clip;	 // Assign this in the Unity editor
    private HapticClipPlayer player;

    void Awake()
    {
        player = new HapticClipPlayer(clip);
        // Optional: setting this clip to the highest priority.
        player.priority = 0;
        player.isLooping = true;
    }

    public void AcceleratorEngaged()
    {
        player.Play(Controller.Left);
    }

    public void AcceleratorDisengaged()
    {
        player.Stop();
    }

    // acceleratorPosition is in a range of
    // 0.0f to 1.0f where 1.0f is fully depressed
    public void AcceleratorPositionChanged(float acceleratorPosition)
    {
        if (0.0f > acceleratorPosition || acceleratorPosition > 1.0f)
        {
            return;
        }

        // amplitude is in a range of 0.0f to 1.0f
        player.amplitude = acceleratorPosition;
        // frequencyShift is in a range of -1.0f to 1.0f
        player.frequencyShift = (acceleratorPosition * 2.0f) - 1.0f;
    }

    void OnDestroy()
    {
        // Free the HapticClipPlayer
        player.Dispose();
    }

    void OnApplicationQuit()
    {
        // Free the Haptics runtime
        Haptics.Instance.Dispose();
    }
}

HapticClipPlayer properties (속성)

HapticClipPlayer 에는 개발에 유용할 수 있는 여러 속성이 있습니다. LogPlayerState예제는 아래 방법을 참조하세요 .

using Oculus.Haptics;

public class ClipPlayerProperties : MonoBehaviour
{
    public HapticClip clip;	 // Assign this in the Unity editor
    private HapticClipPlayer player;

    void Awake()
    {
        player = new HapticClipPlayer(clip);
        player.isLooping = true;
    }

    public void LogPlayerState()
    {
        // The duration of the active clip in seconds
        Debug.Log(player.clipDuration);
        // The amount by which the player amplitude is scaled
        // A value of 1 means no change in amplitude
        Debug.Log(player.amplitude);
        // The amount frequency of the player is shifted
        // A value of 0 means no frequency shift
        Debug.Log(player.frequencyShift);
        // The priority level of the player
        // A value of 128 represents the default priority
        // A lower value represents a higher priority and vice versa
        Debug.Log(player.priority);
    }

    void OnDestroy()
    {
        // Free the HapticClipPlayer
        player.Dispose();
    }

    void OnApplicationQuit()
    {
        // Free the Haptics runtime
        Haptics.Instance.Dispose();
    }
}

사용 사례

Spatial effects

거리 기반 진폭

햅틱 강도가 플레이어 캐릭터와 진동을 유발하는 개체 사이의 상대적 거리에 반응해야 하는 경우 클립의 진폭을 변경할 수 있습니다.

엔진이 공회전 중인 자동차와 같은 진동원에서 멀어지는 플레이어 캐릭터를 상상해 보십시오. 해당 오디오 및 촉각 효과는 플레이어 캐릭터와 진동 소스 사이의 거리가 증가 함에 따라 진폭이 감소 합니다 .

패닝

두 컨트롤러 모두에서 동일한 효과를 재생하고 두 컨트롤러의 진폭을 독립적으로 변조하여 패닝 효과를 만들 수 있습니다.

변형

각 이벤트에 대해 약간의 진폭과 주파수 변조를 사용하여 발자국이나 총소리와 같은 반복적인 촉각 이벤트에 변형을 추가할 수 있습니다.

생성적 햅틱

때로는 사용자 입력(예: 캔버스를 가로질러 달리는 페인트 붓, 자동차 가속 페달에 발을 딛는 사용자)을 기반으로 많은 변화와 역동성이 필요한 햅틱 효과를 생성하고 싶을 수도 있습니다.

고정된 진폭과 주파수를 사용하여 햅틱 클립을 생성하고, 클립을 반복한 다음, 들어오는 사용자 입력에 따라 실시간으로 재생을 변조하여 이러한 유형의 생성 효과를 생성할 수 있습니다.

오류 처리

일반적으로 Unity용 Haptics SDK는 개발자가 API를 의도하지 않게 사용하지 않도록 안내하기 위해 예외를 발생시킵니다. 이러한 의도하지 않은 사용에는 예를 들어 기능에 대한 입력이 허용 가능한 범위를 초과하는 것이 포함됩니다. 이러한 경우 호출 코드를 수정하는 데 도움이 되는 유용한 메시지와 함께 예외가 수신됩니다.

모범 사례

  • 메서드를 호출하여 HapticClipPlayer 개체와 이를 지원하는 리소스를 해제합니다 Dispose(). 늦어도 HapticClipPlayer 개체를 포함하는 MonoBehaviour는 해당 메서드에서 이 작업을 수행해야 합니다 . 필요에 따라 HapticClipPlayer 개체를 해제하여 메모리를 확보하는 것도 가능합니다 . 물론 출시된 HapticClipPlayer 에서 메서드를 호출하면 런타임 오류가 발생합니다.OnDestroy()
  • MonoBehaviour.OnApplicationQuit()를 호출하여 햅틱 런타임을 해제합니다 Haptics.Instance.Dispose().

문제 해결

햅틱과 오디오가 동기화되지 않음

원인

오디오와 햅틱은 각각 지속 시간이 다른 실행 경로가 다르기 때문에 시간 오프셋이 존재할 수 있습니다.

해결책

동기화 메커니즘은 아직 존재하지 않지만 임시 해결책은 둘 중 더 빠른 것을 지연시키는 것입니다. 오디오와 햅틱 사이의 오프셋은 다양한 실행 조건에 따라 달라질 수 있으므로 고정된 지연 값을 권장할 수 없습니다. 아래 코드는 단순히 1초의 예를 사용합니다.

public class MyMonoBehaviour : MonoBehaviour
{
    SomeFunction()
    {
        // Call a function after 1 second
        StartCoroutine(CallFunctionAfterDelay(delay / 1000.0f));
    }

    private IEnumerator CallFunctionAfterDelay(float time)
    {
        yield return new WaitForSeconds(time);
        // Call function here
    }
}

Getting logs

Unity용 Haptics SDK는 일부 메시지를 Unity 로그에 기록하고 다른 메시지를 Android 로그에 기록합니다. 문제가 발생할 때 자세한 정보를 얻으려면 이 로그를 참조하세요. Android 로그의 경우 SDK는 Unity및 HapticsSDK로그 태그를 사용합니다.

 

Gathering logs from the headset (헤드셋에서 로그 수집)

1.로그 버퍼 크기를 늘리십시오. 이렇게 하지 않으면 로그에 마지막 몇 초만 포함되는 경우가 많으며 Haptics SDK 초기화에 대한 것과 같은 중요한 로그 메시지가 누락됩니다.

adb logcat -G 16M

2. 문제를 재현합니다. 문제와 관련된 메시지가 제한된 로그 버퍼에 계속 포함되도록 로그를 수집하기 직전에 문제를 재현하는 것이 중요합니다.

3. 로그를 가져와 파일에 저장합니다. 

adb logcat -d > logs.txt

 

4.로그에 Haptics SDK와 관련된 정보가 포함되어 있는지 확인하세요. 다음은 일부 Haptics SDK 로그 메시지를 표시합니다.

cat logs.txt | grep HapticsSDK

5. 이상적으로 이는 다음과 유사한 메시지를 기록하는 Haptics SDK의 초기화로 돌아갑니다.

05-26 14:08:03.444  9451  9662 I HapticsSDK: haptics_sdk_c_api_core::c_api::helpers: Haptics SDK version <version> initialized

Windows/Link의 Unity 에디터에서 플레이 모드를 사용하는 경우 Haptics SDK 로그는 예를 들어 C:\Users\Username\AppData\Local\Unity\Editor\Editor.log에 기록됩니다. Android와 달리 Haptics SDK 로그 메시지에는 HapticsSDK와 같은 태그가 표시되지 않습니다.