- 投稿日:2020-02-19T16:36:43+09:00
Azure × MR開発準備(HoloLens2、MRTKv2.3.0、Unity2018.4.2f1)
こちらはKumamoto HoloLens ミートアップ vol.5のAzure × HoloLens2の開発準備を整える記事になります。当日、開発を楽しむために、下記の事前準備を行ってください。実機なしでもできます。
開発環境
・Windows 10
・Visual Studio 2019 Community
・Windows 10 SDK (10.0.18362.0)
・Unity Hub
・Unity 2018.4.2f1
・Azure アカウント準備
Visual Studio 2019 ダウンロードからCommunityをインストールしてください。
Windows 10 SDKからWindows 10 SDK (10.0.18362.0)をインストールしてください。
Microsoft Mixed Reality Toolkit v2.3.0からunitypackageをダウンロードしてください。
・Microsoft.MixedReality.Toolkit.Unity.Examples.2.3.0.unitypackage
・Microsoft.MixedReality.Toolkit.Unity.Extensions.2.3.0.unitypackage
・Microsoft.MixedReality.Toolkit.Unity.Foundation.2.3.0.unitypackage
・Microsoft.MixedReality.Toolkit.Unity.Tools.2.3.0.unitypackageUnity をダウンロードからUnity Hubをインストールしてください。
Unity ダウンロード アーカイブからUnity 2018.4.2 をUnity Hubからインストールしてください。
Azure の無料アカウントを今すぐ作成しましょうからAzureアカウントを作成してください。Azure Portalにサインインできる状態にしておくこと。
確認事項
Unity Hubを開いて、Unity 2018.4.2f1でプロジェクトを新規作成します。
同様に、Tools、Extensions、Examplesをインポートしてください。
MRTK Project Configuratorが表示されたらApplyをクリックしてください。
TMP Importerが表示されたら、Import TMP Essentialsをクリック。インポート後に、Import TMP Examples & Extras もクリックしてください。
スタートボタンを押して、動作確認してください。q,w,e,a,s,dキーで移動、ShiftキーでHandの表示、Rayを物体に合わせてクリックでつかめます。
Azure×MR開発準備中 #HoloLens2 #MRTK pic.twitter.com/KIsTL7z0eG
— 藤本賢志(ガチ本)@HoloLens2 Ready (@sotongshi) February 19, 2020App Open Scenesをクリックし、HandInteractionExamplesシーンが選択されていることを確認、PlatformはUniversal Windows Platformを選択し、Switch Platformをクリックしてください。
Player Settingsを開き、Inspectorビューにある設定を確認します。
BuildSettingsにもどり、Buildをクリックします。
ビルドが完了したら、作成したHolo2フォルダの中のMRTK230.slnをVisual Studio 2019で開いてください。
Release、ARMに設定し、Ctrl+Shift+Bを押して、ビルドしてください。
ビルドが完了したら、HoloLens2にデプロイする準備が完了です。
わからないことがあれば @sotongshi までDMください。
3/7のKumamoto HoloLens ミートアップ vol.5はみんなで一日開発しましょう!
- 投稿日:2020-02-19T14:47:40+09:00
【Unity×VR】個人的ベストプラクティス & ワークアラウンド集【2019年度版】
思い出したとき or 気が向いたときに更新
◥◤ 環境構築@ハードウェア
開発用PCおよびVR機器等は,2セット用意すると良い.故障時のスペアとして,また,検証実験を平行して行う際に良い.そして何よりも,在宅作業用と学校作業用をそれぞれ用意することで,持ち運びの労力が大幅に省けるというメリットがある.
大量のデータを扱う上に,技術情報を調べながらの開発だと,ブラウザが開くタブが100を超えることも多々あるため,メモリを盛っておく.休止モードはメモリの中身をストレージに書き込むため,ストレージの空き容量も十分確保しておく.バックアップ用のストレージも忘れずに.
周辺機器もきちんと揃えておこう.まず外付けのPCクーラーは必須である.VR用PCだからと油断しているとOSごと焦げる.また,PCの画面は最低でも2枚ほしい.大量のログやエラーをさばくうえで,画面の狭さは致命傷となり得る.キーボードとマウスは無線のものが良い.設置位置が自由であれば,長時間の作業でも,肩・背中・目などへの疲労を軽減できる.
機器が上手く動かない場合,ソフトウェアの設定ミス等だけでなく,ハードウェアの初期不良,経年劣化も疑うと良い.コネクターを純正品から別の既製品に変えたら正常に動作した,ということもあった.コネクターを買い足す場合には,端子の両端の規格を確認しておこう.普段見ないような組み合わせになっていることもある.
◥◤ 環境構築@ソフトウェア
VR機器との連携
- 今回の構成は,UnityでVR環境を構築し,SteamVRを経由してOpenXR規格で,VR機器と連携,とした.実装開始時点で,容易にマルチデバイス対応可能な方法はこれくらいしかなかったが,現時点ではそうでもない.構成は適宜検討されよ.
エディタのカスタマイズ
- Unityエディタは画面構成をカスタマイズできる.著者はディスプレイが1枚なら図 19上のように,ディスプレイが2枚なら図 19下のようにしている.ポイントはヒエラルキーウィンドウとインスペクターウィンドウを隣接させていること,そしてコンソールウィンドウができるだけよく見えるようにしているところである.特に,コンソールウィンドウは様々なログやエラーが表示される,「ヒントウィンドウ」でもある.常にその全体が視界に入るようにしておけば,問題解決のスピードも上がる.スペースに余裕があるのなら,図 19下のように,セカンドディスプレイいっぱいに表示すると良い.
そのほか
- GPU周りは意外によく不調になる.とりあえず公式のツールを使うなどして,ドライバー等のアップデートをしておく.なお,Unityエディタのアップデートは.少し慎重になった方が良い.まれに仕様への破壊的変更が行われるため,作業中のプロジェクトをフォルダごと複製したものを,新しいバージョンで開いて,一通りの作業が問題なくできるか検証すべきかもしれない.特に,Previewの機能は注意されたし.筆者の環境ではGPUを用いたベイクが2019.3から機能不全になっている.
◥◤ レベルデザイン
レベルデザインとは
Prefab
- NestedとVariant
- どうネストする?
ギズモの表示
ピボットエディタ拡張の利用
- ProGrids
- 自作拡張,ショートカット
小話
- トイレで寿命が縮んだ話
命名規則とヒエラルキーウィンドウによる検索絞り込み
◥◤ ライティングそしてベイク
各種ベイクの設定方法と注意点
設定
static
影投影,クリッピング
アリアライト,えみっしぶ◥◤ スクリプティング
ライフサイクル
物理挙動・衝突/接触判定
- ライフサイクルを踏まえる
- レイヤーを分ける
SteamVR Plugin周りの扱い
小話
- Staticの怪
VRにもテストを
- Prefabで元に戻せる.あるいはシーンを分けて
◥◤ VR体験実施時の配慮など
- 投稿日:2020-02-19T14:28:19+09:00
[Unity]オーディオクリップ設定による発生問題
広告 インディーズチームでAzraelという音ゲーを出しています。現在はiOSバージョンしかありません。 Androidはできる次第リンク先を入れます。 有料ですが、音ゲーにご興味のある方是非遊んでみてください!。 TwitterAzrael公式 iOS: 問題1アプリ起動が遅い 原因 PreloadAudioDataがオンになってるかを確認。 オンになってると、アプリ起動時シーンに入るタイミングで、オンになってるすべてのオーディオのロードに入るため、起動が遅くなる現象が起きます。 問題2アプリ容量が大きい 原因 LoadTypeがCompressedInMemoryになってるかを確認。 アプリパッケージ作った時容量が大量に増えるのが現象です。 問題3音再生時にフレームが落ちる 原因 PreloadAudioDataがオフになってるかを確認。 オフになってると、音再生時にcpu負荷がかかりますので、フレームが落ちます。なので、フレーム保持したいアプリとかは事前にローディングタイミングでLoadAudioData()で読み込み処理を追加する必要があります。 汎用まとめ 大体のロードタイプ LoadType=DecompressOnLoad 大きい過ぎて展開できないファイルのみ LoadType=CompressedInMemory 時間が長いファイルなど(例:BGM) LoadType=Streaming CompressionFormat Android : Vorbis iOS : Vorbisでも問題ないと思いますが、参考からMP3が最適の様です インポート時自動設定拡張 using UnityEngine; using UnityEditor; public class UnityAssetImporter : AssetPostprocessor { /// <summary> /// 音源データインポートした後呼ばれる /// </summary> private void OnPostprocessAudio(AudioClip clip) { var audioimporter = (AudioImporter)assetImporter; audioimporter.Setting("iOS", AudioCompressionFormat.MP3, clip.length); audioimporter.Setting("Android", AudioCompressionFormat.Vorbis, clip.length); audioimporter.preloadAudioData = false; } } public static class ImpoterUtility { public static void Setting(this AudioImporter importer, string platform, AudioCompressionFormat acformat, float length) { var setting = importer.GetOverrideSampleSettings(platform); setting.compressionFormat = acformat; //適当に時間でロードタイプ決める if (length >= 5f) setting.loadType = AudioClipLoadType.Streaming; else setting.loadType = AudioClipLoadType.DecompressOnLoad; importer.SetOverrideSampleSettings(platform, setting); } } 注意:手動でaudioclipインスペクター設定更新した時、拡張ファイル一回走りますので注意
- 投稿日:2020-02-19T14:28:19+09:00
[Unity]オーディオクリップ設定と注意
広告 インディーズチームでAzraelという音ゲーを出しています。現在はiOSバージョンのみです。 Androidはできる次第リンク先を入れます。 有料ですが、音ゲーにご興味のある方是非遊んでみてください!。 TwitterAzrael公式 iOS: 問題1アプリ起動が遅い 原因 PreloadAudioDataがオンになってるかを確認。 オンになってると、アプリ起動時シーンに入るタイミングで、オンになってるすべてのオーディオのロードに入るため、起動が遅くなる現象が起きます。 問題2アプリ容量が大きい 原因 LoadTypeがCompressedInMemoryになってるかを確認。 アプリパッケージ作った時容量が大量に増えるのが現象です。 問題3音再生時にフレームが落ちる 原因 PreloadAudioDataがオフになってるかを確認。 オフになってると、音再生時にcpu負荷がかかりますので、フレームが落ちます。なので、フレーム保持したいアプリとかは事前にローディングタイミングでLoadAudioData()で読み込み処理を追加する必要があります。 汎用まとめ 大体のロードタイプ LoadType=DecompressOnLoad 大きい過ぎて展開できないファイルのみ LoadType=CompressedInMemory 時間が長いファイルなど(例:BGM) LoadType=Streaming CompressionFormat Android : Vorbis iOS : Vorbisでも問題ないと思いますが、参考からMP3が最適の様です インポート時自動設定拡張 using UnityEngine; using UnityEditor; public class UnityAssetImporter : AssetPostprocessor { /// <summary> /// 音源データインポートした後呼ばれる /// </summary> private void OnPostprocessAudio(AudioClip clip) { var audioimporter = (AudioImporter)assetImporter; audioimporter.Setting("iOS", AudioCompressionFormat.MP3, clip.length); audioimporter.Setting("Android", AudioCompressionFormat.Vorbis, clip.length); audioimporter.preloadAudioData = false; } } public static class ImpoterUtility { public static void Setting(this AudioImporter importer, string platform, AudioCompressionFormat acformat, float length) { var setting = importer.GetOverrideSampleSettings(platform); setting.compressionFormat = acformat; //適当に時間でロードタイプ決める if (length >= 5f) setting.loadType = AudioClipLoadType.Streaming; else setting.loadType = AudioClipLoadType.DecompressOnLoad; importer.SetOverrideSampleSettings(platform, setting); } } 注意:手動でaudioclipインスペクター設定更新した時、拡張ファイル一回走りますので注意
- 投稿日:2020-02-19T03:43:19+09:00
[Unity][Fee]セーブデータを暗号化する
はじめに
自作ライブラリ開発日記です。
https://github.com/bluebackblue/fee_coreunitypackage
https://github.com/bluebackblue/fee_core/releasesデータ
public class Data { int money; }セーブ
コード
public static System.Collections.IEnumerator Save(Data a_data) { string t_pass = "asdf1234"; string t_salt = Fee.MD5.MD5.CalcMD5(t_pass); string t_filename = "savedata"; byte t_version = 0x01; //1、ObjectToJsonString string t_jsonstring = Fee.JsonItem.Convert.ObjectToJsonString<Data>(a_data); if(t_jsonstring == null){ yield break; } //2、StringToUtf8Binary.Convert byte[] t_plane_binary = Fee.StringConvert.StringToUtf8Binary.Convert(t_jsonstring); if(t_plane_binary == null){ yield break; } //3.RequestEncryptPass byte[] t_binary_encrypt = null; { Fee.Crypt.Item t_crypt_item = Fee.Crypt.Crypt.GetInstance().RequestEncryptPass(t_plane_binary,0,t_plane_binary.Length,t_pass,t_salt); while(t_crypt_item.IsBusy() == true){ yield return null; } t_binary_encrypt = t_crypt_item.GetResultBinary(); if(t_binary_encrypt == null){ yield break; } } //4、System.Array.Copy byte[] t_binary_encrypt_and_version = new byte[t_binary_encrypt.Length + 1]; { System.Array.Copy(t_binary_encrypt,0,t_binary_encrypt_and_version,1,t_binary_encrypt.Length); t_binary_encrypt_and_version[0] = t_version; } //5、RequestSaveBinaryFile { Fee.File.Item t_file_item = Fee.File.File.GetInstance().RequestSaveBinaryFile(Fee.File.File.SaveRequestType.SaveLocalBinaryFile,new Fee.File.Path(t_filename),t_binary_encrypt_and_version); while(t_file_item.IsBusy() == true){ yield return null; } if(t_file_item.GetResultType() != Fee.File.Item.ResultType.SaveEnd){ yield break; } } //成功。 yield break; }1、ObjectToJsonString
インスタンスをJSON文字列化
{"money":123l}2、StringToUtf8Binary.Convert
JSON文字列をバイト配列化
[ 0] 0x7b System.Byte [ 1] 0x22 System.Byte [ 2] 0x6d System.Byte [ 3] 0x6f System.Byte [ 4] 0x6e System.Byte [ 5] 0x65 System.Byte [ 6] 0x79 System.Byte [ 7] 0x22 System.Byte [ 8] 0x3a System.Byte [ 9] 0x31 System.Byte [10] 0x32 System.Byte [11] 0x33 System.Byte [12] 0x6c System.Byte [13] 0x7d System.Byte3.RequestEncryptPass
バイト配列を暗号化
[ 0] 0xa2 System.Byte [ 1] 0xdd System.Byte [ 2] 0xcb System.Byte [ 3] 0xd9 System.Byte [ 4] 0xd2 System.Byte [ 5] 0xec System.Byte [ 6] 0x7c System.Byte [ 7] 0xcc System.Byte [ 8] 0x9e System.Byte [ 9] 0xd6 System.Byte [10] 0xd7 System.Byte [11] 0xf5 System.Byte [12] 0xd3 System.Byte [13] 0x36 System.Byte [14] 0x3b System.Byte [15] 0x39 System.Byte4、System.Array.Copy
配列の0番目にバーションを設定
配列の1番目以降は暗号化したバイト配列[ 0] 0x01 System.Byte [ 1] 0xa2 System.Byte [ 2] 0xdd System.Byte [ 3] 0xcb System.Byte [ 4] 0xd9 System.Byte [ 5] 0xd2 System.Byte [ 6] 0xec System.Byte [ 7] 0x7c System.Byte [ 8] 0xcc System.Byte [ 9] 0x9e System.Byte [10] 0xd6 System.Byte [11] 0xd7 System.Byte [12] 0xf5 System.Byte [13] 0xd3 System.Byte [14] 0x36 System.Byte [15] 0x3b System.Byte [16] 0x39 System.Byte5、RequestSaveBinaryFile
Application.persistentDataPathにファイルをセーブ
ロード
コード
public static System.Collections.IEnumerator Load(Data a_data) { string t_pass = "asdf1234"; string t_salt = Fee.MD5.MD5.CalcMD5(t_pass); string t_filename = "savedata"; byte t_version = 0x01; //1、RequestLoad byte[] t_binary_encrypt_and_version = null; { Fee.File.Item t_file_item = Fee.File.File.GetInstance().RequestLoad(Fee.File.File.LoadRequestType.LoadLocalBinaryFile,new Fee.File.Path(t_filename)); while(t_file_item.IsBusy() == true){ yield return null; } t_binary_encrypt_and_version = t_file_item.GetResultAssetBinary(); if(t_binary_encrypt_and_version == null){ yield break; } if(t_binary_encrypt_and_version[0] != t_version){ yield break; } } //2、RequestDecryptPass byte[] t_plane_binary = null; { Fee.Crypt.Item t_crypt_item = Fee.Crypt.Crypt.GetInstance().RequestDecryptPass(t_binary_encrypt_and_version,1,t_binary_encrypt_and_version.Length - 1,t_pass,t_salt); while(t_crypt_item.IsBusy() == true){ yield return null; } t_plane_binary = t_crypt_item.GetResultBinary(); if(t_plane_binary == null){ yield break; } } //3、Utf8BinaryToString.Convert string t_jsonstring = Fee.StringConvert.Utf8BinaryToString.Convert(t_plane_binary,0,t_plane_binary.Length); if(t_jsonstring == null){ yield break; } //4、JsonStringToObject Data t_data = Fee.JsonItem.Convert.JsonStringToObject<Data>(t_jsonstring); if(t_data == null){ yield break; } //成功。 a_data.money = t_data.money; yield break; }1、RequestLoad
Application.persistentDataPathのファイルをロード
ロードしたバイト配列の0番目はバージョンが入っているはず[ 0] 0x01 System.Byte [ 1] 0xa2 System.Byte [ 2] 0xdd System.Byte [ 3] 0xcb System.Byte [ 4] 0xd9 System.Byte [ 5] 0xd2 System.Byte [ 6] 0xec System.Byte [ 7] 0x7c System.Byte [ 8] 0xcc System.Byte [ 9] 0x9e System.Byte [10] 0xd6 System.Byte [11] 0xd7 System.Byte [12] 0xf5 System.Byte [13] 0xd3 System.Byte [14] 0x36 System.Byte [15] 0x3b System.Byte [16] 0x39 System.Byte2、RequestDecryptPass
ロードしたバイト配列の1番目以降を複合化
[ 0] 0x7b System.Byte [ 1] 0x22 System.Byte [ 2] 0x6d System.Byte [ 3] 0x6f System.Byte [ 4] 0x6e System.Byte [ 5] 0x65 System.Byte [ 6] 0x79 System.Byte [ 7] 0x22 System.Byte [ 8] 0x3a System.Byte [ 9] 0x31 System.Byte [10] 0x32 System.Byte [11] 0x33 System.Byte [12] 0x6c System.Byte [13] 0x7d System.Byte3、Utf8BinaryToString.Convert
複合化したバイト配列をJSON文字列化
{"money":123l}4、JsonStringToObject
JSON文字列からインスタンスを作成