This document is about: FUSION 2
SWITCH TO

레거시 Meta 아바타

Topology
SHARED AUTHORITY
Fusion Industries 프로토타이핑 애드온

이 애드온은 Fusion과 Meta 아바타를 통합하는 방법을 보여줍니다.

주요 목표는 다음과 같습니다:

  • Fusion 네트워크 변수를 사용한 아바타 동기화
  • Fusion Voice와의 립싱크 통합
Fusion Oculus Meta Avatar

Meta XR SDK

다른 샘플에서 사용된 OpenXR 플러그인 대신 Oculus XR 플러그인을 사용합니다.

Meta XR SDK는 스코프 레지스트리 https://npm.developer.oculus.com/를 통해 추가되었습니다.
자세한 내용은 Meta 공식 문서를 참조하세요.

Meta 레지스트리에서 설치되는 주요 패키지는 다음과 같습니다:

  • Meta XR Core SDK
  • Meta XR Platform SDK (Oculus 사용자 ID 및 Meta 아바타 로딩에 필요)

Oculus 리그 및 빌딩 블록

OpenXR 플러그인이 아닌 Oculus XR 플러그인을 기반으로 하기 때문에, 헤드셋 및 손 위치를 캡처하기 위한 별도의 리그가 필요합니다.

이 하드웨어 리그는 Meta 빌딩 블록을 통해 생성되었습니다.

  • 해당 프리팹은 /Prefabs/Rig/BaseBuildingBlocks/[BuildingBlock] BaseRig에 위치합니다. (MetaOVRHandsSynchronization 애드온 포함)
  • 동기화 컴포넌트를 포함한 실제 사용 프리팹은 /Prefabs/HardwareRig/[BuildingBlock] HardwareRigForMetaAvatar에 위치합니다.
Meta의 빌딩 블록 기반 리그

MetaAvatar 게임 오브젝트는 Meta 아바타 기능을 위한 모든 구성 요소를 포함합니다.

  • LipSync: OVRAvatarLipSyncContext 컴포넌트를 포함하며, Oculus SDK가 제공하는 립싱크 설정용 컴포넌트입니다.
  • BodyTracking: SampleInputManager 컴포넌트를 포함하며, OvrAvatarInputManager를 상속받아 하드웨어 리그 기반의 트래킹 입력을 처리합니다.
  • AvatarManager: OVRAvatarManager를 통해 Meta 아바타 로딩을 담당합니다.

Runner

Runner 게임 오브젝트에 위치한 ConnectionManager는 Photon Fusion 서버 연결을 처리하고, OnPlayerJoined 콜백 시 사용자 네트워크 프리팹을 생성합니다.
음성 스트리밍을 위해 Fusion Voice Client가 필요하며, 해당 클라이언트는 Runner 하위에 위치한 Recorder를 참조합니다.

Fusion과 Photon Voice 통합에 대한 자세한 내용은 다음 링크를 참고하세요:
Voice - Fusion Integration

RunnerMetaAvatarMicrophoneAuthorization 컴포넌트를 통해 마이크 권한을 요청하고, 권한이 부여되면 Recorder 오브젝트를 활성화합니다.

하위 오브젝트 Recorder는 마이크 연결을 담당하며, AudioLipSyncConnector 컴포넌트를 통해 오디오 스트림을 OVRAvatarLipSyncContext로 전달합니다.

사용자 스폰 네트워크 프리팹

OnPlayerJoined 콜백 시, ConnectionManagerNetworkRigWithOVRHandsMetaAvatar Variant 프리팹을 생성합니다.

프리팹 구성:

  • MetaAvatarSync: 아바타를 무작위로 선택하고 네트워크로 스트리밍 처리

  • NetworkedAvatarEntity: Oculus의 OvrAvatarEntity를 상속한 클래스이며, 로컬 또는 원격 사용자에 따라 아바타를 구성합니다.

아바타 동기화

개요

MetaAvatarSync 클래스는 아바타 동기화의 중심 역할을 합니다.
ConfigureAsLocalAvatar() 메서드를 통해 로컬 사용자 프리팹에 다음 구성요소를 연결합니다:

  • 립싱크: OvrAvatarLipSyncContext
  • 바디 트래킹: SampleInputManager

이 데이터는 네트워크 변수를 통해 전송됩니다.

원격 사용자의 경우 ConfigureAsRemoteAvatar()가 호출되어 수신된 데이터를 기반으로 아바타를 빌드 및 애니메이션 처리합니다.

Fusion Oculus Meta Avatar

아바타 모드

MetaAvatarSync는 다음 두 가지 모드를 지원합니다:

  • UserAvatar: 사용자의 Meta 아바타를 로드
  • RandomAvatar: 무작위 Meta 아바타를 로드

