Closed80

MagicLeapプロンプターアプリ

松本隆介松本隆介

発表会とかでカンニングペーパー的な感じに使いたいアプリ
あがり症な人は人前で喋るのが苦手、視界を覆うMagicLeapならいい感じに緊張緩和できるのでは?

松本隆介松本隆介

実際に登壇する時のスライドと登壇者が喋る言葉はイコールではない、緊張すると話したかった内容が頭から抜けスライドの朗読になって薄ペラな発表になるためMagicLeap側でプロンプターのように話す内容( セリフ? )を表示して登壇者はそれを読む

松本隆介松本隆介

https://qiita.com/wakagomo/items/6e83019481d7cd326e72

これ良さそう、これ + Photonなりで通信してやれば上手く行くかも?

松本隆介松本隆介

仕事終わったらまずはMagicLeap <-> UnityEditorでの通信ができるところまでを確認する

松本隆介松本隆介

とりあえず同一プロジェクトでWindows用とMagicLeap用ビルドすればいいか、PhotonBoltだとBoltAssetを共有することで別々のプロジェクトでも管理できるけど結構面倒くさかった

松本隆介松本隆介

ひとまずWindows同士の通信でイベントベースで通信できることを確認した

松本隆介松本隆介

同一プロジェクトでいじると不具合が起こりそうなのでリポジトリを同一にして一つ下の階層にWindows用のUnityプロジェクトとMagicLeap用のプロジェクトを配置
BoltAssetについてはWindows側で編集して其れをMagicLeap側に適用する形にする、ネットワーク周りのコードも全部Windows側で編集しMagicLeap側はそれを利用する形にする

松本隆介松本隆介

セッションが決定したのちに遷移するシーンは同一でなければならないなんてことはなかったはずだからこの作り方で一応できるはできると思うんだけどなぁ
Windows_Start : Serverの起動、Server起動後ユーザーがセッションに入ってきたらシーン遷移 -> Windows_Main
MagicLeap_Start : Clientの起動、Serverが開いたセッションを見つけ次第そこに入る -> MagicLeap_Main

こんな感じの作り

松本隆介松本隆介

遷移先のシーンは同じじゃないとダメだったわ
じゃあ遷移先でシーンの構成を動的に変更すればいいか
#PLATFORM_STANDALONE_WIN
#PLATFORM_LUMIN

これで切り分け

松本隆介松本隆介

入力周りはジェスチャでいいかも
アプリ閉じる時とスライド戻す時はコントローラーで?
まぁ最初はコントローラ入力でいいか

松本隆介松本隆介

試しにMagicLeapとWindowsのプロジェクトを一つにまとめてみる

松本隆介松本隆介

なんかうまくいきそう、うまくいったら一つにまとめてEditorの拡張で切り替えられるようにする

松本隆介松本隆介

マウスのイベント発火にはこれが使えそう..?
https://whoopsidaisies.hatenablog.com/entry/2013/03/22/142031

松本隆介松本隆介

前のスライドに戻れるようにRightArrow,LeftArrowの入力ができるようにしよう

松本隆介松本隆介

Windows側は一段落ついた、これからML側を進める
欲しい機能としてはこんな感じかな

  1. スピーカーノート
  2. 経過時間表示
松本隆介松本隆介

スピーカーノートはとりあえず実機に.txtファイルを入れてそれを利用した形で表示する
--- <- この文字列のみの行で改行とする

松本隆介松本隆介

コントローラのタッチパッドの左右ジェスチャでページ送り戻りを実装する

松本隆介松本隆介

一通りのスピーカーノート機能は実装出来たように思う
note.txtからテキストをロードし表示 --- この文字列でページの区切り
タイマーのスタートとリセット機能

松本隆介松本隆介

なんか知らんけど.txtファイルに記述されてる日本語が表示されない...
MagicLeap側の問題なのか.txtファイル側の問題なのか切り分けないとな
とりまuGUIに直接日本語打ち込んで表示されるかどうか見てみるか

松本隆介松本隆介

