LoginSignup
7
5

More than 1 year has passed since last update.

カメラの画面でUnityアプリ!? THETA XでUnityを使ったプラグイン開発。

Posted at

はじめに

リコーのYuukiSです。
弊社ではRICOH THETAという全周囲360度撮れるカメラを出しています。
RICOH THETA V, RICOH THETA Z1, RICOH THETA Xは、OSにAndroidを採用しています。Androidアプリを作る感覚でTHETAをカスタマイズすることもでき、そのカスタマイズ機能を「プラグイン」と呼んでいます(詳細は本記事の末尾を参照)。

ついにTHETAに液晶ディスプレイが!

2022年7月22日に発売されたTHETA Xには、タッチ可能なディスプレイが搭載されています。
これにより、これまでのTHETAでは出来なかったカメラ単体でのライブビューやプレビューが可能になり、撮影体験が向上しています。
さらに、従来のTHETA VやZ1と同様にAndroidを搭載していますので、Androidアプリも画面に表示し操作する事が可能です。

せっかくAndroidが動いてタッチパネルも搭載されたTHETA X。
どうせならリッチな3D表現もしてみたい、と思い立ってUnityアプリを動かす試行錯誤をしてみました。
THETAXでUnity.gif
その結果が、この通り。
無事Unityで作ったアプリケーションが動作しました。
ただ、なかなか工夫したポイントもいくつかあり、今回はそのポイントを紹介します。
※Unityの表示確認にSDユニティちゃんを利用させて頂きました。(© Unity Technologies Japan/UCL)

Unity as a Libraryを使う

今回、まず最初にUnity単体でビルドしたアプリをインストールし動かしてみました。
その結果、アプリの動作は問題ないもののTHETA固有のハードウェアボタンの押し込みを検出できないことが判明しました。
(Input.GetKeyDown等で色々試したのですが駄目だったので、もし動作した方がいましたらコメント下さい)
THETA Xの標準のプラグインは、Modeボタンの長押しで終了する仕様になっているので、このボタンが検出できないとアプリ終了動作を共通に出来ません。
なので、今回は描画部分にのみUnityを利用するUnity as a Libraryという枠組みを利用することにしました。

Unity as a Libraryとは

Unityの機能をフレームワークとしてネイティブアプリから読み出して利用できる機能です。
image.png
公式ページリンク

これを利用すると例えばUI部分はユーザが慣れ親しんだiOSやAndroidのネイティブ表示を利用しつつ、複雑な3D描画はUnityを利用するといったことが可能になります。

今回は下図の様にAndroidのネイティブアプリを新規で構成し、THETAの一般機能の制御にはTHETA Plug-in Library、画面描画はUnity as a Libraryを用いる構成にしました。
image.png

これにより、Modeボタン等の振る舞いはネイティブアプリのTHETA Plug-in Libraryで管理することが出来るので、前述したアプリ終了動作の問題が解消できます。

Unity as a Libraryの利用準備

Unity as a Libraryでは、Unity側のシーンはUnityで構築し、それをエクスポートしてネイティブアプリの開発環境(Android Studio)で取り込んでビルドします。
今回、この一連の流れは@cha84rakanalさんの以下の記事を大変参考にさせて頂きました。
AndroidアプリにUnity as a Libraryでリッチな3Dを簡単に組み込む

ほぼ上記の記事を踏襲すれば準備は完了ですが、自分の環境では下記エラーが出てAndroid Studioでビルドが通りませんでした。

Could not get unknown property 'unityStreamingAssets' for object of type com.android.build.gradle.internal.dsl.AaptOptions

調べると、どうやらUnity2020以降で発生するエラーのようでgradle.propertiesファイルに以下の1行を追加することで解消されました。

unityStreamingAssets=.unity3d

THETA Plug-in Libraryの導入

THETAの各機能を便利に利用するため、THETA Plug-in Libraryを導入します。
導入の方法は、GitHubのHow to Useに従えば大丈夫です。

MainActivityの実装

以上でUnity側のシーンの利用とTHETA側のプラグイン利用の準備が整ったので、MainActivityを実装していきます。
と言っても大部分は下記の記事を踏襲します。
AndroidアプリにUnity as a Libraryでリッチな3Dを簡単に組み込む

