Oculus Quest / Unity もろもろ

Oculus Quest のゲームレビューと、Unityを使った開発について書く

【Oculus Quest】Beat Saber レビュー

Oculus Questを買ってまず最初にみんながやるであろうゲーム、Beat Saber。
f:id:malt03:20190602185458j:plain

めちゃめちゃ素晴らしいゲームなことは間違いないんだけど、買ってみて感じたネガティブな意見を書いていこうと思う。
概して、Beat Saberは素晴らしいゲームなんだけど、Oculus Questでやるべきゲームでは今の所ないよね、という話。大きく2つ。

MODを入れられない

MODっていうのは、ユーザーたちが勝手にゲームに変更を加える手段のこと。
dic.nicovideo.jp

Beat Saberは音ゲーであり、音ゲーはやっぱり自分の好きな音楽をやりたい。
だけど、Oculus Questには今の所MODを入れる手段がないいので、曲を追加できない。
ならRift版買ったほうが良いんじゃないって話。

と思っていたら公式Twitterでこんな発表が!胸熱。

結局これまでユーザーたちがつくってきたMODで遊べないのは残念ではあるけれど、今後はみんな公式エディターつかってレベルを作っていくんだろうし、ここの部分のデメリットは無くなったといって良いと思う。

画面共有や配信が出来ない

Oculus Questには標準でスマホやChromecastとの画面共有や、Facebookでのライブ配信機能がついているのだが、音楽の権利的なアレなのかなんなのかわからないけど、Beat Saberはその機能をサポートしていない。
Beat Saberほど家族や友達にプレイを見てもらいたかったり、配信受けするゲームもあまりないと思うのに…。

当然Oculus Riftだったらそんなことも出来る。うーん…。
録画は出来るんだけどなぁ。

まとめ

とはいえめちゃめちゃ面白いので、絶対にやるべきゲームなのは間違いない。
Oculus Questを買って、まだBeat Saberをやったことがないなら速攻で買うべきだと思う。

$HOME/Library/Android/sdk/tools/monitor の起動に失敗する問題

Oculus Questでデバッグするにあたって monitor を起動したいが、エラーが出てうまくいかなかった。
$HOME/Library/Android/sdk/tools/lib/monitor-x86_64/configuration/1559226132541.log にログが出ているので見ると、こんな感じ。

java.lang.IllegalStateException: Unable to acquire application service. Ensure that the org.eclipse.core.runtime bundle is resolved and started (see config.ini).
        at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:74)
        at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:353)
        at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:180)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:629)
        at org.eclipse.equinox.launcher.Main.basicRun(Main.java:584)
        at org.eclipse.equinox.launcher.Main.run(Main.java:1438)

Info.plistをいじる

