LoginSignup
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)への参加もよろしくおねがいします。

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
What you can do with signing up
5