메타 아바타
이 애드온은 메타 아바타를 Fusion과 통합하는 방법을 보여줍니다.
주요 내용은 다음과 같습니다:
- Fusion 네트워크 변수를 사용하여 아바타 동기화
- Fusion Voice와 립싱크 통합
Meta XR SDK
여기에는 다른 샘플에 사용되는 OpenXR 플러그인 대신 Oculus XR 플러그인이 사용됩니다.
Meta XR SDK는 범위가 지정된 레지스트리 https://npm.developer.oculus.com/ (자세한 내용은 Meta 문서 참조)를 통해 추가되었습니다.
메타 레지스터의 주요 설치 패키지는 다음과 같습니다:
- Meta XR Core SDK
- Meta XR Platform SDK: Oculus 사용자 ID에 액세스하고 Meta 아바타를 로드하는데 필요합니다.
Oculus 리그 및 빌딩 블록
OpenXR 플러그인 대신 Oculus XR 플러그인을 기반으로 헤드셋과 손 위치를 캡처할 수 있는 특정 리그가 만들어졌습니다.
이 하드웨어 수집 리그는 Meta 빌딩 블록을 통해 생성되었습니다.
- 이 단계에서 생성된 프리팹은
MetaOVRHandsSynchronization
애드온의/Prefabs/Rig/BaseBuildingBlocks/[BuildingBlock] BaseRig
프리팹에서 사용할 수 있습니다. - 이전에 동기화 컴포넌트가 추가된 추가 기능에 사용된 프리팹은
/Prefabs/HardwareRig/[BuildingBlock] HardwareRigForMetaAvatar
프리팹에서 사용할 수 있습니다.
MetaAvatar
게임 객체는 메타 아바타가 제 기능을 하는 데 필요한 모든 컴포넌트를 한데 묶습니다.
LipSync
는OVRAvatarLipSyncContext
라는 컴포넌트를 가지고 있습니다: Oculus SDK에서 립싱크 기능을 설정하기 위해 제공합니다.BodyTracking
은 Oculus SDK(Asset/Avatar2/Example/Common/Scripts
)에서 나온SampleInputManager
의 컴포넌트입니다.OvrAvatarInputManager
의 기본 클래스에서 파생된 클래스로 아바타 개체에 추적 입력을 설정하는OVR Hardware Rig
를 말합니다.AvatarManager
는 메타바타를 로드하는 데 사용되는OVRAvatarManager
라는 컴포넌트를 가지고 있습니다.
러너
Runner
게임 객체에 위치한 ConnectionManager
는 OnPlayerJoined
콜백이 호출되면 Photon Fusion 서버와의 연결을 처리하고 사용자 네트워크 프리팹을 생성합니다.
네트워크를 통해 음성을 스트리밍 하려면 Fusion Voice Client
가 필요합니다. 프라이머리 레코더 필드는 Runner
에 있는 Recorder
게임 객체를 말합니다.
Fusion으로 Photon Voice 통합에 대한 자세한 내용은Voice - Fusion 통합 페이지를 참조하십시오.
Runner
의 게임 객체는 MetaAvatarMicrophoneAuthorization
컴포넌트 덕분에 마이크 인가를 요청하는 기능도 담당합니다. 마이크 접근이 허용되면 Recorder
객체를 활성화합니다.
하위 객체인 Recorder
는 Recorder
의 오디오 스트림을 수신하여 OVRAvatarLipSyncContext
로 전달하는 AudioLipSyncConnector
컴포넌트를 포함하고 있습니다.
사용자가 스폰 한 네트워크 프리팹
ConnectionManager
는 OnPlayerJoined
콜백이 호출되면 사용자 네트워크 프리팹인 NetworkRigWithOVRHandsMetaAvatar Variant
를 생성합니다.
이 프리팹은 다음을 포함합니다:
MetaAvatarSync
: 시작할 때 임의의 아바타를 선택하고 네트워크를 통해 아바타를 스트리밍 하는 기능을 담당합니다.NetworkedAvatarEntity
: OculusOvrAvatarEntity
에서 파생되었습니다. 네트워크 리그가 로컬 사용자를 나타내는지 원격 사용자를 나타내는지에 따라 아바타 객체를 구성하는 데 사용됩니다.
아바타 동기화
개요
MetaAvatarSync
클래스는 아바타 동기화의 오케스트레이션을 담당합니다.
ConfigureAsLocalAvatar()
메소드 덕분에 사용자 네트워크 프리팹이 로컬 사용자를 위해 생성되면 관련 NetworkAvatarEntity
는 다음으로부터 데이터를 받았습니다:
- 립싱크를 위한
OvrAvatarLipSyncContext
- 바디 트래킹을 위한
SampleInputManager
네트워크 변수 덕분에 데이터가 네트워크를 통해 스트리밍됩니다.
원격 사용자를 위해 사용자 네트워크 프리팹이 생성되면 MetaAvatarSync
ConfigureAsRemoteAvatar()
가 호출되고 관련 NetworkAvatarEntity
클래스가 데이터 스트리밍을 통해 아바타를 빌드하고 애니메이션화합니다.
아바타 모드
MetaAvatarSync
는 2가지 모드를 지원합니다 :
- UserAvatar : 사용자의 메타 아바티 로드
- RandomAvatar : 무작위 메타 아바타 로드
따라서, 로컬 사용자 네트워크화된 프리팹이 생성될 때, 아바타는 이 구성에 따라 선택됩니다.
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
에서 참조합니다.
이 설정은 MetaAvatarSync
(ConfigureAsLocalAvatar()
)에 의해 수행됩니다.
각각의 LateUpdate()
, MetaAvatarSync
는 해당 지역 플레이어의 아바타 데이터를 캡처합니다.
C#
private void LateUpdate()
{
// Local avatar has fully updated this frame and can send data to the network
if (Object.HasInputAuthority)
{
CaptureAvatarData();
}
}
CaptureLODAvatar
메소드는은 아바타 객체 스트림 버퍼를 받아 AvatarData
라는 네트워크 변수에 복사합니다.
용량은 중간 또는 높은 LOD에서 메타바타를 스트리밍하기에 충분하므로 1200으로 제한됩니다(실제 구성의 경우 메모리 낭비를 방지하기 위해 이 숫자는 실제 필요한 데이터 양과 일치해야 함).
단순화를 위해 이 샘플에는 중간 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();
}
}
개인화된 메타 아바타 로딩
로컬 사용자 아바타 로딩
앞에서 본 바와 같이 사용자의 메타 아바타를 로드하려면 AvatarMode
를 AvatarMode.UserAvatar
로 설정해야 합니다.
그래서 Spawned
콜백 중에 NetworkedAvatarEntity
는 LoadUserAvatar()
로 사용자 계정 아바타를 요청합니다.
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;
}
이 메소드는 UserId
[Networked] 변수에 저장된 Meta의 계정 사용자 ID를 반환하여 모든 클라이언트에서 사용자 ID가 동기화되도록 합니다.
C#
[Networked]
public ulong UserId { get; set; } = 0;
사용자 아바타를 로드하려면 다음과 같이 하십시오:
Defer Loading
은 플레이어의 프리팹의NetworkedAvatarEntity
컴포넌트에서 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);
}
}
메타 아바타 접근
메타바타를 로드하려면 Oculus > Oculus Platform
유니티 설정 메뉴에서 애플리케이션에 대한 App Id
를 추가해야 합니다.
이 App Id
는 Meta 관리 화면의 API > App Id
필드에서 확인할 수 있습니다.
또한 이 애플리케이션은 Data use checkup
섹션을 완료해야 하며, User Id
, User profile
, Avatars
접근이 필요합니다:
사용자의 아바타 테스트
개발 중에 로컬 메타 계정과 관련된 아바타를 볼 수 있으려면, 로컬 사용자 계정이 Oculus Platform 설정에서 제공된 App Id
와 관련된 조직의 구성원이어야 합니다.
크로스 플랫폼 설정(Quest와 데스크톱 빌드 사이)에서 아바타를 보려면 이 페이지의 Group App IDs Together
장에 명시된 대로 Quest와 Rift 애플리케이션을 그룹화해야 합니다.Meta 아바타 SDK용 앱 구성
립씽크
마이크 초기화는 Photon Voice Recorder
에 의해 수행됩니다.
OVRHardwareRig
의 OvrAvatarLipSyncContext
는 오디오 버퍼와 함께 직접 호출이 가능하도록 구성되어 있습니다.
아래와 같이 OvrAvatarLipSyncContext
에 전달하기 위해 레코더 오디오 판독에 후크를 연결합니다.
Recorder
클래스는 읽기 오디오 버퍼를 IProcessor
인터페이스를 구현하는 클래스로 전달할 수 있습니다.
사용자 지정 오디오 프로세서를 만드는 방법에 대한 자세한 내용은 Photon Voice - FAQ페이지를 참조하십시오.
이러한 프로세서를 음성 연결에 등록하기 위해 Recorder
와 동일한 게임 오브젝트에 VoiceComponent
서브클래스인 AudioLipSyncConnector
를 추가합니다.
이로 인해 PhotonVoiceCreated
및 PhotonVoiceRemoved
콜백이 수신되어 연결된 음성에 포스트 프로세서를 추가할 수 있게 되었습니다.
연결된 포스트 프로세서는 AvatarAudioProcessor
로 IProcessor<float>
또는 IProcessor<short>
를 구현합니다.
MetaAvatarSync
컴포넌트는 플레이어 연결 중에 레코더에 있는 AudioLipSyncConnector
를 검색하여 이 프로세서의 lipSyncContext
필드를 설정합니다.
이렇게 하면 수신된 오디오 버퍼를 가진 OvrAvatarLipSyncContext
에서 AvatarAudioProcessor Process
콜백이 호출될 때마다 수신된 오디오 버퍼를 통해 ProcessAudioSamples
가 호출되어 아바타 모델에서 립씽크가 계산되도록 합니다.
이렇게 하면 MetaAvatarSync
업데이트가 늦어지는 동안 아바타 개체에서 RecordStreamData_AutoBuffer
로 캡처하면 다른 아바타 객체 정보와 함께 립싱크가 스트리밍됩니다.
의존성
- Meta Avatar2 SDK
- Meta XR Core SDK
- Meta XR Platform SDK
- Photon Voice SDK
- MetaOVRHandsSynchronization 애드온
데모
데모 씬은 Assets\Photon\FusionAddons\MetaAvatar\Demo\Scenes\
폴더에 있습니다.
다운로드
이 애드온의 최신 버전은 애드온 프로젝트에 있습니다.
지원하는 토폴로지
- 공유 모드
변경 내역
- Version 2.0.0: 최초 릴리즈