THETA向けの変更点としては、継承するクラスをPluginActivityに変更し、下記のようなTHETA特有の制御を入れました。

  • onResume()で notificationWebApiCameraOpen()を呼び出し
    今回、Unity側からのTHETA制御にはTHETA Web APIを利用しました。
    ”RICOH THETA X におけるプラグイン開発”の記事にある通り、THETA XではプラグインからのWeb API利用/終了には手続きが追加されました。
    よって、onResume時にこの手続きを行い、Unity側からWeb APIを利用できるようにしています。
  • onPause()で、notificationWebApiCameraClose()を呼び出し
    同様に終了時の手続きも行います。
  • onDestroy() でunityPlayer?.quit()を呼び出し
    Modeボタンが長押しされた場合呼ばれるonDestroy()内で、Unity側の処理も終了する様にしています。

以上でMainActivityの実装も完了です。

(参考までにMainActivity全体のコードも折り畳んで記載しておきます)
MainActivity.kt
package com.yuukis.uaal4thetax

import android.os.Bundle
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
import com.theta360.pluginlibrary.activity.PluginActivity
import com.unity3d.player.UnityPlayer

class MainActivity : PluginActivity() {

    var unityPlayer: UnityPlayer? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        unityPlayer = UnityPlayer(this)
        window.clearFlags(1024)

        findViewById<ConstraintLayout>(R.id.unity)?.addView(
            unityPlayer, ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
            )
        )
        unityPlayer?.requestFocus()
    }

    // Notify Unity of the focus change.
    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)
        unityPlayer?.windowFocusChanged(hasFocus)
    }

    override fun onResume() {
        super.onResume()
        unityPlayer?.resume()
        notificationWebApiCameraOpen()
    }

    override fun onPause() {
        super.onPause()
        unityPlayer?.pause()
        notificationWebApiCameraClose()
    }

    override fun onDestroy() {
        super.onDestroy()
        unityPlayer?.quit()
    }
}

Unity側からTHETAの制御をおこなう

ここまでで、ネイティブアプリ側からTHETA Plug-in Libraryを利用しつつUnityのシーンが描画出来るようになりました。
ただ、これだけでは単にディスプレイ上に表示が出るのみなので、画面のボタンを押したらTHETAの撮影が出来るようにしてみましょう。

これには、ネイティブアプリ側の画面にボタンを追加しPlug-in Libraryから撮影をする方法と、Unityシーン側にボタンを追加しWeb APIから撮影する2通りの方法が存在します。
今回はUnity側でUIを完結したかったため、後者を選択しました。
(ちなみにUnity as a LibraryではネイティブとUnity間で通信する仕組みもあるので、これを利用してUnityシーン側のボタンが押されたことをネイティブアプリ側に通知し、ネイティブアプリ側でPlug-in Libraryから撮影をすることも可能だと思います。)

UnityからWeb APIを利用する例は、過去の記事"UnityちゃんとTHETAでMixedRealityな記念撮影を"で紹介しています。

具体的なコードは以下の通りです。

 IEnumerator sendTakePictureSignal()
    {
        string url = "http://127.0.0.1:8080/osc/commands/execute";
        takepicObject.name = "camera.takePicture";
        settedJson = JsonUtility.ToJson(takepicObject);
        byte[] postData_takePic = System.Text.Encoding.UTF8.GetBytes(settedJson);
        var request_takePic = new UnityWebRequest(url, "POST");
        request_takePic.uploadHandler = (UploadHandler)new UploadHandlerRaw(postData_takePic);
        request_takePic.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
        request_takePic.SetRequestHeader("Content-Type", "application/json");
        yield return request_takePic.SendWebRequest();
        if (request_takePic.isNetworkError || request_takePic.isHttpError)
        {
            Debug.Log(request_takePic.error);
            Debug.Log(request_takePic.downloadHandler.text);
        }
        else
        {
            Debug.Log(request_takePic.downloadHandler.text);
        }
    }

この関数を画面に配置したボタンのonClickに割り当てて、完成です。
コンポ 1_2_1.gif
GIFでは分かりにくいですが、画面のボタンを押すとシャッターが切れています。
(せっかくなので、同時にユニティちゃんにジャンプしてもらいました)

まとめ

今回は、THETA XでUnityを活用する試みを紹介しました。
THETAで撮影できる全天球画像と3Dコンテンツは相性が良いので、色々出来ることもありそうです。
皆さんもぜひ、遊んで試してみてください。

RICOH THETAプラグインパートナープログラムについて

THETAプラグインをご存じない方はこちらをご覧ください。
パートナープログラムへの登録方法はこちらにもまとめてあります。
QiitaのRICOH THETAプラグイン開発者コミュニティ TOPページ「About」に便利な記事リンク集もあります。
興味を持たれた方はTwitterのフォローとTHETAプラグイン開発コミュニティ(Slack)への参加もよろしくおねがいします。

7
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
5