VRMモデルをカメラ目線にする
カメラ目線にしたい
Vtuberになって配信するときにカメラ目線にしたい、と言われ開発してみました。
VRMLookAtHeadスクリプトをいじる
UniVRMが入っている状態で、UnityにVRMをインポートする。
すると、VRMに自動で付いてくるVRMLookAtHeadスクリプト。
これのTargetに、VRMに見てもらいたいオブジェクトをヒエラルキーからドラッグアンドドロップすれば、完成。
今回はカメラ目線にしたいので、Vtuberの前に置いて映すカメラを選択すればOK。
動的にVRMインポートを行いカメラ目線にする
今回、VRMを動的にインポートするように開発を行った。
なので、インポート段階では、↑のTargetは何もアタッチされていない。
ので、動的にアタッチする。
// VRMを動的にインポートした際に、このスクリプトをVRMにAddComponent private void Awake() { // VRMLookAtHeadスクリプトの参照を受け取る var lookAtHead = this.gameObject.GetComponent<VRMLookAtHead>(); // Targetに目線を向けたいカメラをアタッチする lookAtHead.Target = GameObject.Find("VtuberCamera").transform; }
結果
多分カメラ目線になった、気がする。
Typescript * ReactでFuntion Componentに引数を渡す
はじめに
少しばかり仕事でReactを使う機会があります。
Reactを触った事ないし、Typescriptも触った事なくて、ドキュメントも結構少ないため、苦戦しながら書いてます。。
でもLintが厳しく指導してくるのが癖になってきて、先生に教えられているみたい。
自分へのメモ兼Typescript*Reactを使う事になってしまった人のために書きます。
Function Component
Reactのチュートリアルやって、そもそもJavascriptにClassなんてあったんだ・・・!
なんて気持ちだったのに、最新版のReactではClassComponentではなく、FunctionComponentを使っていこうな感じらしい。
親側のコンポーネントから何か値を入れたい時の書き方をメモする。
import * as React from 'react'; const App : React.FC = () => { return( <> <Child1 name="yuma1217" /> <Child2 name="yuma1217" /> </> ); } const Child1 : React.FC<{name:string}> = (prop) => { return( <div> {prop.name} </div> ); } interface IAppInterface { name : string; } const Child2 : React.FC<IAppInterface> = (prop) => { return ( <div> {prop.name} </div> ); }
二つのChildコンポーネントは同じことをしている。
Child2のInterfaceを使うやり方がTypescriptでは正しいんだと思うんだけど、最初の学習でInterface書くの少ししんどくて。。
そんなときはChild1のように書ける。
型指定しないと怒られるので、もし面倒だったら、とりあえずany
にして置けば大丈夫。(怒られないってだけで本番の開発ではしっかり型指定した方が良さそう)
UnityのGameObjectのアクティブ、非アクティブの切替え
はじめに
何かキー押したときに、GameObjectのアクティブ・非アクティブを切り替えたい時ってありますよね。
昔if文使って処理書いてたけど、もっときれいで楽な方法をどっかのリポジトリで見て使ってたけど、忘れてたので、ブログにメモとして残します。
実装
昔の実装
public GameObject target; void Update() { if (Input.GetKeyDown(KeyCode.Space)) { if (target.activeSelf) { target.SetActive(false); } else { target.SetActive(true); } } }
正直ですね。
activeかどうか判断して、切り替える。
今の実装
public GameObject target; void Update() { if (Input.GetKeyDown(KeyCode.Space)) { target.SetActive(!target.activeSelf); } }
シンプル~。笑
多分有名っぽい気がするので、みんな知ってそうですが、自分へのメモで残します。
OculusGoにアプリをデプロイできない問題
今までアプリをデプロイできていたのに、急に出来なくなってしまいました。
やってしまったこととしては、Androidの署名作業です。
署名時のパスワードを間違えているのかなんなのか分からないですが、こんなエラーが。。
CommandInvokationFailure: Unable to list keys in the keystore. Please make sure the location and password of the keystore is correct. C:\Program Files\Unity\Hub\Editor\2018.3.7f1\Editor\Data\PlaybackEngines\AndroidPlayer/Tools\OpenJDK\Windows\bin\java.exe -Xmx4096M -Dcom.android.sdkmanager.toolsdir="C:/Users/yuma1217/AppData/Local/Android/Sdk\tools" -Dfile.encoding=UTF8 -jar "C:\Program Files\Unity\Hub\Editor\2018.3.7f1\Editor\Data\PlaybackEngines\AndroidPlayer/Tools\sdktools.jar" -
パスワード系は気をつけないと。。
やったこと
本当にどうしようも無くなったので、署名をする前のプロジェクトをGitHubからクローンし直して、再度build & run.
上のエラーは消えたけど
CommandInvokationFailure: Unable to install APK to device. Please make sure the Android SDK is installed and is properly configured in the Editor. See the Console for more details. C:/Users/yuma1217/AppData/Local/Android/Sdk\platform-tools\adb.exe -s "1KWPH804MG8256" install -r "C:\Unity\Project\Apk\main.apk" stderr[ adb: failed to install C:\Unity\Project\Apk\main.apk: Failure [INSTALL_FAILED_VERSION_DOWNGRADE] ] stdout[ ]
前入れたアプリよりバージョンが下がってるよ!って怒られたよう。
Unityプロジェクトの名前を変更したから大丈夫って思っていたけど、違うよう。
初めて知ったけど、
BuildSettings > OtherSettings > Identification > PackageName
ここがアプリとしてのidになっているみたい。
UnityでAndroidアプリをビルドするには - フレームシンセシス
ここを変更した。
この際、Unity側での保存や、設定が上手くいってなかったのか分からないけど、OculusGoに同じアプリとして認識されて上手くいかなかったので、OculusGoをUSBで挿してadbコマンドを試した。(上エラー分に書いてあるコマンド)
adb install -r main.apk
一瞬でデプロイに成功。
Deploy後のエラー
Deploy自体はできるけど、エラーが2つ。2つ目のエラーは、1つ目から起因するものっぽい。
DeploymentOperationFailedException: No activity in the manifest with action MAIN and category LAUNCHER. Try launching the application manually on the device.
UnityException: Could not find any valid targets to launch on for Android
このエラーはAndroidのManifestっていう設定ファイルが何個か存在すると起こりうるよう.
Plugins > Android下にある場合は削除。
また、OculusのPluginによって、Unityのメニューからも削除が可能。
デプロイやビルド系のエラーは精神がやられますね。 誰かの助けになれれば幸いです。
OVRPlayerControllerを使ってカメラが足元にめり込む問題の解決
#oculus OVRPlayerController付けてUnityで再生すると、OVRCameraRigのLocalYpositionが-1されるの一体何?
— Yu (@yuma1217_ja) March 15, 2019
問題
Unity上でOVRPlayerControllerを使って再生すると、
VR上でのカメラ位置を表すOVRCameraRigのy座標が-1になる。
つまり、頭の位置が-1下がってしまう問題が発生。
OVRPlayerControllerにはカプセルコライダーが付いているため、コライダーの一番底くらいにカメラが配置され、足元にめり込む現象が起きて困った。
ちょっと調べてみた。
調査
まず、学びとして、OculusのForumで検索をかけてみるのが早いなって思った。
同じ問題が掲載されていた。
解決方法
OVRPlayerControllerにはUserProfileDataという設定項目がある。 ここがデフォルトではTrueになっているが、Falseに変える事で、上記の問題を無くすことが出来る。
理由
なにが起こってるかちょっと見てみると、UserProfileDataはOVRPlayerController.csのUpdateControllerメソッドで使われていて、
if (useProfileData) { // 一部抜粋 var p = CameraRig.transform.localPosition; // OVRCameraRigに付いているOVRManagerの設定項目 // デフォルトだとEyeLevelに設定 if (OVRManager.instance.trackingOriginType == OVRManager.TrackingOrigin.EyeLevel) { // この文が現象の胆だった、コメントアウトすると問題が消える p.y = OVRManager.profile.eyeHeight - (0.5f * Controller.height) + Controller.center.y; } CameraRig.transform.localPosition = p; }
CameraRigのlocalPositionを変更しているpというパラメータを追っていくと、
p.y = OVRManager.profile.eyeHeight - (0.5f * Controller.height) + Controller.center.y;
ここでy座標をがっつりいじってる。
デバッグをしてみると、
常にこの値が表示された。上の式に代入してみれば-1なので、問題はここだったんだろう。
OVRManager.profileを見てみると
Gets the current profile, which contains information about the user's settings and body dimensions.
Oculusユーザーの身体情報を取って使うデータのよう。
Oculusを始める際、身長などを入れたと思うけど、そのデータを使って、見え方を最適化できるものっぽい。
それがUnity側には存在しないから、今回のような問題が起こったのかなぁって思った。
まとめ
Unity側では常にUserProfileDataの項目は切っておいて良さそう。
OculusPlatformのSettingについて
OculusPlatformについて
この記事はNotionというアプリを使って書いたものをコピーしています。
一押しのMarkdownクラウドメモサービスです。是非使ってみて欲しいです!!
前回
OculusRoomsみたいなアプリを作りたくて、OculusPlatformを使ってみようとなったいきさつを書きました。
OculusRoomみたいなアプリを作りたい - 海外で生活したいXRエンジニアのブログ
今回はOculuPlatformのことはじめを書いていこうと思います。
概要
Introduction to the Platform SDK
The Platform SDK contains features that you can use to create engaging and social game experiences.
ドキュメントによると、OculusPlatformにはソーシャルゲームを作る事が出来る機能が含まれているようです。
使ってみての私の理解は、 OculusPlatformはBaaS(Backend as a Service)だと思っています。
本来サーバーが必要な部分をOculus側が用意してくれていて、機能ごとにAPIが用意されていて、
開発者は必要なAPIを利用するコードを書くだけで、ソーシャルVRを実現できる。
そのAPIを叩きやすくしたものが、OculusPlatformSDK。という認識をしています。
OculusPlatformの機能
OculusGo、特にOculus Rooms をイメージすると分かりやすいかもです。
ユーザーはアプリ内で写真を撮りFacebookに投稿することが出来る
ユーザーはアプリ内で友人を招待し一緒にゲームをプレイできる
ユーザーはアプリ内で音声通話をすることが出来る
ユーザーはアプリ内で世界中のユーザーとマッチングし一緒に遊ぶことが出来る(Dead and Buriedや、Bigscreen、Oculus Venueをイメージすると良いかもです)
これ以外にもOculusが用意してくれている機能をふんだんに使えます!
もちろん、OculusPlatformの機能を使用しなくても出来る機能はあると思います。
OculusPlatformの良いところ
通信をする相手を指定する際にOculusアカウントを簡単に使えるのは便利です。
多分他のネットワークライブラリなどを使う際には、通信する相手を指定するのはちょっと面倒、か、ユーザーにIDを打たせるなどのUIを与えてしまいそうな気がしました。
OculusPlatformの注意点
Oculusデバイスのみしか使えません。(OculusRift, GearVR, OculusGo, OculusQuest...)
Oculusデバイスのみを考えれば良くなるので私は良いな。と思ってました。
が、既存のマルチプレイのゲームをVR化したい、なんて時は使いづらいというかいらないですよね。
でも、そんな人でもOculusStoreに出したいなら、
絶対にやらなきゃいけない事があります。
Entitlement Checkは必須
https://developer.oculus.com/documentation/platform/latest/concepts/pgsg-unity-gsg/
Verifying that the user is entitled to your app is required to sell an app on the Oculus Store.
OculusStoreにアプリを売り出すには、提出するアプリのユーザーが、そのアプリを使う・持つ資格があるか(entitled)を検証する必要があるそうです。
なので、OculusPlatformの機能を使わなくとも、Storeに出したいなら EntitlementCheckは必須です。
OculusPlatform使ってみる
最初のセットアップは今回ざっくり書きます。
まずはOculusのOculus Developer Dashboardからアプリを作成します。
作った際のappIDというものを控えておく。
参考
https://developer.oculus.com/distribute/latest/concepts/publish-create-app/
↑のCreating an App Page参照
次に、Unityのセットアップをします。
UnityのAssetStoreからOculusIntegrationをインポート。
Unityの上のメニューから、OculusDashboardで作ったアプリのappIDを記述する。
参考
https://developer.oculus.com/documentation/platform/latest/concepts/pgsg-unity-gsg/
↑のConfigure Your Development Environment
かなり飛ばしましたが、これでOculusPlatformを使う下地は整いました。
EntitlementCheck
何か一つGameObjectを作成し、Startなどに下のメソッドを書きましょう。
using Oculus.Platform;
Start()
{
// Oculus.Platform.Entitlementsのメソッドを呼ぶ
Entitlements.IsUserEntitledToApplication().OnComplete(IsEntitledCallback);
}
Entitlements.IsUserEntitledToApplicationで、↑で設定したappIDに紐づいたアプリに資格があるかを検証します。
そして検証した結果が、IsEntitledCallback
にMessageとして渡されます。
このCallbackは自分で記述する必要があります。
void IsEntitledCallback(Message msg)
{
if (msg.IsError)
{
// EntitlementCheckに失敗した場合、msg.IsErrorがTrueになる
// ①
return;
}
// EntitlementCheckが成功
// ②
}
1番について。
このエラーをハンドリングするようドキュメントにはあります。
また、アプリを終了するよう促す文言もありました。
You may not allow the user to proceed in your app after a failed entitlement check.
Sampleシーンでは、メソッドを呼び、そこでUnityEngine.Application.Quit()を実行し、アプリを強制終了していました。
2番について。
OculusPlatformを使って実行したいような処理を記述します。
例えば、アプリを使っているユーザーの情報を取得するメソッド
Users.GetLoggedInUser().OnComplete(GetLoggedInUserCallback);
ここのCallbackは割愛しますが、さっきと同じようにMessageをハンドルする処理を書くのみです。
次回
今回はここまでとします。
次回は、私はこれでも失敗したので、OculusDashboardの設定や、Rooms機能について書いていこうと思います。
概要
この記事では、OculusPlatformの設定方法について説明します。
OculusPlatformについて知りたい場合は、前回の投稿を是非読んでみてください。
なお、今回はsuinさんのこちらの記事を参考にして
https://twitter.com/suin/status/976704532163039232
HackMDを使って英語で書いてみてDev.toにPostしてから、記事を書いてみました。凄い画期的な方法だなと思ったので是非!(Google翻訳の日本語になってるので少々おかしいかも)
dev.to
設定
OculusDashBoard
アプリIDを取得できるので、メモしてください。
ここからは、OculusPlatformでマルチプレイ機能をテストするならば、読んでみてください。
テストユーザーを追加します。
左側のサイドバーで、[管理]> [ユーザー名]> [設定]> [ユーザーのテスト]の順に選択します。
テストユーザーを追加します。パスワードと暗証番号を入力してください。送信します。
後でパスワードを使用するのでメモ。
テストユーザーが追加されました、Oculus IDとメールアドレスを書き留めてください。
(重要)作成したテストユーザーを開発者として登録します。
これを行わないと、テストユーザーに作成したアプリの資格が付きません。
設定 > メンバーを選択してから、「開発者を追加」を選択します。
作成したテストユーザーのOculus IDを入力し、追加を選択します。
これでテストユーザーが登録されました。
OculusPlatformの設定は完了です。
UnitySetting
UnityのAssetStoreで、Oculus Integrationを入力してインポートします。
トップメニューで、OculuPlatform> EditSettingsを選択。
アプリIDを入力します。さっき取得したOculusDashBoardでの設定時の16桁の数字です。
OculusDashBoardでOculusRift Appsを作成した場合は、OculusRiftAppId行にappIDを入力します。
OculusDashBoardでGearVR / OculusGoアプリを作成した場合は、GearVRアプリID行に入力します。
次に、appId設定の下のUnityIditorSettingsを開き、テストユーザーのアドレスとパスワードを入力し、[ログイン]をクリックします。
テストユーザーを使用しない場合は、自分のOculusアカウントのメールアドレスとパスワードを使用してください。
または
Use Stand Platform
チェックボックスをオフにします。チェックマークをはずすと、UnityはOculusApplicationを見つけて、アプリケーションにログインしているOculusユーザーの情報を使います。設定が完了しました。
次回は、実際にUnityでのOculusPlatformAPIの使い方を書きます。