PC側の情報をMagicleapに送信したい
今のところリアルタイムである必要はないのでMagicleapからアクション → PCがリアクションとしてスクショを返す的な形がいいかも

松本隆介松本隆介

透過ウィンドウでスクショしたけど思ったのと違うのが撮れた...

松本隆介松本隆介

そりゃアプリ自体のスクリーンショットだからこうなるか...

松本隆介松本隆介

凹みTipsを頼りにしてみる
https://tips.hecomi.com/entry/2016/12/04/125641

松本隆介松本隆介

PlayModeに入ったとたんすぐ落ちると思ったらPlayerSettingsのGraphicsAPIの設定がOpenGLだった、ZeroIterationを利用するときはOpenGLにする必要があるのでいちいち切り替えが面倒くさそう( 後でエディタ拡張で自動化したい )

Direct3D11にしたらちゃんとuDesktopDuplicationは動いた

松本隆介松本隆介

なんでかわからんがTexture2Dから取得したbyte配列を使ってTexture2Dを生成するのがうまくいかない...

↓これでうまくいくと思ったんだけどなぁ...


            // uDesktopDuplicationからデスクトップのキャプチャを取得する.
            var capture = tex.monitor.texture;
            var rawData = capture.GetRawTextureData();

            Texture2D texture = new Texture2D(2, 2);
            texture.LoadImage(rawData); // 一旦生のデータでテクスチャを生成できるのを確認する必要がある.
            m.material.mainTexture = texture;
            

松本隆介松本隆介

ヨシ、何とかテクスチャをbyte[] -> string -> byte[] -> Texture2D -> 何らかのメッシュに張り付ける

これが出来た
ただbyte[]を圧縮すると画像がおかしくなるから今度はそこが課題かな.

松本隆介松本隆介

最後の文字 -1 してたけどこれいらないかも? 業務終了後に試してみる

松本隆介松本隆介

ひとまず↓のような流れが出来た

  1. RenderTextureでキャプチャ
  2. RenderTextureの内容をEncodeToPNG()でbyte配列に
  3. byte配列をstring配列に変換
  4. string配列を圧縮したstring配列にし、最後の要素に -e のマーカーを付けた
  5. 受け取った( 想定 )のコードでstring配列を一つのstringにし、byte配列に変換
  6. byte配列からTexuter2Dを生成、Spriteに変換しuGUIのImageへ適用

作っておいてなんだが何やってるんだろうな俺...

別クラスに分けたところは省略、最初のscreenCapture.CaptureToStrings()の部分が 1 ~ 3 の処理
スクショっとったやつをstring配列に変換している.


        public void Capture()
        {
           // 1 ~ 3 の処理.
            string[] captureStrings = screenCapture.CaptureToStrings();

            // 4 の処理.
            // 受け取ったstringを圧縮.
            var compressStrings = new List<string>();
            for (var i = 0; i < captureStrings.Length; ++i)
            {
                if (i == captureStrings.Length - 1)
                {
                    // 最後の要素にはマーカーをつける.
                    compressStrings.Add(StringCompressor.CompressFromString(captureStrings[i]) + "-e");
                }
                else
                {
                    compressStrings.Add(StringCompressor.CompressFromString(captureStrings[i]));
                }
            }

            // stringにしたデータを送信.
            StartCoroutine(SendCapture(compressStrings));

            // 5 の処理.
            // 受信、イベントを受け取るときは List にキャッシュし -e マーカーのついているデータが来るまで Listにデータを積む.
            string[] recieve = compressStrings.ToArray();
            var decompressStrings = new StringBuilder();
            for (var i = 0; i < recieve.Length; ++i)
            {
                // 最後の要素のマーカーを取り除く.
                decompressStrings.Append(StringCompressor.DecompressToStr(recieve[i].Replace("-e", "")));
            }
            File.WriteAllText(Application.persistentDataPath + "/jetson.txt", decompressStrings.ToString());
            var texture = screenCapture.StringToTexture2D(decompressStrings.ToString());

            // 6 の処理.
            // 何らかのテクスチャに張り付ける.
            m.material.mainTexture = texture;
            Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero);
            GameObject go = GameObject.Find("Hoge");
            go.GetComponent<UnityEngine.UI.Image>().sprite = sprite;
        }

