Meta Avatar
このアドオンは、MetaアバターとFusionとのインテグレーション方法を示します。
主な焦点は、以下の通りです。
- Fusionのネットワーク変数を使用してアバターを同期する
- Photon Voiceとリップシンクとのインテグレーション
Meta XR SDK
他のサンプルで使用されているOpenXRプラグインのかわりに、ここではOculus XRプラグインを使用しています。
Meta XR SDKは、MetaのScoped Registry https://npm.developer.oculus.com/ に追加されています。(詳細はMeta documentationを参照)
Metaからインストールしたパッケージには以下が含まれます。
- Meta XR Core SDK
- Meta XR Platform SDK:Oculus User IDへアクセスして、Metaアバターのロードするために必要です。
Oculusリグとビルディングブロック
OpenXRプラグインのかわりにOculus XRプラグイン使用する場合は、ヘッドセットと手の位置をキャプチャするために特定のリグが作成されます。
このハードウェア収集リグは、Meta building blocksから作成されます。
- このステップで作成されるプレハブは、
MetaOVRHandsSynchronization
アドオンの/Prefabs/Rig/BaseBuildingBlocks/[BuildingBlock] BaseRig
プレハブから利用可能です - アドオンで実際に使用するプレハブは、同期コンポーネントが追加されていて、
/Prefabs/Rig/[BuildingBlock] HardwareRigForMetaAvatar
プレハブから利用可能です
MetaAvatar
ゲームオブジェクトには、Metaアバターを正しく機能させるために、必要なコンポーネントがすべてまとめて追加されています。
LipSync
はOVRAvatarLipSyncContext
コンポーネントを持ちます:リップシンク機能をセットアップするためにOculus SDKから提供されます。BodyTracking
はSampleInputManager
コンポーネントを持ちます:これはOculus SDK(Asset/Avatar2/Example/Common/Scripts
)にあります。OvrAvatarInputManager
基底クラスを継承していて、アバターのトラッキング入力を設定するためにOVR Hardware Rig
を参照します。AvatarManager
はOVRAvatarManager
コンポーネントを持ちます:Metaアバターをロードするために使用されます。
Runner
Runner
ゲームオブジェクトにあるConnectionManager
は、OnPlayerJoined
コールバックが呼び出された時に、Photon Fusionのサーバーへの接続とユーザーのネットワークプレハブのスポーンを制御します。
また、ネットワークを通して音声をストリームするためには、Fusion Voice Client
が必要です。recorder
フィールドは、Runner
にあるRecorder
ゲームオブジェクトを参照しています。
FusionとPhoton Voiceとのインテグレーションの詳細は以下のページをご覧ください:Voice - Fusion Integration
Runner
ゲームオブジェクトは、MetaAvatarMicrophoneAuthorization
コンポーネントによって、マイクの権限周りも扱います。マイクアクセスが付与された時に、Recorder
オブジェクトを有効にします。
Recorder
は、マイクの接続を扱います。これに含まれるAudioLipSyncConnector
コンポーネントは、Recorder
からオーディオストリームを受け取って、OVRAvatarLipSyncContext
に渡します。
ユーザーのネットワークプレハブのスポーン
ConnectionManager
は、OnPlayerJoined
コールバックが呼び出された時に、ユーザーのネットワークプレハブNetworkRigWithOVRHandsMetaAvatar Variant
をスポーンします。
このプレハブは以下を含みます。
MetaAvatarSync
:開始時にランダムなアバターを選択して、ネットワークを通してアバターをストリーミングします。NetworkedAvatarEntity
:OculusのOvrAvatarEntity
を継承しています。ネットワークリグがローカルユーザーかリモートユーザーかによって、アバターを調整するために使用されます。
アバターの同期
概要
MetaAvatarSync
クラスは、アバター同期の自動化を制御します。
ConfigureAsLocalAvatar()
メソッドによって、ローカルユーザーでユーザーのネットワークプレハブがスポーンした時、関連するNetworkAvatarEntity
が以下のデータを受け取ります。
OvrAvatarLipSyncContext
から、リップシンクSampleInputManager
から、ボディートラッキング
ネットワーク変数によって、データがネットワークを通してストリームされます。
リモートユーザーでユーザーのネットワークプレハブがスポーンした時は、MetaAvatarSync
のConfigureAsRemoteAvatar()
が呼び出され、関連するNetworkAvatarEntity
クラスがストリームされたデータからアバターの構築とアニメーションを行います。
アバターモード
MetaAvatarSync
は、2つのモードに対応しています。
- 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
に参照されます。
この設定は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
と呼ばれるネットワーク変数にコピーします。
容量は、MetaアバターのMediumかHighのLODをストリームするのに十分な、1200に制限されています。(実用的な設定では、実際に必要なデータ量に合わせて、無駄なメモリ確保を回避します)
説明を簡単にするため、このサンプルではMedium 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アバターのローディング
ローカルユーザーアバターのローディング
先ほど見たように、ユーザーのMetaアバターをロードするには、AvatarMode
はAvatarMode.UserAvatar
に設定されている必要があります。
Spawned
コールバックで、LoadUserAvatar()
からNetworkedAvatarEntity
はユーザーアカウントのアバターを問い合わせます。
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
に保存されるので、ユーザーIDはすべてのクライアント間で同期されます。
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
を追加する必要があります。
このApp ID
は、MetaダッシュボードのAPI > App Id
フィールドにあります。
また、アプリケーションは、Data use checkup
セクションを完了している必要があり、User Id
・User profile
・Avatars
アクセスが必要です。
ユーザーアバターのテスト
開発中にローカルのMetaアカウントに関連したアバターを見られるようにするには、Oculus Platform SettingsからローカルユーザーアカウントをApp Id
に関連した組織のメンバーにする必要があります。
クロスプラットフォーム(Questビルドとデスクトップビルド)でアバターを見るには、以下のページのGroup App IDs Together
チャプターで指定されるように、QuestとRiftのアプリケーションをグループ化する必要があります。Configuring Apps for Meta Avatars SDK
リップシンク
Photon Voice Recorder
でマイクの初期化が行われます。
OVRHardwareRig
のOvrAvatarLipSyncContext
は、オーディオバッファを転送するために直接呼び出されることを想定して調整されます。
Recorder
から読み取ったオーディオをフックするクラスは、後述するように、オーディオをOvrAvatarLipSyncContext
に転送します。
Recorder
クラスはIProcessor
インターフェースを実装したクラスに、読み取りオーディオバッファを転送できます。
カスタムオーディオプロセッサーの作成方法の詳細は、以下のページをご覧ください。Photon Voice - よくある質問
Voice接続時にオーディオプロセッサーを登録するため、VoiceComponent
を継承したAudioLipSyncConnector
を、Recorder
と同じゲームオブジェクトに追加します。
これによって、PhotonVoiceCreated
とPhotonVoiceRemoved
コールバックを受け取り、Voice接続時にポストプロセッサーを追加できるようになります。
接続されるポストプロセッサーは、IProcessor<float>
かIProcessor<short>
を実装したAvatarAudioProcessor
です。
プレイヤー接続時、MetaAvatarSync
コンポーネントは、Recorder
にあるAudioLipSyncConnector
を検索して、lipSyncContext
フィールドにプロセッサーを設定します。
そうすることで、Recorder
からAvatarAudioProcessor
のProcess
コールバックが呼び出されるたびに、受け取ったオーディオバッファに対してOvrAvatarLipSyncContext
のProcessAudioSamples
が呼び出され、アバターモデルでリップシンクの計算が行われます。
リップシンクはアバターのボディー情報と一緒にストリームされて、アバターのRecordStreamData_AutoBuffer
でキャプチャされた時に、MetaAvatarSync
のLateUpdate
内で行われます。
依存関係
- Meta Avatars SDK (com.meta.xr.sdk.avatars) 24.1.1 + Sample scene
- 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 addon
デモ
デモシーンはAssets\Photon\FusionAddons\MetaAvatar\Demo\Scenes\
フォルダーにあります。
ダウンロード
このアドオンの最新バージョンは、Industries アドオンのプロジェクトに含まれています。
対応するトポロジー
- 共有モード
更新履歴
- Version 2.0.1:
- Compatibility with packaged Meta avatar com.meta.xr.sdk.avatars 24.1.1
- Version 2.0.0: First release