This document is about: FUSION 2
SWITCH TO

Stage Screen Sharing

Level 4
Available in the Industries Circle
Circle

概要

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のデモバージョンが、以下からダウンロードできます。

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クライアントとして調整するため、ExtendedRigSelectionRecorderという名前の固有のリグ設定を含みます。

  • 特定のエミッタープレハブから、デフォルトのユーザープレハブを変更する
  • アンビエントサウンドを無効化する
  • レコーディング(特定のリグ・UI・エミッター)に必要なオブジェクトを有効化する
  • 出席者名簿にアプリケーションを登録する

ステージ

ステージの管理にChatBubbleアドオンが使用されます。

デフォルトでは、ステージのチャットバブルの収容数は1ユーザーに制限されているので、プレゼンターが既にステージ上にいる時に他の人はステージに上がれません。プレゼンターは、ステージコンソールからこの値を変更できます。

プレゼンターがすべてのユーザーで正しく表示されるために、ステージに上がったユーザーのLODGroupは無効化され、LODがトリガーされないことが保証されます。(PublicSpeechHandlerStageCameraManagerクラスをご覧ください)

音声

プレゼンターがいるステージのチャットバブルに他の参加者はいないため、DynamicAudioGroupアドオン(バージョン2.0.2)のホワイトリスト機能を使用して、すべての参加者が常にプレゼンターの音声を聞けるようにします。
また、AudioSourceの3D音響を削除するので、プレゼンターの音声はルームのどこでも聞くことが可能です。

プレゼンターカメラ

プレゼンターカメラは、ステージ上のユーザーに追従します。ステージ上のユーザーリストを保持するため、StageCameraManagerコンポーネントはIAudioRoomListenerインターフェースを実装しています。
ユーザーがステージに上がると、カメラトラッキングとレコーディングをトリガーします。
StageCameraManagerは複数のカメラを処理できます。各プレゼンターを追従するカメラ間を移動して、最も関連性あるプレゼンターのみの表示を有効にします。
カメラの描画レートは低く、カメラの移動と共にStageCameraクラスで実行されます。
カメラは、カメラリグのTransformに関連し、そのTransformx軸に沿って移動します。

座席と帯域削減

着席中のプレイヤーの位置は更新する必要がないため、着席中は更新レートを削減する機能を追加しています。
更新レートは離席すると通常の頻度に戻ります。これによって、帯域消費を削減し、アプリケーションの参加人数を増加させます。

プレイヤーのネットワークリグの頭と手に追加されている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;
     }
}

出席者のステージ音声へのアクセス

会議の参加者は、ステージのマイクへのアクセスをリクエストすることができます。ステージ上のプレゼンターは、このリクエストを許可/拒否できます。

Attendee system

ユーザーのネットワークリグにはVoiceableAttendeeコンポーネントが含まれ、[Networked]変数のAttendeeStatusを持ちます。ステータスは以下の値を取ります。

  • まだリクエストしていない
  • ステージ音声へのアクセスをリクエストしている
  • リクエストが許可された
  • リクエストが許可されたが、一時的にミュートになっている
  • リスエストが拒否された
Attendee system

ユーザーがUIから音声アクセスをリクエストすると (1) 、ステータスが更新され (2) 、ネットワーク上の変数がすべてのユーザーで同期されます (3)
すべてのクライアント上でコールバックが呼び出され (4) 、出席者を保持するAttendeeRegistryコンポーネントに通知、リスナー全員に変更情報をブロードキャストします (5)

このようにして、ステージ上の机に関連付けられたAttendeeRequestHandlerは、リクエスト中の出席者のリストを保持して、適切にUIを更新します。
[Networked]変数のSelectedRequestingAttendeeInfoは、UIで選択中の出席者についての情報を持つので、各クライアントのUIはすべて同期されます。