프리팹 생성 시 다음과 같은 코드로 아바타를 결정합니다:

C#

public override void Spawned()
{
    base.Spawned();

    if (Object.HasInputAuthority)
    {
        LoadLocalAvatar();
    }
    else
    {
        if (!avatarConfigured)
        {
            ConfigureAsRemoteAvatar();
        }
    }
    changeDetector = GetChangeDetector(ChangeDetector.Source.SnapshotFrom);
    // Trigger initial change if any
    OnUserIdChanged();
    ChangeAvatarIndex();
}

async void LoadLocalAvatar()
{
    if (avatarMode == AvatarMode.UserAvatar)
    {
        // Make sure to download the user id
        ConfigureAsLocalAvatar();
        UserId = await avatarEntity.LoadUserAvatar();
    }
    else
    {
        ConfigureAsLocalAvatar();
        AvatarIndex = UnityEngine.Random.Range(0, 31);
        avatarEntity.LoadZipAvatar(AvatarIndex);
    }
}

AvatarIndex가 네트워크 변수이므로, 값이 변경되면 ChangeDetector를 통해 모든 클라이언트에서 자동으로 동기화됩니다.

C#

    [Networked]
    public int AvatarIndex { get; set; } = -1;

    ChangeDetector changeDetector;

C#

    public override void Render()
    {
        base.Render();
        foreach (var changedPropertyName in changeDetector.DetectChanges(this))
        {
            if (changedPropertyName == nameof(UserId)) OnUserIdChanged();
...
        }
    }

아바타 데이터

SampleInputManager는 하드웨어 리그의 움직임을 추적하며, 로컬 사용자의 경우 NetworkedAvatarEntity에 참조됩니다.
매 프레임 LateUpdate()에서 데이터를 캡처합니다:

C#

    private void LateUpdate()
    {
    // Local avatar has fully updated this frame and can send data to the network
    if (Object.HasInputAuthority)
    {
        CaptureAvatarData();
    }
}

CaptureLODAvatar 메서드는 아바타 엔티티의 스트림 버퍼를 가져와 AvatarData라는 네트워크 변수에 복사합니다.
용량은 1200으로 제한되어 있으며, 이는 중간 또는 높은 LOD 수준의 Meta 아바타를 스트리밍 하기에 충분한 크기입니다.
(실제 구성에서는 메모리 낭비를 피하기 위해 필요한 데이터 크기에 맞게 조정하는 것이 좋습니다)
참고로, 이 샘플에서는 단순화를 위해 중간 LOD만 스트리밍 됩니다.

버퍼 크기인 AvatarDataCount 역시 네트워크를 통해 동기화됩니다.

C#

    [Networked, Capacity(1200)]
    public NetworkArray<byte> AvatarData { get; }
 
    [Networked]
    public uint AvatarDataCount { get; set; }

따라서 아바타 스트림 버퍼가 업데이트되면, 원격 사용자들에게 해당 변경 사항이 전달되고, 수신된 데이터를 원격 사용자를 나타내는 네트워크 리그에 적용하게 됩니다.

C#

    public override void Render()
    {
        base.Render();
        foreach (var changedPropertyName in changeDetector.DetectChanges(this))
        {
...
            if (changedPropertyName == nameof(AvatarData)) ApplyAvatarData();
        }
    }

사용자 정의 Meta 아바타 로드

로컬 사용자 아바타 로드

AvatarMode.UserAvatar 모드로 설정 시, LoadUserAvatar()를 통해 Meta 사용자 계정의 아바타를 불러옵니다:

C#

/// <summary>
/// Load the user meta avatar based on its user id
/// Note: _deferLoading has to been set to true for this to be working
/// </summary>

public async Task<ulong> LoadUserAvatar()
{
    // Initializes the OVR PLatform, then get the user id
    await FinOculusUserId();
    if(_userId != 0)
    {
        // Load the actual avatar
        StartCoroutine(Retry_HasAvatarRequest());
    }
    else
    {
        Debug.LogError("Unable to find UserId.");
    }
    return _userId;
}

이 메서드는 Meta 계정의 사용자 ID를 반환하며, 이 값은 UserId 네트워크 변수에 저장되어 모든 클라이언트 간에 동기화됩니다.

C#

    [Networked]
    public ulong UserId { get; set; } = 0;

사용자 아바타를 로드하기 위해서는 다음 사항을 반드시 유의해야 합니다:

  • 플레이어 프리팹의 NetworkedAvatarEntity 컴포넌트에서 Defer Loading 옵션을 true로 설정해야 합니다.
    이 설정은 아바타가 시작 시 자동으로 로드되는 것을 방지합니다.

원격 사용자 아바타 로드