松本隆介松本隆介

PhotonBoltでデータのやり取りが無理すじっぽかったらどっかにデータを移動してそこから取得するようにしてみるか

松本隆介松本隆介

よっしゃ、ひとまずPCで撮影したスクリーンショットをMagicLeapに送信してMagicLeap側で再構築できるようにしたぞ!

松本隆介松本隆介

今時間計ったらPCが送信開始してから46秒で構築完了した( MagicLeap側はZeroIterationの環境 )、実機だともっと厳しいかもしれんな

松本隆介松本隆介

なんか知らんがOutOfRangeの例外が出てるな PCからMagicLeapに送信するとき.

松本隆介松本隆介

Firebase Storageのチュートリアルはこれかな?
https://firebase.google.com/docs/storage/unity/start?hl=ja

Unityでのストレージへの参照のチュートリアル
https://firebase.google.com/docs/storage/unity/create-reference?hl=ja

Unityからファイルをアップロードする方法
https://firebase.google.com/docs/storage/unity/upload-files?hl=ja

ファイルをダウンロードする方法
https://firebase.google.com/docs/storage/unity/download-files?hl=ja

松本隆介松本隆介

Firebaseだとなんかうまくいかない、ここはPUNでメッセージを送信する方法に切り替えたほうがいいかもしれない

松本隆介松本隆介

ポスタリゼーションと色を灰色、白色の二色にすることで50秒弱かかるところをおよそ3秒ほどまで縮めた
但し、MagicLeap側でガクッっとフレームレートが落ちるのでこの辺は改善したほうがいいかもしれない

松本隆介松本隆介

スライドの資料用に特に編集してないテクスチャとモノクロ、ポスタリゼーションでのデータ送信回数の違いのスクリーンショットを作っておく

Hidden comment
松本隆介松本隆介

uDesktopDuplicationと透過ディスプレイが相性が悪いみたい、uDesktopDuplicationを入れただけの差分でブランチ切って試したらうまく動かない、その直前のdevelopブランチではちゃんと動く( なんかMagicLeap云々のエラーが出てるが... )

とりあえずuDesktopDuplicationと透過ディスプレイの組み合わせはよろしくない事がわかった

松本隆介松本隆介

念のためRunInBackGroundにチェックを入れてPCアプリをディスプレイモードで起動して動くかどうか見てみたらちゃんと動いた、悔しいけどこの方針で行くか、こうすれば何とかスクリーンショットはMagicLeap側に送信できるはずなんだよね

松本隆介松本隆介

とりあえずPCアプリの方は動いてるみたいだから今度はMagicLeap側でメッセージを受け取ってスクリーンショットを再構築する処理を作らねば

松本隆介松本隆介

今のところネットワークが切断することは起きてないが、今後切断されたら再度接続しなおす処理と現在接続状態か否かのインジケータくらいは欲しい

松本隆介松本隆介

インジケータは作ったので一応切断した状態はわかるようになった、復帰処理は今のところ出来てない

松本隆介松本隆介

MagicLeap側のUIは

前ノート 次ノート
ScreenShot
前スライド 次スライド

こんな感じか?

松本隆介松本隆介

各スイッチはトリガーを引いた状態で接触したら反応するように
OnTriggerEnter + Trigger 1 で判定とする

松本隆介松本隆介

常にボタンを表示してるとうっとおしいからトリガーを引ききったときに表示にしよう、そうすればトリガーを引ききってるかどうかもわかる

松本隆介松本隆介

スライド作成に取りかかる、来週発表だけど俺の場合スローペースだから今日から始めてちょうどいいくらい

松本隆介松本隆介

画像転送を頑張って時間短くしたよりもUIの工夫とかの方がいいかもしれないな、そっちの方が他の人のニーズに沿ってそうだし

このスクラップは2021/12/10にクローズされました