Stage Screen Sharing
概要
Fusion Stage Screen Sharingサンプルは、Fusionで最大200人参加できるソーシャルアプリケーションを開発するためのアプローチを示します。
各プレイヤーはアバターで表現され、Photon Voice SDKのおかげで同じチャットバブルにいる他のプレイヤーと会話することができます。
さらに、ユーザーの1人はステージに上がり、プレゼンテーションを始めることができます。
プレゼンターが許可すれば、ユーザーはルームの大きなバーチャルスクリーンに自身のPCスクリーンを共有することもできます。
このサンプルの特徴は以下の通りです。
- 最初に、アバター選択画面でプレイヤーは自身のアバターをカスタマイズします。
- そして、プレイヤーはStageシーンに参加できます。サンプルをPCかMACで起動しているなら、デスクトップモード(キーボードとマウス)かVRモード(Meta Questヘッドセット)を選択できます。
- 同じチャットバブルにいるプレイヤー同士は会話できます。各チャットバブルではロックボタンが使用可能で、新規プレイヤーの参加を止めることができます。
- ユーザーの1人はステージに上がって、ルーム内の全ユーザーと話すことができます。ステージに参加できるユーザー数を増やすこともできます。
- プレゼンターの音声は空間オーディオではなくなり、スピーカーの音声のように聞こえます。
- そこでは、全ユーザーと再生状況が同期される動画のようなコンテンツを共有することができます。
- カメラはプレゼンターを追従し、プレゼンターは専用にスクリーンに表示されます。
- 着席したユーザーは、ステージ上のプレゼンターに会話を求めることができます。プレゼンターが許可すると、誰でも会話が終わるまでその会話を聞くことができます。
- また、聴衆はエモートアイコンを送信して、プレゼンテーションに意見を述べることができます。
- 帯域消費を削減して参加プレイヤー数を増やすために、着席したユーザーのティックレートは減少します。
技術情報
- サンプルは共有モード(Shared Mode)を使用
- 対象プラットフォームは、PC・Mac・Meta Quest
- 開発環境は、Unity 2021.3、Fusion 2、Photon Voice 2.53
- 2つのアバターソリューションに対応(自作のシンプルなアバター・「Ready Player Me」アバター)
事前準備
サンプルを実行するには、
ダッシュボードからFusionのAppIdを作成して、Realtime Settings(Fusionメニューから選択可能)の
App Id Fusion
フィールドに貼り付けてください。ダッシュボードからVoiceのAppIdを作成して、Realtime Settingsの
App Id Voice
フィールドに貼り付けてください。それから、
AvatarSelection
シーンをロードして、Play
を押してください。
ダウンロード
バージョン | リリース日 | ダウンロード | |
---|---|---|---|
2.0.0 | Oct 16, 2024 | Fusion Stage Screen Sharing 2.0.0 Build 692 |
実行ファイルのダウンロード
Stage Screen Sharingのデモバージョンが、以下からダウンロードできます。
- Fusion 2 Stage Screen Sharing for Quest
- Fusion 2 Stage Screen Sharing for Windows
- Fusion 2 Stage Screen Sharing for Mac
Stage Screen Sharing Recorder for Windowsは、以下からダウンロードできます。
WebGL
The Stage Screen Sharingサンプルは、WebGLでビルドできます。
こちらから、StageのWebGLビルドをテストできます。
ただしWebGLビルドに対するいくつかUnityの制限により、正常に動作させるためには固有の対応が必要で、詳細はこちらをご覧ください。
このWebGLビルドは、WebXR(ブラウザ上のVR)に対応していません。unity-webxr-exportなどのオープンソースライブラリを使用することで対応可能ですが、デフォルトのUnityでは未対応のため、ここではそれを示しません。
Google Chromeでテストしてください(Firefoxでは、VP8コーデック問題が発生する可能性があります)。
操作方法
デスクトップ
キーボード
- 移動: WASD or ZQSD で移動
- 回転: QE or AE で回転
- メニュー: Esc でアプリケーションのメニュー開閉
マウス
- 移動: マウス左クリックでポインタ表示、対象にテレポート
- 回転: マウス右ボタン押下中にドラッグで視点の回転
- 移動 & 回転: マウス左右ボタン押下で前進、視点の回転も可能
- 掴む: マウス左ボタンを使用してオブジェクトを掴む
Meta Quest
- テレポート: ABXYかスティック押下でポインタ表示、対象にテレポート
- 触る (チャットバブルのロックボタンなど): 単純にボタンに触れて動かす
フォルダー構造
サンプルに関するファイルは、メインフォルダーの/Stage
以下にすべて含まれます。
/IndustriesComponents
には、他のIndustries Samples(Fusion Expoサンプルなど)と共有されるコンポーネントが含まれます。
/Photon
フォルダーには、FusionとPhoton Voice SDKが含まれます。
/Photon/FusionXRShared
フォルダーには、リグとグラブのロジックが含まれます。これはVR Sharedサンプルを元にしており、その軽量なFusionXRShared SDKは他のプロジェクトでも共有されています。
/Photon/FusionAddons
フォルダーには、このサンプルで使用されるIndustriesアドオンが含まれます。
/XR
フォルダーには、VRの設定ファイルが含まれます。
アーキテクチャ概要
このサンプルは、VR Sharedと同じコードベースに依存しています(特にリグの同期)。
このサンプルや他のIndustries Samplesには、レイの同期・ロコモーションの検証・タッチ・スムーズなテレポート・視線システムのような再利用可能な機能を制御するための、FusionXRSharedやIndustriesアドオンが含まれています。
またこのサンプルは、Photon Voice SDKに加えて、Photon Video SDKに依存しています。
ルームに参加したいユーザーが実行する通常のクライアントに加えて、スクリーンを共有したいユーザーは専用のWindowsアプリケーション「Recorderクライアント」を実行する必要があります。これによって、どのスクリーンを共有するかを制御したり、表示する権限をリクエストします。
スクリーンキャプチャはuWindowCaptureに基づいており、デスクトップ画像のキャプチャとテクスチャへの適用を処理します。
ビデオストリームの処理は、Photon Voide SDKのVoiceConnection
(現在はまだ「Voice」という用語を「Stream」の意味で使用しています)で行います。
シーンロジック
通常のクライアント(出席者)とRecorderクライアント(ステージ上スクリーンにデスクトップ画面を配信する)とは、同じUnityのシーンを使用する必要があります。
しかし、使用したいクライアントモードに応じていくつかの修正が必要です。
そのため、StageWithScreenShareing
シーンでは、アプリケーションをRecorderクライアントとして調整するため、ExtendedRigSelection
はRecorder
という名前の固有のリグ設定を含みます。
- 特定のエミッタープレハブから、デフォルトのユーザープレハブを変更する
- アンビエントサウンドを無効化する
- レコーディング(特定のリグ・UI・エミッター)に必要なオブジェクトを有効化する
- 出席者名簿にアプリケーションを登録する
ステージ
ステージの管理にChatBubble
アドオンが使用されます。
デフォルトでは、ステージのチャットバブルの収容数は1ユーザーに制限されているので、プレゼンターが既にステージ上にいる時に他の人はステージに上がれません。プレゼンターは、ステージコンソールからこの値を変更できます。
プレゼンターがすべてのユーザーで正しく表示されるために、ステージに上がったユーザーのLODGroup
は無効化され、LODがトリガーされないことが保証されます。(PublicSpeechHandler
やStageCameraManager
クラスをご覧ください)
音声
プレゼンターがいるステージのチャットバブルに他の参加者はいないため、DynamicAudioGroup
アドオン(バージョン2.0.2)のホワイトリスト機能を使用して、すべての参加者が常にプレゼンターの音声を聞けるようにします。
また、AudioSourceの3D音響を削除するので、プレゼンターの音声はルームのどこでも聞くことが可能です。
プレゼンターカメラ
プレゼンターカメラは、ステージ上のユーザーに追従します。ステージ上のユーザーリストを保持するため、StageCameraManager
コンポーネントはIAudioRoomListener
インターフェースを実装しています。
ユーザーがステージに上がると、カメラトラッキングとレコーディングをトリガーします。
StageCameraManager
は複数のカメラを処理できます。各プレゼンターを追従するカメラ間を移動して、最も関連性あるプレゼンターのみの表示を有効にします。
カメラの描画レートは低く、カメラの移動と共にStageCamera
クラスで実行されます。
カメラは、カメラリグのTransform
に関連し、そのTransform
のx
軸に沿って移動します。
座席と帯域削減
着席中のプレイヤーの位置は更新する必要がないため、着席中は更新レートを削減する機能を追加しています。
更新レートは離席すると通常の頻度に戻ります。これによって、帯域消費を削減し、アプリケーションの参加人数を増加させます。
プレイヤーのネットワークリグの頭と手に追加されているNetworkTransformRefreshThrottler
コンポーネントは、特定オブジェクトのエミッションレートの削減を担います。そのため、スロットリングが有効になると、状態権限者のNetworkTransform
の位置/回転がしばらくの間は同じ値に設定され続けます。これにより、プロキシ上のデータもしばらくの間は同じ値になり、ティックベースの補間も起こらないため、正しい振る舞いになります。
このアプローチを処理するため、スロットリングが有効になると、プロキシ上ではタイムベースの補間が使用されます。これは、ティックの状態ではなく、最新の変更を受信したタイミングを参照します。
状態権限者自身のティックベースの補間データは、このアプローチによって破損してしまいますが、スロットリング中は補間処理が行われず、適切な位置への補外(位置の強制)が行われることを前提としています。
StageサンプルのNetworkRig
クラスでは、この補外が適用されます。
ここでは、StageNetworkRig
でスロットリングが有効化されます。
HardwareRig
のサブクラスStageHardwareRig
は、着席リクエスト(ユーザーが席にテレポートしたタイミングを監視するSeatDetector
クラスからトリガーされる)を受信できます。それからStageNetworkRig
は、ローカルのSeatStatus
を更新し、着席したユーザーのスロットリングを有効にします。
C#
void LocalNetworkRigSeatStatusUpdate()
{
if (IsLocalNetworkRig && stageHardwareRig && SeatStatus.Equals(stageHardwareRig.seatStatus) == false)
{
SeatStatus = stageHardwareRig.seatStatus;
}
}
public override void FixedUpdateNetwork()
{
base.FixedUpdateNetwork();
LocalNetworkRigSeatStatusUpdate();
if (Object.HasStateAuthority)
{
rigThrottler.IsThrottled = SeatStatus.seated;
leftHandThrottler.IsThrottled = SeatStatus.seated;
rightHandThrottler.IsThrottled = SeatStatus.seated;
headsetThrottler.IsThrottled = SeatStatus.seated;
}
}
出席者のステージ音声へのアクセス
会議の参加者は、ステージのマイクへのアクセスをリクエストすることができます。ステージ上のプレゼンターは、このリクエストを許可/拒否できます。
ユーザーのネットワークリグにはVoiceableAttendee
コンポーネントが含まれ、[Networked]
変数のAttendeeStatus
を持ちます。ステータスは以下の値を取ります。
- まだリクエストしていない
- ステージ音声へのアクセスをリクエストしている
- リクエストが許可された
- リクエストが許可されたが、一時的にミュートになっている
- リスエストが拒否された
ユーザーがUIから音声アクセスをリクエストすると (1) 、ステータスが更新され (2) 、ネットワーク上の変数がすべてのユーザーで同期されます (3) 。
すべてのクライアント上でコールバックが呼び出され (4) 、出席者を保持するAttendeeRegistry
コンポーネントに通知、リスナー全員に変更情報をブロードキャストします (5) 。
このようにして、ステージ上の机に関連付けられたAttendeeRequestHandler
は、リクエスト中の出席者のリストを保持して、適切にUIを更新します。
[Networked]
変数のSelectedRequestingAttendeeInfo
は、UIで選択中の出席者についての情報を持つので、各クライアントのUIはすべて同期されます。
プレゼンターが音声リクエストを承認すると (6) 、SelectedRequestingAttendeeInfo
が変更されます。
プレゼンターとリクエスト中の出席者は違う人なので、VoiceableAttendee
やAttendeeStatus
を直接変更することはできず、ネットワークオブジェクトのリグの状態権限も持ちません。
しかしSelectedRequestingAttendeeInfo
は[Networked]
変数なので、プレゼンターはローカルでこれを変更して (7) 、すべてのクライアント上で更新をトリガーします (8) 。
この更新で、各クライアントはVoiceableAttendee
のネットワークオブジェクトの状態権限を持っているかどうかをチェックし、持っているなら、出席者のステータスを変更します (9) 。
最後に、ステータスの変更ですべてのクライアント上のVoiceableAttendee
とAttendeeStatus
の更新がトリガーされ、音声が有効な出席者として見えるようになります (10) 。
- このユーザーは
DynamicAudioGroupMember
のホワイトリストに追加される(PublicSpeechHandler
クラス) - 距離によらず全員に聞こえるように、空間オーディオは無効になる
- このユーザーの
AvatarRepresentation
のLODGroup
は無効になるため、ステージ上のプレゼンターのように全員から最大ディテールで見える
動画の同期
現在の動画プレイヤーはシンプルなUnityのVideoPlayer
ですが、動画ライブラリを使用することもできます。
ステージ上のプレゼンターはステージのコンソールから、動画の開始・特定時間のシーク・ポーズが可能です。これをすべてのユーザーで同期するため、VideoControl
のNetworkBehaviour
は[Networked]
構造体のPlayState
を含み、再生状態と位置を保持します。ネットワーク上の変数であるため、プレゼンターがUIを使って変更を行うと、その変更はすべてのクライアント上でトリガーされ、各自のプレイヤーで変更が反映されます。
絵文字
音声リクエストに加えて、出席者はいつでも絵文字(エモーティコン)で感情を表現できます。
これは重要な機能ではありませんが、ユーザーが絵文字UIボタンをクリックすると、RPCによって関連したプレハブがスポーンします。つまり新しくルームに参加したユーザーは、過去に生成された絵文字を見ることはできません。(どちらにせよ、絵文字は数秒後に消えます)
また、空間内で絵文字の位置を同期する必要はないと考えたため、絵文字プレハブはネットワークオブジェクトではありません。
EmotesRequest
クラスは出席者UI上にあり、EmotesSpawner
クラスにリクエストを行って、ユーザーの位置に絵文字をスポーンします。
ネットワークオブジェクトが必要になるため、EmotesSpawner
はユーザーのネットワークリグ上に配置されています。
スクリーン共有
メインスクリーン上の配信権限をリクエストするため、音声リクエストと似た権限システムをScreenSharingAttendee
で使用していて、スクリーン共有アクセスをリクエストしたり、EmissionOrchestratorWithAuthorizationManagement
でリクエストを承認するためにステージ上のスクリーンを操作したりできます。
スクリーン共有は、uWindowCaptureでキャプチャし、Photon Video SDKで他のクライアントに送信します。
詳細はScreen Sharing Industriesアドオンをご覧ください。
スクリーン共有リクエスト管理
ステージ上でユーザーがデスクトップスクリーンの共有を許可される方法は、出席者がプレゼンターとの会話を許可される方法と似ています。
StageNetworkRigRecorder
プレハブは、Recorderアプリケーションがセッションに参加した時にスポーンされます。
このプレハブはScreenShareAttendee
クラスを含み、[Networked]
変数のScreenShareStatus
を持ちます。
C#
[Networked]
public ScreenShareStatus ScreenShareStatus { get; set; }
ステータスは以下の値を取ります。
- まだスクリーン共有をリクエストしていない
- スクリーン共有をリクエストしている
- リクエストが許可された
- スクリーン共有を停止している
- リクエストが拒否された
C#
public enum ScreenShareStatus
{
NoScreenShareRequested, // no request yet
ScreenShareCanceled, // request canceled on the recorder UI
ScreenShareRequested, // request done, waiting for answer
ScreenShareInProgress, // screensharing in progress
ScreenShareStopped, // screensharing stopped (by the speaker using the desk, or using the recorder UI)
ScreenShareRejected // screensharing rejected by the speaker
}
EmissionOrchestratorWithAuthorizationManagement
はステージ上の机に関連付けられ、スクリーン共有リクエスト中のユーザーを保持して、適切にUIを更新します。
詳細はIScreenShare
インターフェースをご覧ください。
最初のスクリーン共有リクエストは操作盤に表示されます。
ScreenShareStatus
を変更すると(例えば、プレゼンターがスクリーン共有リクエストを承認すると)ネットワーク上でブロードキャストされるため、スクリーン共有を許可されたクライアントは自身のステータスを変更できます。
したがって、スクリーン共有をリクエストしたユーザーが権限を受け取ったら、選択したデスクトップで配信が開始されます。
C#
if (ScreenShareStatus == ScreenShareStatus.ScreenShareInProgress)
{
Debug.Log("Starting Screen Sharing !");
screenSharingEmitter.ConnectScreenSharing();
}
EmitterMenuWithAuthorizationManagement
クラスは、スクリーン共有ボタンを表示して、ユーザーのメニュー操作やScreenShareStatus
に従ってテキストフィールドを更新します。
コンパイル
通常のクライアント(出席者)と、Recorderクライアント(ステージスクリーン上でデスクトップを配信する)は、同じUnityのシーンを使用しています。
そのため、コンパイルしたいクライアントに応じて手作業で修正する必要があります。
Recorderクライアントのコンパイル
Recorderアプリケーションをコンパイルするには、以下の2つのステップに従ってください。
1/ StageAvatarSelection
シーンを開きます。LoadMainSceneInRecorderMode
ゲームオブジェクトのIs Recorder Compilation Mode
にチェックを入れて、アバター選択シーンをロードせずに直接メインシーンをロードするようにします。
これは、通常クライアントとRecorderクライアントのシーンリストを一致させるために必要になります。
2/ StageWithScreenShareing
シーンを開きます。ExtendedRigSelection
ゲームオブジェクトでForce to use Recorder
を設定します。
RecorderリグのScreenShareAppWindowsSettings
クラスは、解像度の変更を担います。
これはUnityのパラメーターから手動で変更することもできます。
Project Settings
/Player
:
-Product Name
の変更 : 例として"Recorder"を追加しますProject Settings
/Player
/Resolution and Presentation
/Resolution
- Fullscreen Mode : Windowed
- Default Screen Width : 640
- Default Screen Height : 380
- Resizable : No
- Allow Fullscreen : No
通常クライアントのコンパイル
通常クライアントアプリケーションをコンパイルするには、以下の3つのステップに従ってください。
1/ StageAvatarSelection
シーンを開きます。LoadMainSceneInRecorderMode
ゲームオブジェクトのIs Recorder Compilation Mode
のチェックを外します。
2/ StageWithScreenShareing
シーンを開きます。RigSelection
ゲームオブジェクトのRecorderAppRigSelection
クラスのApp Kind
パラメーターをNormal
に設定します。
RecorderAppRigSelection
は、その選択に従ってシーンを調整します。
3/ Unityのパラメーターを確認します。
Project Settings
/Player
:
-Product Name
の変更 : 例として"Client"を追加しますProject Settings
/Player
/Resolution and Presentation
/Resolution
- Fullscreen Mode : Fullscreen Windows
- Resizable : Yes
- Allow Fullscreen : Yes
使われているXRアドオンとIndustriesアドオン
3D/XRプロジェクトのプロトタイピングを誰でも簡単に始められるように、無料のアドオンを提供しています。
詳細はXR Addonsをご覧ください。
また、Industries Circleメンバー向けに、再利用可能な総合的なアドオンを提供しています。
詳細はIndustries Addonsをご覧ください。
このサンプルで使用したアドオンは以下の通りです。
XRShared
XRSharedアドオンは、XR体験を作成するための、Fusionと互換性がある基本コンポーネントを提供しています。
プレイヤーのリグパーツの同期や、グラブやテレポートなどのシンプルな機能を担当します。
詳細はXRSharedをご覧ください。
Spaces
同じルームに複数のインスタンスを作れるように、Meetingサンプルと同じアプローチを再利用しています。
ユーザーはパブリックルームか、特定のルーム番号のプライベートルームに参加できます。
これは、アバター選択画面か、アプリケーションメニューから選択することができます。
詳細はSpace Industriesアドオンをご覧ください。
Connection Manager
接続処理の起動とユーザーのスポーンを管理するために、ConnectionManager
アドオンを使用しています。
詳細はConnectionManagerアドオンをご覧ください。
Extended Rig Selection
サンプルで必要となる3つのリグを切り替えるために使用したアドオンです。
- Metaビルド用のVRリグ
- WindowsとMac用のデスクトップリグ
- スクリーン上でデスクトップを配信するWindows RecorderアプリケーションをビルドするためのRecorderリグ
詳細はExtended Rig Selection Industriesアドオンをご覧ください。
Avatar
このアドオンは、シンプルなアバター一式を含むアバター機能に対応しています。
詳細はAvatar Industriesアドオンをご覧ください。
Ready Player Me Avatar
Ready Player Meアバターとのインテグレーションのアドオンです。
詳細はReady Player Me Avatar Industriesアドオンをご覧ください。
Social distancing
快適なパーソナルスペースを確保するため、Social distancingアドオンを使用しています。
詳細はSocial distancing Industriesアドオンをご覧ください。
Locomotion validation
プレイヤーの移動を(定義されたシーン境界にとどまるように)制限するため、Locomotion validationアドオンを使用しています。
詳細はLocomotion validation Industriesアドオンをご覧ください。
Dynamic Audio group
快適さと帯域消費を最適化するユーザー間の距離を考慮しながら、ユーザー同士のチャットを可能にするため、Dynamic Audio groupアドオンを使用しています。
参加者が同じルームにいないプレゼンターの音声も聞き取れるように、ホワイトリスト機能も使用しています。
詳細はDynamic Audio group Industriesアドオンをご覧ください。
Audio Room
AudioRoom
アドオンは、チャットバブルの防音に使用されています。
詳細はAudio Room Industriesアドオンをご覧ください。
Chat Bubble
Expoシーンに含まれる静的なチャットバブルを提供するアドオンです。
詳細はChat Bubble Industriesアドオンをご覧ください。
Virtual Keyboard
プレイヤー名やルームIDを編集するために、バーチャルキーボードが必要です。
詳細はVirtual Keyboard Industriesアドオンをご覧ください。
Touch Hover
3DオブジェクトやUI要素とのプレイヤーのインタラクションを増やすために、このアドオンが使用されています。インタラクションは、仮想的な手や光線で表現できます。
詳細はTouch Hover Industriesアドオンをご覧ください。
Feedback
アプリケーションのサウンドと、触覚や音声のフィードバックを集中管理するために、Feedback
アドオンを使用しています。
詳細はFeedbackアドオンをご覧ください。
Screen Sharing
ユーザーは、プレゼンターに許可されると、ステージの大スクリーン上に自身のコンピューターのスクリーンを共有しブロードキャストできます。
詳細はScreen Sharing Industriesアドオンをご覧ください。
サードーパーティー製コンポーネント
- Oculus Integration
- Oculus Lipsync
- Oculus Sample Framework hands
- Ready player me
- Sounds
既知の問題
- Quest : ユーザーがログインする前にスクリーン共有が初期化されると、スクリーン共有の表示に時間がかかったり失敗したりします。
- 概要
- アーキテクチャ概要
- シーンロジック
- ステージ
- 座席と帯域削減
- 出席者のステージ音声へのアクセス
- 動画の同期
- 絵文字
- スクリーン共有
- スクリーン共有リクエスト管理
- コンパイル
- 使われているXRアドオンとIndustriesアドオン
- XRShared
- Spaces
- Connection Manager
- Extended Rig Selection
- Avatar
- Ready Player Me Avatar
- Social distancing
- Locomotion validation
- Dynamic Audio group
- Audio Room
- Chat Bubble
- Virtual Keyboard
- Touch Hover
- Feedback
- Screen Sharing
- サードーパーティー製コンポーネント
- 既知の問題