プレゼンターが音声リクエストを承認すると (6)SelectedRequestingAttendeeInfoが変更されます。
プレゼンターとリクエスト中の出席者は違う人なので、VoiceableAttendeeAttendeeStatusを直接変更することはできず、ネットワークオブジェクトのリグの状態権限も持ちません。
しかしSelectedRequestingAttendeeInfo[Networked]変数なので、プレゼンターはローカルでこれを変更して (7) 、すべてのクライアント上で更新をトリガーします (8)
この更新で、各クライアントはVoiceableAttendeeのネットワークオブジェクトの状態権限を持っているかどうかをチェックし、持っているなら、出席者のステータスを変更します (9)

最後に、ステータスの変更ですべてのクライアント上のVoiceableAttendeeAttendeeStatusの更新がトリガーされ、音声が有効な出席者として見えるようになります (10)

  • このユーザーはDynamicAudioGroupMemberのホワイトリストに追加される(PublicSpeechHandlerクラス)
  • 距離によらず全員に聞こえるように、空間オーディオは無効になる
  • このユーザーのAvatarRepresentationLODGroupは無効になるため、ステージ上のプレゼンターのように全員から最大ディテールで見える

動画の同期

現在の動画プレイヤーはシンプルなUnityのVideoPlayerですが、動画ライブラリを使用することもできます。

ステージ上のプレゼンターはステージのコンソールから、動画の開始・特定時間のシーク・ポーズが可能です。これをすべてのユーザーで同期するため、VideoControlNetworkBehaviour[Networked]構造体のPlayStateを含み、再生状態と位置を保持します。ネットワーク上の変数であるため、プレゼンターがUIを使って変更を行うと、その変更はすべてのクライアント上でトリガーされ、各自のプレイヤーで変更が反映されます。

Attendee system

絵文字

音声リクエストに加えて、出席者はいつでも絵文字(エモーティコン)で感情を表現できます。

Attendee system

これは重要な機能ではありませんが、ユーザーが絵文字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インターフェースをご覧ください。
最初のスクリーン共有リクエストは操作盤に表示されます。

Fusion Stage Screen Sharing Control Desk

ScreenShareStatusを変更すると(例えば、プレゼンターがスクリーン共有リクエストを承認すると)ネットワーク上でブロードキャストされるため、スクリーン共有を許可されたクライアントは自身のステータスを変更できます。

したがって、スクリーン共有をリクエストしたユーザーが権限を受け取ったら、選択したデスクトップで配信が開始されます。

C#

if (ScreenShareStatus == ScreenShareStatus.ScreenShareInProgress)
{
    Debug.Log("Starting Screen Sharing !");
    screenSharingEmitter.ConnectScreenSharing();
}

EmitterMenuWithAuthorizationManagementクラスは、スクリーン共有ボタンを表示して、ユーザーのメニュー操作やScreenShareStatusに従ってテキストフィールドを更新します。

Fusion Stage Screen Sharing Client

コンパイル

通常のクライアント(出席者)と、Recorderクライアント(ステージスクリーン上でデスクトップを配信する)は、同じUnityのシーンを使用しています。
そのため、コンパイルしたいクライアントに応じて手作業で修正する必要があります。

Recorderクライアントのコンパイル

Recorderアプリケーションをコンパイルするには、以下の2つのステップに従ってください。

1/ StageAvatarSelectionシーンを開きます。LoadMainSceneInRecorderModeゲームオブジェクトのIs Recorder Compilation Modeにチェックを入れて、アバター選択シーンをロードせずに直接メインシーンをロードするようにします。
これは、通常クライアントとRecorderクライアントのシーンリストを一致させるために必要になります。

2/ StageWithScreenShareingシーンを開きます。ExtendedRigSelectionゲームオブジェクトでForce to use Recorderを設定します。

RecorderリグのScreenShareAppWindowsSettingsクラスは、解像度の変更を担います。
これはUnityのパラメーターから手動で変更することもできます。

Fusion Stage Screen Sharing Recorder Unity Parameters
  • 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のパラメーターを確認します。

Fusion Stage Screen Sharing Recorder Unity Parameters
  • 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アドオンをご覧ください。

サードーパーティー製コンポーネント

既知の問題

  • Quest : ユーザーがログインする前にスクリーン共有が初期化されると、スクリーン共有の表示に時間がかかったり失敗したりします。
Back to top