ログを見てconfig.iniを見たくなるが今回さわるのはそこじゃなくInfo.plist$HOME/Library/Android/sdk/tools/lib/monitor-x86_64/monitor.app/Contents/Info.plistにあった。
見つからなかったら、find ~/Library/Android/sdk/tools/ | grep Info.plis すると良いと思う。
以下の通り、-vmの行でjavaのパスを指定すると動く。

  <key>Eclipse</key>
        <array>
            <!-- to use a specific Java version (instead of the platform's default) uncomment one of the following options:
                <string>-vm</string><string>/System/Library/Frameworks/JavaVM.framework/Versions/1.4.2/Commands/java</string>
                <string>-vm</string><string>/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Commands/java</string>
            -->
            <string>-vm</string><string>/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/bin/java</string>
            <string>-keyring</string><string>~/.eclipse_keyring</string>
            <string>-showlocation</string>
            <!-- WARNING:
                If you try to add a single VM argument (-vmargs) here,
                *all* vmargs specified in eclipse.ini will be ignored.
                We recommend to add all arguments in eclipse.ini
             -->
        </array>

参考

qiita.com

Oculus Quest / Unity のデバッグ方法

Unity で Oculus Quest 開発をしている中でpringfデバッグの方法がわからなかったので調べた。
方法は2つあって、おすすめは OVRDebugConsole を使う方法。

Debug.Logを使う

qiita.com この記事がとても参考になった。Oculus Questで詰まったとき、とりあえずOculus Goで検索するソリューションは鉄板。
ただし、この方法だとVR画面を見ながらログが見えない。PC画面とVR画面を同時に見ることは出来ないので。

うまくmonitorが動かない場合

oculus.hatenablog.com

OVRDebugConsoleを使う

そこで、ゲーム画面内にログを表示する。
公式ドキュメントも存在しておらず、/Assets/Oculus内を漁っていて見つけた。
使い方はとても簡単。

OVRDebugConsoleとOVRDebugConsoleOutputの配置

適当な場所にOVRDebugConsoleOVRDebugConsoleOutputを配置する。
どこでも良いけど、わかりやすいようにOVRCameraRigとかの下にするのが良さそう。

f:id:malt03:20190531111910p:plain

textMsgの設定

OVRDebugConsoletextMsgを設定する。ドラッグアンドドロップで楽ちん。
出力するための実装はこれでおしまい。素晴らしすぎる。 f:id:malt03:20190531112118p:plain

ログ出力

コードのどこからでも、OVRDebugConsole.Logを呼び出せばゲーム画面内にログが出力される。やった!
↓の動画はラケットのvelocityを0.1秒ごとに出力している様子。

Unityでどうにもうまくオブジェクトが反発しないときの確認事項

Unity初心者としては、ちゃんとやっているはずなのに、どうにも壁にボールとかが跳ね返ったりしないことがある。
そんなときの確認事項。

Bounce Threshold を確認

一番簡単なやつ。
Unityでは一定速度以下の衝突を無視するようになっている。
多分、シミュレーションを軽量にしたり、例えば重力でバウンドしているのがいつまで経っても静止しない問題を解決するためとかだと思う。
[Edit] > [Project Settings...] を開いてBounce Thresholdを0.1とかにしてみる。 f:id:malt03:20190530012512p:plain

オブジェクトごとのMassを確認

オブジェクトの位置をコードで固定していたりしても、Massの値によって固定している方のオブジェクトを押せてしまう。
Massを著しく重くしちゃえばひとまず解決する。

オブジェクトのvelocityを確認

オブジェクトをコードで移動させていると、velocityが0になってしまっているので、速く動いているように見えてもシミュレーション上は静止している壁と同じ。
基本はaddForceで動かすべきだし、どうしてもそうは行かない場合はvelocityの値も無理やりいじる。

Collider の Material を確認

Collider の Material で反発のしやすさを変更できる。公式ドキュメントが素晴らしい。 docs.unity3d.com

Rigidbody の Collision Detection を確認

シミュレーションを軽量にするために、デフォルトだとフレーム毎に重なっているオブジェクトに対してしか衝突判定を行わない。
つまり速い速度で動いているオブジェクトはすり抜けうるということ。
↓の記事がとてもきちんと検証されていて素晴らしく参考になった。

ekulabo.com

UnityでOculus Questのコントローラに追従して、オブジェクトを打てるオブジェクトを作る

3DのPONGを作ろうとしてハマった。
コントローラに追従するオブジェクトを作るところまでは超簡単なんだけど、そのオブジェクトで別のオブジェクトを打とうとすると難しかった。
普通にやるとオブジェクトのvelocityが常に0であるため、速く振っても単に壁にあたったのと同じ反応になってしまう。

結論だけ知りたい人はラケットにプログラミング

前準備

oculus.hatenablog.com この記事の通りOculus Questの開発準備は整えておく。

コントローラに追従するオブジェクトを作る

これは超簡単。

OVRCameraRigの設置

まずはOVRCameraRigをシーンにドラッグアンドドロップする。
OVRCameraRigは、Oculus開発用のカメラで、専用の機能が色々とついているっぽい。
専用のカメラを置いたので、最初から置いてあるMain Cameraは削除しておく。 f:id:malt03:20190528232555p:plain

オブジェクトを配置

OVRCameraRigを開くと、色々なアンカーがあることがわかる。
そのうちLeftHandAnchor/LeftControllerAnchorRightHandAnchor/RightControllerAnchorがコントローラに追従するアンカー。*1

せっかくなので、Oculus Questのコントローラのモデルを置いてみて実行する。

f:id:malt03:20190528234757p:plain

f:id:malt03:20190528234637j:plain

やったぜ!

オブジェクトを打てるオブジェクトを作る

なかなか難しい

オブジェクトの配置

ラケット

さっきのコントローラのモデルは削除して、Cubeを置く。

ボール

打つためのボールを置く。

Rigidbodyを追加

物理法則に従うオブジェクトにはRigidbodyを設定する必要がある。
ボールとラケットに、メニューの [Component] > [Physics] > [Rigidbody] で追加。
今回は重力を効かせたくないのでRigidbodyUse Gravityはオフにしておく。

このまま実行しても押せるだけで打つことは出来ないし、どんどんラケット位置がズレちゃう。

f:id:malt03:20190529000705p:plain

ラケットにプログラミング

仕方ないのでラケット用にプログラミングしていく。
要するに、オブジェクトの位置がズレないようにしつつ、コントローラが動いた速度でvelocityを無理やり設定してあげれば良い。
以下のコードをRightControllerAnchorコンポーネントとして追加し、racket変数にラケットオブジェクトを設定する。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Racket : MonoBehaviour
{
    public GameObject racket;
    private Vector3 lastPosition;

    void Start()
    {
        lastPosition = transform.position;
    }

    // Update is called once per frame
    void Update()
    {
        racket.transform.localPosition = Vector3.zero;
        racket.transform.localRotation = Quaternion.identity;
        racket.GetComponent<Rigidbody>().velocity = (transform.position - lastPosition) / Time.deltaTime;
        lastPosition = transform.position;
    }
}

f:id:malt03:20190530011421p:plain

やった!

速いボールを打つ

これで止まっているボールは打てるが、速く向かってきているボールは打てない。
そのあたりは以下の記事にまとめた。

oculus.hatenablog.com

*1:HandAnchor直下にオブジェクト置いても普通に動いたんだけど、ControllerAnchorに置くのとの違いはなんなのか、分かる人は教えて下さい。

Oculus Questのスクリーンショットや録画をmacに取り込む

Oculus QuestはAndroidベースなので、Androidと同様、Android File Transferを利用することでスクリーンショットや録画を転送したり取り込んだりすることができる。
Windowsなら特に何もインストールしなくても繋げば良いっぽい。羨ましい。

スクリーンショットや録画の撮り方

これは本当に簡単で、ホームで シェア > 写真を撮る録画 を押すだけ。 アプリが中断されていれば勝手に再開されて撮られるし、何も無ければそのまま撮られる。

f:id:malt03:20190528232054j:plain

開発者モードをオフにする

この記事を閲覧している人は開発者モードをオンにしている人が多いと思うが、オフにしないとファイル転送が出来ないらしい。
マジかよ!とオフにして転送完了したが、本当かな?と思って開発者モードに戻して見たところ、普通にファイル転送出来た。
いったんオフにしてやったことがあるからかな?情報待ってます。

追記:
これ普通に無理でした。逆になんで行けてたんだろう。
開発中にスクショ取ってPCに取り込みたいとき毎度オンオフ切り替えるのしんどい。

Android File Transfer

インストール

Android File Transferからインストールできる。

転送

/Oculus/Screenshots/Oculus/VideoShots内に存在するので、ドラッグアンドドロップで簡単。 f:id:malt03:20190528114210p:plain

備考

murabitoleg.com

↑の記事が参考になった。
Oculus Questでなにか詰まったら、とりあえずOculus Goに検索ワードを変えてみると解決する可能性が高い、という知見を得た。

UnityでOculus Questのゲーム開発を開始する手順

PCとOculus Quest本体さえあれば簡単に実機でゲーム開発が出来る!
こんなに素晴らしいことがあるだろうか。

だがしかし日本語での記事がほぼ見当たらなかったので書く。
Unityを使うのはほぼ初めてなので、ツッコミどころがあったらコメントでお願いします。
この通りにやっても詰まったよ!って場合もコメントもらったら修正します。
開発機はMacです。

Unityのインストール

Unity Hub のインストール

今のUnityはUnity Hubというのを使ってインストールするのが王道っぽい。

Unity Store - Downloadからダウンロードできる。
Unity Hub自体は軽量はアプリケーションなので、インストールまですぐに終わる。

Unity 本体のインストール

Unity Hubを起動してアカウント作成とかライセンスとか色々やると↓のような画面になるので右上のインストールをクリック。 f:id:malt03:20190527145037p:plain

最新版をインストールするが、ここでトラップ!
最後のピリオドの後が0a3とか0b3のようにabが入っているのはアルファ版やベータ版である。
4f1のようにfが入っているものをインストールする。
f:id:malt03:20190527145643p:plain

モジュールのインストール

Unityの中に入れるモジュールを選択する。
よくわからないけどとりあえず開発したい人は、

にチェックを入れて次へ。
Language packsの日本語とかも入れても良いかもしれないけど、個人的にはこういう開発ツールをローカライズするとググりにくくなるのでおすすめしない。
f:id:malt03:20190527150333p:plain

Oculus QuestはAndroidベースらしく、Android開発用の設定で開発していく。
Android SDKとかが入っている場合はAndroid SDK & NDK ToolsはUnityが勝手に認識してくれるので不要。
開発ツールでVisual Studioを使わない人は不要。
なので、本当に必須なのはAndroid Build Supportだけ。

二回利用規約に同意するとインストールが始まる。
これはUnity本体をダウンロードするので結構時間かかるし、インストールも時間かかる。
途中でパスワードを聞かれるので、放置してPCから離れているとインストールが終わらないという悲しい事件が起きる。
ダウンロードは進捗がわかるが、インストールは進捗がわからないので辛い。
ディレクトリもできてるし終わってるんじゃね…?とか思うけど、信じて待つときちんと終わる。

作ったゲームをOculus Questで動かす

サンプルとかもあるんだけど、なんかうまく動かない。 1から作ってもさらりと実機ビルドまで動くので、そっちのほうが早い。

前準備

Oculus Questを開発者モードにする

スマートフォンのOculusアプリを起動し、設定 > その他の設定 > 開発者モード を開き、開発者モードをオンにする。
まだ開発者登録をしていない場合、登録するよう促されるので登録し、再度同じ操作をすることで開発者モードをオンにできる。

開発者登録はOculus開発者ダッシュボードから出来る。

f:id:malt03:20190527173219p:plain:w200f:id:malt03:20190527173223p:plain:w200f:id:malt03:20190527173228p:plain:w200

ADB Driverをインストールする?(Windows向け)

Macなのでやっておらずわからないのだが、Windowsの人はADB Driverというのをインストールしなくちゃいけないっぽい?
Device Setup - Oculus QuestのページのInstall the Oculus Go ADB Driver (Windows only)を参照。

ゲーム開発

プロジェクトの作成

ようやくゲームを作る。プロジェクトタブから新規作成。テンプレートは3Dを選択。
プロジェクト名は適当。パスはわかりやすいところに。 作成を押すとUnityが立ち上がる。テンション上がってきたー!

Unityはじめての人はUnity / Oculus 開発はじめての人向けページ - Oculus Quest / Unity もろもろを読んで見て下さい。

f:id:malt03:20190527172600p:plain

Oculus Integrationのインポート

Oculus開発をするための色々が入ったセットをインポートする。
この作業はプロジェクトを作るたびにやらなきゃいけない。

Window > Asset Store を開く。
Search for assetsに"oculus"とか入れると"Oculus Integration"というアセットがあるはずなので、インポートする。
Import unity Packageというウィンドウが開くので、全てチェックが入った状態でImportをクリック。
まずまず時間がかかる。

アップデートするか聞かれるのでYes
Unityを再起動するか聞かれるのでRestart

再起動が終わると、メニューにOculusが追加されている。やった!

Virtual Reality Supported

まずはPlayer設定で Virtual Reality Supported をオンにする。
Edit > Project Settings... を開く。
Player を開き、Androidのタブの XR Settings 内の Virtual Reality Supported にチェックを入れる。
Virtual Reality SDKsOculusを追加。 f:id:malt03:20190527171454p:plain

Vulkan Graphics API を無効にする

XR is currently not supported when using Vulkan Graphics API.と警告が出ているのでよくわからないけど解消する。
f:id:malt03:20190527171714p:plain

Minimum API Level の設定

よくわからないけど、デフォルトは16になっていて、19にしないとビルドして実機に入れるタイミングで怒られて辛い気持ちになるので、このタイミングで変えておく。 f:id:malt03:20190527172237p:plain

GameObjectを置いてみる

このままビルドしても良いんだけど、何にもないのもアレなのでなにか置いてみる。
メニューの GameObject > 3D Object > Cube を押すとシーンに立方体が追加される。 f:id:malt03:20190527174939p:plain

実機で動かす!

まずはUSBでOculus QuestとPCをつなぐ。初回接続時にOculus側で許可する必要があるはず。
メニューのFile > Build Settings... を開く。
Android を選択し、Switch Platformをクリック。結構時間かかる。 f:id:malt03:20190527222137p:plain

終わったらBuild and Runをクリックすると、実機で実行される! f:id:malt03:20190528114802j:plain