UserId를 수신하면, 원격 클라이언트는 해당 ID에 연동된 아바타를 자동으로 다운로드하게 됩니다.

C#

    public override void Render()
    {
        base.Render();
        foreach (var changedPropertyName in changeDetector.DetectChanges(this))
        {
            if (changedPropertyName == nameof(UserId)) OnUserIdChanged();
            ...
        }
    }
    void OnUserIdChanged()
    {   
        if(Object.HasStateAuthority == false && UserId != 0)
        {
            Debug.Log("Loading remote avatar: "+UserId);
            avatarEntity.LoadRemoteUserCdnAvatar(UserId);
        }
    }

Meta 아바타 접근 설정

Meta 아바타를 로드하려면 Unity 메뉴의 Oculus > Platform > Edit Settings에서 App Id를 입력해야 합니다.

Fusion Oculus Platform Settings Menu
Fusion Oculus Platform Settings

Meta 대시보드의 API > App Id에서 확인 가능하며, Data use checkup 항목에서 User Id, User profile, Avatars 접근 권한이 설정되어 있어야 합니다.

Fusion Oculus Meta Avatar Data use checkup

사용자 아바타 테스트

개발 중 로컬 Meta 계정에 연결된 아바타를 확인하려면, 로컬 사용자 계정이 Oculus 플랫폼 설정에 입력된 App Id와 연결된 조직의 구성원이어야 합니다.

Quest와 데스크톱 빌드 간의 크로스 플랫폼 환경에서 아바타를 확인하려면, 해당 Quest 앱과 Rift 앱이 하나의 그룹으로 묶여 있어야 합니다.
이 설정 방법은 다음 문서의 "Group App IDs Together" 섹션에서 확인할 수 있습니다: Configuring Apps for Meta Avatars SDK

립싱크

마이크 초기화는 Photon Voice Recorder에 의해 수행됩니다.

OVRHardwareRig에 포함된 OvrAvatarLipSyncContext는 오디오 버퍼를 직접 전달받는 방식으로 설정되어 있으며,
이를 위해 별도의 클래스가 Recorder의 오디오 데이터를 가로채어 OvrAvatarLipSyncContext로 전달합니다. 아래는 이 처리 방식의 상세 내용입니다.

Recorder 클래스는 읽어들인 오디오 버퍼를 IProcessor 인터페이스를 구현한 클래스에 전달할 수 있습니다.
커스텀 오디오 프로세서를 만드는 방법에 대한 자세한 내용은 다음 문서를 참고하세요: Photon Voice - FAQ

이러한 프로세서를 음성 연결에 등록하려면, VoiceComponent를 상속받은 AudioLipSyncConnector 클래스를 Recorder와 동일한 GameObject에 추가해야 합니다.
이로 인해 PhotonVoiceCreatedPhotonVoiceRemoved 콜백을 수신할 수 있으며, 연결된 음성에 후처리 프로세서를 등록할 수 있게 됩니다.
이때 연결되는 후처리 프로세서는 IProcessor<float> 또는 IProcessor<short>를 구현한 AvatarAudioProcessor입니다.

플레이어가 연결되면 MetaAvatarSync 컴포넌트는 Recorder 오브젝트 내의 AudioLipSyncConnector를 찾아
해당 프로세서의 lipSyncContext 필드에 OvrAvatarLipSyncContext를 설정합니다.

이 설정이 완료되면, Recorder에서 AvatarAudioProcessor.Process 콜백이 호출될 때마다
오디오 버퍼가 OvrAvatarLipSyncContext.ProcessAudioSamples()로 전달되어, 아바타 모델에 립싱크가 실시간으로 적용됩니다.

이 방식 덕분에, 립싱크 정보도 아바타의 다른 바디 데이터와 함께 MetaAvatarSyncLateUpdate() 단계에서 RecordStreamData_AutoBuffer를 통해 스트리밍 됩니다.

의존성

  • Meta Avatars SDK (com.meta.xr.sdk.avatars) 24.1.1 + 샘플 씬
  • Meta Avatars SDK Sample Assets (com.meta.xr.sdk.avatars.sample.assets) 24.1.1
  • Meta XR Core SDK (com.meta.xr.sdk.core) 62.0.0
  • Meta XR Platform SDK (com.meta.xr.sdk.platform) 62.0.0
  • Photon Voice SDK
  • MetaOVRHandsSynchronization 애드온

데모

데모 씬은 Assets\Photon\FusionAddons\MetaAvatar\Demo\Scenes\ 폴더에 있습니다.

지원되는 토폴로지

  • 공유 모드

변경 로그

  • 버전 2.0.1:

    • Meta Avatar com.meta.xr.sdk.avatars 24.1.1 패키지 24.1.1 호환성 추가
  • 버전 2.0.0: 최초 릴리즈

Back to top