- 投稿日:2020-01-01T23:57:00+09:00
[Unity][Fee]インプトマネージャでパッド対応
はじめに
自作ライブラリ開発日記です。
https://github.com/bluebackblue/fee_coreなにが問題なのか
インプットマネージャは「パッドの数」x「パッドの種類」x「ボタンの数」だけ設定をする必要がある。
解決策
必要最低限の全パターンを一括で登録する「InitializeInputManager」を作った。
「pad_0」は0番目のパッド。
「pad_1」は1番目のパッド。
「type_p」はPSコントローラ対応。
「type_x」はXBOXコントローラ対応。
「type_a」はAndroidでのXBOXコントローラ対応。コード
/** 初期設定。 */ public void Initialize() { //0番目のパッドにXBOXコントローラが接続してあることが前提。 Fee.Input.Pad.GetInstance().pad_status[0].pad_type = Fee.Input.Pad_InputManagerItemName.PadType.Type_X; //1番目のパッドにPSコントローラが接続してあることが前提。 Fee.Input.Pad.GetInstance().pad_status[1].pad_type = Fee.Input.Pad_InputManagerItemName.PadType.Type_P; } /** 更新。 */ public void Main() { //0番目のパッドのデジタルボタン左が押された。 if(Fee.Input.Pad.GetInstance().pad_status[0].left.down == true){ UnityEngine.Debug.Log("pad 0 left down"); } //1番目のパッドのデジタルボタン左が押された。 if(Fee.Input.Pad.GetInstance().pad_status[1].left.down == true){ UnityEngine.Debug.Log("pad 1 left down"); } }動作確認
InputSystemと違いXBOXコントローラ、PSコントローラのどちらが接続されているのかの判別ができない。
WebGL 2019.2.17f1(WindowsChromeで実行)
XBOXコントローラ、PSコントローラ:どちらもType_Xとして動作する。
Standalone 2019.2.17f1(Windowsで実行)
XBOXコントローラ:Type_Xとして動作する。
PSコントローラ:Type_Pとして動作する。Android 2019.2.17f1
XBOXコントローラ:USB接続で認識する。Type_Aとして動作する。
PSコントローラ:ブルートゥース接続で認識するがType_XでもType_Pでもない。かなり不安定。
複数パッド対応は未確認。
- 投稿日:2020-01-01T21:30:25+09:00
【Unity】iosデバッグ時のbuild設定 ios実機/Simulator
- 投稿日:2020-01-01T20:55:41+09:00
【Unity】DoTweenを使ってUIを上下ループさせて目立たせる
コード
UIPointer.csusing UnityEngine; using DG.Tweening; using DG.Tweening.Core; using DG.Tweening.Plugins.Options; public class UIPointer : MonoBehaviour { [SerializeField] private float _durationSeconds = 0.2f; private float _initY = 0; private float _endY = 0; [SerializeField] private float _moveY = 3f; private TweenerCore<Vector3, Vector3, VectorOptions> _tweener; public void InitDisplay(Vector3 position) { // 指定した位置に移動する transform.position = position; // 初期化 _initY = transform.position.y; _endY = _initY - _moveY; // 表示する gameObject.SetActive(true); _tweener = transform .DOMoveY(_endY, duration: _durationSeconds) .SetEase(Ease.InCubic) .SetLoops(-1, LoopType.Yoyo) .Play(); } private void OnDisable() { _tweener.Kill(); } [ContextMenu("TestDisplay")] void TestDisplay() { InitDisplay(Vector3.zero); } }エディタ
デモ
ようやく動きました。ありがとうございます! pic.twitter.com/vuSCWNEBgE
— アズマゴロー@放置ゲーハクスラ開発中 (@azumagoro) January 1, 2020参考
余談
地味にコピペですぐ使えるコードが見つからなかったので記事にしました。
- 投稿日:2020-01-01T20:38:53+09:00
Unity Cloud Buildで自動ビルド環境を手に入れる
はじめに
皆様明けましておめでとうございます!
本業はフロントエンドエンジニアですが、趣味ではサークルでゲームを作ったりしてまして、最近はこんなゲームを作ったりしてました。
このゲームは私(プランニング、プログラミング担当)ともう一人(グラフィック、サウンド担当)で作ったんですが、開発時に修正チェックなどでお互いの環境でビルドして動作確認するのが煩雑だなーと感じていました。
次回作を作るにあたり、このめんどくささを解消したいなと考え、調べた結果、Unity公式がUnity Cloud Buildというサービスを提供しており、今やりたいこととマッチしていたので実際に試してみました実現したいこと
- GitHubで管理しているリポジトリに変更が加わる
- 自動的にビルドが行われる
- ビルド完了通知がSlackに送られる(ビルド生成物のダウンロードもできる)
Unity Team Advanced
Unity Cloud Buildの公式ページはこちらです。
公式ページを見ればわかる通り今回実現したいことを実現するためにはUnity Team Advancedを手に入れている必要があります。
ひと月あたり$9~(チーム人数によって変動)かかりますが、1か月は無料で使うことができるので、試してみて快適だなと感じたら課金しましょう。
Cloud Buildが使える以外にもBasicプランに比べていろいろパワーアップしています!Unity Cloud Build
プロジェクト作成
Unity Team Advancedアカウントを作ってUnity Cloud Buildにログインするとこんな管理画面にアクセスできます
(私はすでにプロジェクトを作っているので一つだけプロジェクトがありますが無視してください)
まずプロジェクトを作りましょう
右上の「CREATE NEW PROJECT」という青いボタンを押します。
任意のプロジェクト名を入力し、先ほど作成したUnity Team Advancedアカウントを組織で選択します。作成ボタンを押下すると以下のようなプロジェクト管理画面に遷移します。
GitHub連携
GitHubと連携して、ビルドを自動化しましょう。
左のメニューから「Cloud Build」 → 「Config」と進みます
ここから「Souce Control Setting」をEditします。
連携できるサービスが表示されます。
現状GitHub、Bitbucket、GitLabが選択できます。
ここでは「GitHub」を選択します。GitHub側の認証を求めるので許可すると、以下のようなリポジトリを選択する画面に遷移します。
ここでビルドしたいUnityプロジェクトのリポジトリを選択して、「NEXT: TARGET SETUP」を押下します。
すると元のConfig画面に戻るのでSource Control SettingsのところにGitHubのSSH Keyが設定されているのを確認しつつ「SETUP NEW TARGET」を押下します
どのプラットフォーム用のビルドをするか聞かれるのでお好きなものを選択してください。次の画面ではビルドの設定を行うことができます。
設定できる項目としては以下の通りです
項目 内容 ラベル ラベル名称。実行ファイル名になるみたいです(Windows 64bitで確認)。アルファベットとハイフンとスペースのみ使用可能 branch ビルド対象Branch Project Subfolder rootフォルダ以外のところに資産が置いてある場合はここで指定します Auto Detect Version ONにするとプロジェクト設定(ProjectSettings/ProjectVersion.txt)からUnityバージョンを自動検出するかどうか Unity Version Auto Detect VersionがOFFの場合はUnityバージョンを明示的に指定します Build with closest version Auto Detect VersionがONの場合で、検出したUnityバージョンがCloud Build上で使えない場合は、最も近いバージョンを使うことを許可するか Auto-build リポジトリに変更があった場合に自動でビルドするかどうか ビルドするプロジェクトや好みに応じてお好きに設定してください。
(今回やりたいことをやるためにはAuto-buildのONは必須です)設定が終わったら「NEXT」を押下しましょう。
するとこんな感じでビルドヒストリーを見られる画面に遷移します。
この画面で右上の「BUILD DEFAULT~」という青いボタンを押せば、手動ビルドすることも可能です。
これでリポジトリに変更が加われば自動的にビルドが行われるようになりました!
Slack連携
ただこれではビルドは自動で行ってくれるのですが、いつ完了するのかは都度この画面で確認する必要があって面倒です(今回作ったゲームで試したところビルド時間はそこそこかかった)。
終わったら教えてくれるのが理想ですね。
現状平時の連絡はSlackで行っているので、終わったらSlackに通知してくれるようにしましょう。
連携の口はCloud Buildが提供してくれているので、設定を行うだけで連携完了します。
左のメニューから「Settings」→「Integrations」を選択します。
「NEW INTEGRATION」を押下して連携設定を新規作成しましょう。
選べるサービスもいくつかありますが、今回はSlackを選択します。
(最近流行ってるコミュニケーションツールは大体揃ってる印象ですね)
次の画面ではどのアクションをSlack側に通知するかを選べます。
この辺りは好みに応じてお好きにどうぞ。
(個人的にはCloud Build全てとCollaborateを選択していますが、とりあえず全部チェックしといて邪魔だったら消すでいいとも思います)
設定完了後、「NEXT」を押下するとUnity Serviceに許可する情報と通知が投稿されるチャンネルを指定すれば連携完了です。連携完了後
連携完了後に指定したリポジトリのブランチに変更を加えると以下のような形でSlackに通知が投稿されます!
Downloadリンクをクリックすればビルドされたゲームの実行フォルダがダウンロードできます
おわりに
こんなことしてるから肝心のゲーム開発本体が進まない説
- 投稿日:2020-01-01T19:52:18+09:00
【Unity Editor拡張 with Odin】 Addressable AssetReferenceのプレビューを表示する
環境
Unity 2019.2.17f1
Addressable 1.5
Odin Inspector 2.1.8 (有料プラグイン)
AssetReferenceって何を参照しているのか分かりにくい。。。
名前を設定している場合はまだ分かりやすいですが、フォルダを指定している場合フルパスが表示されるのでかなり分かり辛いです。それを有料プラグインのOdinを使って解決してみようと思います。
まずは Before / After
Before...
After !!!!
だいぶ分かりやすくなりましたね。
Prefab名をクリックするとProject内のPrefabをハイライトしてくれます。Code
OdinWithAddressableAssetReference.csusing System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.AddressableAssets; using Sirenix.OdinInspector; #if UNITY_EDITOR using UnityEditor; using UnityEditor.AddressableAssets; using UnityEditor.AddressableAssets.Settings; #endif [CreateAssetMenu(menuName = "Sample/OdinWithAddressableAssetReference")] public sealed class OdinWithAddressableAssetReference : ScriptableObject { [SerializeField, HideInInspector] AssetReferenceGameObject references; public AssetReferenceGameObject References => references; #region Inspector #if UNITY_EDITOR #pragma warning disable 0649 [SerializeField, ValueDropdown("ReferenceDropDownEditorOnly"), OnValueChanged("ReferenceValueChangedEditorOnly"), LabelText("References")] string referenceGuidEditorOnly; [ShowInInspector, ReadOnly, InlineEditor(InlineEditorModes.LargePreview), ShowIf("ReferencePreviewShowIfEditorOnly")] GameObject PreviewOnEditor; [SerializeField, ValueDropdown("AssetGroupDropDownEditorOnly", IsUniqueList = true), LabelText("Addressable Group Filter")] string[] targetAssetGroupGuidsEditorOnly; #pragma warning restore 0649 IEnumerable ReferenceDropDownEditorOnly() { return GetAllAssetEntrys(targetAssetGroupGuidsEditorOnly) .Select(x => new ValueDropdownItem(x.AssetPath, x.guid)); } IEnumerable AssetGroupDropDownEditorOnly() { return GetAllAssetGroups() .Select(x => new ValueDropdownItem(x.Name, x.Guid)); } void ReferenceValueChangedEditorOnly(string guid) { var entrys = GetAllAssetEntrys(targetAssetGroupGuidsEditorOnly); var item = entrys.FirstOrDefault(x => x.guid == guid); if (item != default) { references = new AssetReferenceGameObject(item.guid); UpdatePreviewAssetEditorOnly(); } } bool ReferencePreviewShowIfEditorOnly() { if(PreviewOnEditor == default) { UpdatePreviewAssetEditorOnly(); } return PreviewOnEditor != default; } void UpdatePreviewAssetEditorOnly() { PreviewOnEditor = default; if(references.RuntimeKeyIsValid()) { PreviewOnEditor = LoadAsset<GameObject>(references); } } /// <summary> /// アセットの取得 /// </summary> /// <returns>The asset.</returns> /// <param name="reference">Reference.</param> /// <typeparam name="T">The 1st type parameter.</typeparam> public static T LoadAsset<T>(AssetReference reference) where T : Object { return reference.RuntimeKeyIsValid() ? AssetDatabase.LoadAssetAtPath<T>(AssetDatabase.GUIDToAssetPath(reference.AssetGUID)) : default; } /// <summary> /// グループ一覧を取得 /// </summary> /// <returns>The asset groups.</returns> public static List<AddressableAssetGroup> GetAllAssetGroups() { var setting = AddressableAssetSettingsDefaultObject.GetSettings(false); var gropus = new List<AddressableAssetGroup>(); if (setting != default) { gropus = setting.groups; } return gropus; } /// <summary> /// 全エントリーを取得 /// </summary> /// <returns>The asset entrys editor only.</returns> /// <param name="groupFilterGuids">Group filter.</param> public static List<AddressableAssetEntry> GetAllAssetEntrys(string[] groupFilterGuids = null) { var setting = AddressableAssetSettingsDefaultObject.GetSettings(false); var entrys = new List<AddressableAssetEntry>(); if (setting != default) { foreach (var group in setting.groups) { if (groupFilterGuids != null && groupFilterGuids.Length > 0 && !groupFilterGuids.Any(guid => guid == group.Guid)) { continue; } var _entrys = new List<AddressableAssetEntry>(); group.GatherAllAssets(_entrys, false, true, false); entrys.AddRange(_entrys); } } return entrys; } #endif #endregion }実装のポイント
AddressableAssetSettingsの取得方法が変わりました
OdinWithAddressableAssetReference.csvar setting = AddressableAssetSettingsDefaultObject.GetSettings(false);プレビュー用GameObjectをシリアライズされないようにする
プレビューを表示するためのGameObjectがシリアライズされないようにprivateでShowInInspectorアトリビュートを使用しています。
publicにしたい場合は、[System.NonSerialized]を追加。更に、プレビューは参照だけで使用されることが無いので#pragma warningでCS0649警告が表示されないようにしています。
OdinWithAddressableAssetReference.cs[ShowInInspector, (略)] GameObject PreviewOnEditor;OdinでAddressableは非対応なのでGuidを保存する
ドロップダウンは実はテキストです(string referenceGuidEditorOnly)。
表示するリストを生成する際(ReferenceDropDownEditorOnly())、表示用のアセットパスと保存用のGuidをOdinのValueDropdownItemに代入しています。
そして、Guidに変更があった場合(ReferenceValueChangedEditorOnly(string guid))でプレビューを更新する仕様です。OdinWithAddressableAssetReference.cs[SerializeField, ValueDropdown("ReferenceDropDownEditorOnly"), OnValueChanged("ReferenceValueChangedEditorOnly"), LabelText("References")] string referenceGuidEditorOnly; IEnumerable ReferenceDropDownEditorOnly() { return GetAllAssetEntrys(targetAssetGroupGuidsEditorOnly) .Select(x => new ValueDropdownItem(x.AssetPath, x.guid)); } void ReferenceValueChangedEditorOnly(string guid) { var entrys = GetAllAssetEntrys(targetAssetGroupGuidsEditorOnly); var item = entrys.FirstOrDefault(x => x.guid == guid); if (item != default) { references = new AssetReferenceGameObject(item.guid); UpdatePreviewAssetEditorOnly(); } } /// <summary> /// 全エントリーを取得 /// </summary> /// <returns>The asset entrys editor only.</returns> /// <param name="groupFilterGuids">Group filter.</param> public static List<AddressableAssetEntry> GetAllAssetEntrys(string[] groupFilterGuids = null) { var setting = AddressableAssetSettingsDefaultObject.GetSettings(false); var entrys = new List<AddressableAssetEntry>(); if (setting != default) { foreach (var group in setting.groups) { if (groupFilterGuids != null && groupFilterGuids.Length > 0 && !groupFilterGuids.Any(guid => guid == group.Guid)) { continue; } var _entrys = new List<AddressableAssetEntry>(); group.GatherAllAssets(_entrys, false, true, false); entrys.AddRange(_entrys); } } return entrys; }グループフィルターに対応
フィルタ機能もつけてみました。
ほんとはLabel用のフィルタ機能もつけたかったのですが、 LabelTableがprivateの為一覧取得ができず断念しました。
- 投稿日:2020-01-01T19:52:18+09:00
【Unity Editor拡張 with Odin】 Addressable AssetReferenceのプレビュー表示とグループでのフィルタリング
環境
Unity 2019.2.17f1
Addressable 1.5
Odin Inspector 2.1.8 (有料プラグイン)
AssetReferenceって何を参照しているのか分かりにくい。。。
名前を設定している場合はまだ分かりやすいですが、フォルダを指定している場合フルパスが表示されるのでかなり分かり辛いです。それを有料プラグインのOdinを使って解決してみようと思います。
まずは Before / After
Before...
After !!!!
だいぶ分かりやすくなりましたね。
Prefab名をクリックするとProject内のPrefabをハイライトしてくれます。
そしてグループでのフィルタリングにも対応しました。Code
OdinWithAddressableAssetReference.csusing System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.AddressableAssets; using Sirenix.OdinInspector; #if UNITY_EDITOR using UnityEditor; using UnityEditor.AddressableAssets; using UnityEditor.AddressableAssets.Settings; #endif [CreateAssetMenu(menuName = "Sample/OdinWithAddressableAssetReference")] public sealed class OdinWithAddressableAssetReference : ScriptableObject { [SerializeField, HideInInspector] AssetReferenceGameObject references; public AssetReferenceGameObject References => references; #region Inspector #if UNITY_EDITOR #pragma warning disable 0649 [SerializeField, ValueDropdown("ReferenceDropDownEditorOnly"), OnValueChanged("ReferenceValueChangedEditorOnly"), LabelText("References")] string referenceGuidEditorOnly; [ShowInInspector, ReadOnly, InlineEditor(InlineEditorModes.LargePreview), ShowIf("ReferencePreviewShowIfEditorOnly")] GameObject PreviewOnEditor; [SerializeField, ValueDropdown("AssetGroupDropDownEditorOnly", IsUniqueList = true), LabelText("Addressable Group Filter")] string[] targetAssetGroupGuidsEditorOnly; #pragma warning restore 0649 IEnumerable ReferenceDropDownEditorOnly() { return GetAllAssetEntrys(targetAssetGroupGuidsEditorOnly) .Select(x => new ValueDropdownItem(x.AssetPath, x.guid)); } IEnumerable AssetGroupDropDownEditorOnly() { return GetAllAssetGroups() .Select(x => new ValueDropdownItem(x.Name, x.Guid)); } void ReferenceValueChangedEditorOnly(string guid) { var entrys = GetAllAssetEntrys(targetAssetGroupGuidsEditorOnly); var item = entrys.FirstOrDefault(x => x.guid == guid); if (item != default) { references = new AssetReferenceGameObject(item.guid); UpdatePreviewAssetEditorOnly(); } } bool ReferencePreviewShowIfEditorOnly() { if(PreviewOnEditor == default) { UpdatePreviewAssetEditorOnly(); } return PreviewOnEditor != default; } void UpdatePreviewAssetEditorOnly() { PreviewOnEditor = default; if(references.RuntimeKeyIsValid()) { PreviewOnEditor = LoadAsset<GameObject>(references); } } /// <summary> /// アセットの取得 /// </summary> /// <returns>The asset.</returns> /// <param name="reference">Reference.</param> /// <typeparam name="T">The 1st type parameter.</typeparam> public static T LoadAsset<T>(AssetReference reference) where T : Object { return reference.RuntimeKeyIsValid() ? AssetDatabase.LoadAssetAtPath<T>(AssetDatabase.GUIDToAssetPath(reference.AssetGUID)) : default; } /// <summary> /// グループ一覧を取得 /// </summary> /// <returns>The asset groups.</returns> public static List<AddressableAssetGroup> GetAllAssetGroups() { var setting = AddressableAssetSettingsDefaultObject.GetSettings(false); var gropus = new List<AddressableAssetGroup>(); if (setting != default) { gropus = setting.groups; } return gropus; } /// <summary> /// 全エントリーを取得 /// </summary> /// <returns>The asset entrys editor only.</returns> /// <param name="groupFilterGuids">Group filter.</param> public static List<AddressableAssetEntry> GetAllAssetEntrys(string[] groupFilterGuids = null) { var setting = AddressableAssetSettingsDefaultObject.GetSettings(false); var entrys = new List<AddressableAssetEntry>(); if (setting != default) { foreach (var group in setting.groups) { if (groupFilterGuids != null && groupFilterGuids.Length > 0 && !groupFilterGuids.Any(guid => guid == group.Guid)) { continue; } var _entrys = new List<AddressableAssetEntry>(); group.GatherAllAssets(_entrys, false, true, false); entrys.AddRange(_entrys); } } return entrys; } #endif #endregion }実装のポイント
AddressableAssetSettingsの取得方法が変わりました
OdinWithAddressableAssetReference.csvar setting = AddressableAssetSettingsDefaultObject.GetSettings(false);プレビュー用GameObjectをシリアライズされないようにする
プレビューを表示するためのGameObjectがシリアライズされないようにprivateでShowInInspectorアトリビュートを使用しています。
publicにしたい場合は、[System.NonSerialized]を追加。更に、プレビューは参照だけで使用されることが無いので#pragma warningでCS0649警告が表示されないようにしています。
OdinWithAddressableAssetReference.cs[ShowInInspector, (略)] GameObject PreviewOnEditor;OdinでAddressableは非対応なのでGuidを保存する
ドロップダウンは実はテキストです(string referenceGuidEditorOnly)。
表示するリストを生成する際(ReferenceDropDownEditorOnly())、表示用のアセットパスと保存用のGuidをOdinのValueDropdownItemに代入しています。
そして、Guidに変更があった場合(ReferenceValueChangedEditorOnly(string guid))でプレビューを更新する仕様です。OdinWithAddressableAssetReference.cs[SerializeField, ValueDropdown("ReferenceDropDownEditorOnly"), OnValueChanged("ReferenceValueChangedEditorOnly"), LabelText("References")] string referenceGuidEditorOnly; IEnumerable ReferenceDropDownEditorOnly() { return GetAllAssetEntrys(targetAssetGroupGuidsEditorOnly) .Select(x => new ValueDropdownItem(x.AssetPath, x.guid)); } void ReferenceValueChangedEditorOnly(string guid) { var entrys = GetAllAssetEntrys(targetAssetGroupGuidsEditorOnly); var item = entrys.FirstOrDefault(x => x.guid == guid); if (item != default) { references = new AssetReferenceGameObject(item.guid); UpdatePreviewAssetEditorOnly(); } } /// <summary> /// 全エントリーを取得 /// </summary> /// <returns>The asset entrys editor only.</returns> /// <param name="groupFilterGuids">Group filter.</param> public static List<AddressableAssetEntry> GetAllAssetEntrys(string[] groupFilterGuids = null) { var setting = AddressableAssetSettingsDefaultObject.GetSettings(false); var entrys = new List<AddressableAssetEntry>(); if (setting != default) { foreach (var group in setting.groups) { if (groupFilterGuids != null && groupFilterGuids.Length > 0 && !groupFilterGuids.Any(guid => guid == group.Guid)) { continue; } var _entrys = new List<AddressableAssetEntry>(); group.GatherAllAssets(_entrys, false, true, false); entrys.AddRange(_entrys); } } return entrys; }グループフィルターに対応
フィルタ機能もつけてみました。
ほんとはLabel用のフィルタ機能もつけたかったのですが、 LabelTableがprivateの為一覧取得ができず断念しました。
- 投稿日:2020-01-01T01:23:23+09:00
ARで穴をあける[ウソ穴]システムの作り方
紹介すること
個人で開発している『ウソ穴』というシステムの作り方を紹介します。
ウソ穴とは
ウソ穴は、AR(拡張現実)とストリーミングを組み合わせて穴があいたかのような感覚を提供するシステムです。
こちらは、板にウソ穴を搭載したときの動画です。板に穴が空いているように見えますが、実際には板に穴はあいていません。壁に穴が開いてるように改良(動画30秒)
— j4amountain (@zsipparu) September 8, 2019
長編(5分)はYouTube(https://t.co/wD04rT7Vcd)#AR #拡張現実 #AugmentedReality #科学の力で穴を開けた https://t.co/TNqoJ6e9vM pic.twitter.com/tygFg49SbP穴をあけたように見せかけているので、このように体に穴をあける(あけたように見せかける)こともできます。
#ウソ穴 で体に穴をあけた。カーテンとモニターが、のぞき見えるのわかるかな。#MA_FESTA ではいろんな人に穴をあけたい。 pic.twitter.com/7X5CBvNNRg
— j4amountain (@zsipparu) December 3, 2019概要図
仕組み図解
- ラズパイをストリーミングサーバにして、ラズパイに装着したカメラの映像を配信します。
- 配信した映像をテクスチャとした3Dオブジェクトを作成します。
- 作成した3DオブジェクトをARで表示されるようにします。
- 板にARマーカを付けます。
- ARを設定したカメラを通して板を見るとを、ARマーカーの位置をもとに3Dオブジェクトが表示されます。これがウソ穴です。
※ 写真はこちらから拝借 https://www.pexels.com/ja-jp/photo/1128065/
セットアップの概要
ラズパイとWinPCで行うセットアップの概要です。
- ラズパイ (Raspberry Pi 4 Model B / 4GB)
- カメラを付ける
- MJPG-streamerでストリーミングサーバーにする
- →カメラ映像をストリーミングで配信する
- WinPC (Window10)
- Unityをインストール
- VuforiaでARマーカーを認識
- ARで3Dオブジェクを表示する
- →穴の形状をした3Dオブジェクトを作成する
- →3Dオブジェクトにストリーミング映像をテクスチャとしてマッピングする
参考リンク
※注意※
- セキュリティ対策は不十分です。
- ウソ穴のシステムは安定稼働に課題があり、ストリーミングサーバが意図せず停止することがあります。(連続稼働は5分くらいが限度)
- 備忘録なので説明が不十分なところがあります。それら情報も
参考リンク
で紹介した記事など参照することで確認できると思います。ラズパイをセットアップしよう
簡単ですがラズパイのセットアップ手順を紹介します。OSは、Rasbian(2019-09-26)をインストールしました。
ssh接続します。
ssh pi@raspberrypi.local # パスワード raspberryホスト名を変更します。
sudo nano /etc/hostname sudo nano /etc/hosts
- 更新します。
# パッケージ更新 $ sudo apt-get update $ sudo apt-get upgrade -y $ sudo apt-get dist-upgrade # ファームウェアを更新 $ sudo rpi-update
- ※先ほどの更新をシェルでまとめて実行するとこうなります。
# setup.sh という空ファイル作成 $ sudo touch setup.shsetup.sh#!/bin/sh sudo apt-get update sudo apt-get upgrade -y sudo apt-get dist-upgrade -y sudo rpi-update -y# 実行権限を付与 $ chmod +x setup.sh # シェル実行 $ ./setup.sh
- Wi-Fi接続設定をします。
/etc/wpa_supplicant/wpa_supplicant.confctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 network={ ssid="xxxxx-1" psk="xxxx" priority=0 scan_ssid=1 id_str="home1" } network={ ssid="xxxxx-2" psk="xxxx" priority=0 scan_ssid=1 id_str="home2" }
sudo raspi-configで色々設定していきます。
パスワード変更
1 Change User Password Change password for the current user
ロケールを設定
4 Localisation options - Change Locale - ja_JP.UTF-8
タイムゾーンを設定
4 Localisation Options - I2 Change Timezone - Asia - Tokyo
Wifiロケールを設定します
4 Localisation Options - I4 Change Wi-fi Country - JP Japan
pipバージョンアップ
$ sudo pip install --upgrade pip必須ではないですが、Windowsとのデータ移行が楽になるので、sambaをインストールします。
$ sudo apt-get install samba $ cd /etc/samba
- /etc/samba/smb.confの最後尾に以下を追記します。
[pi-raspberry] path = /home/pi read only = No guest ok = Yes force user = pi [tmp-raspberry] path = /var/tmp read only = No guest ok = Yes force user = pi
- sambaを再起動するとWindowsのエクスプローラ経由でアクセスできるようになります。
$ sudo service smbd restart $ sudo service nmbd restart
- カメラモジュールを認識させます。
$ sudo raspi-config
5 Interfacing Options
-P1 Camera
-はい
-了解
- OSを再起動後に再接続(ssh接続)します。
- カメラが認識されているか確認します。
$ vcgencmd get_camera
supported=1 detected=1
と表示されれば認識成功です。ラズパイにMJPG-streamerをインストールしてストリーミングサーバにしよう
- mjpeg-streamerをインストールして、起動します。
$ sudo apt-get install build-essential libjpeg8-dev imagemagick libv4l-dev cmake -y $ git clone https://github.com/jacksonliam/mjpg-streamer.git $ cd mjpg-streamer/mjpg-streamer-experimental
- CMakeLists.txtを編集します。
- ⾏頭にʼ#ʼを追加してコメントアウトします。(これすると、make実行時のエラー発生を対策できるみたいです)
#add_subdirectory(plugins/input_opencv)$ make $ sudo make install
- ※よくわからんのだが、↓をするといいらしい
~/mjpg-streamer/mjpg-streamer-experimental $ cp input_raspicam.so ../
- MJPEG-streamerのインストールが完了したので、ストリーミング配信を試します。
- コマンドを実行し配信を開始したら、ブラウザで
http://{{ラズパイのIP}}:8080/
にアクセスして、ラズパイカメラの映像が表示されれば成功です。# ストリーミング起動 $ /usr/local/bin/mjpg_streamer -i "input_raspicam.so -x 640 -y 480 -fps 15 -q 80" -o "output_http.so -p 8080 -w /usr/local/share/mjpg-streamer/www" # -> http://{{ラズパイのIP}}:8080/ # -> http://{{ラズパイのIP}}:8080/javascript_simple.html # -> http://{{ラズパイのIP}}:8080?action=snapshot # -> http://{{ラズパイのIP}}:8080?action=stream
- ウソ穴では、このような設定にしていました。
# ウソ穴 $ /usr/local/bin/mjpg_streamer -i "input_raspicam.so -x 64 -y 64 -fps 10 -q 80" -o "output_http.so -p 8090 -w /usr/local/share/mjpg-streamer/www" # -> http://{{ラズパイのIP}}:8090?action=stream
- 配信を開始するコマンドをShellにしておくと便利です。
/usr/local/bin/start_mjpeg.sh#!/bin/sh /usr/local/bin/mjpg_streamer -i "input_raspicam.so -x 256 -y 256 -fps 15 -q 80" -o "output_http.so -p 8090 -w /usr/local/share/mjpg-streamer/www"
- 実行権限を付与します。
chmod +x start_mjpeg.shラズパイでストリーミング再生をスケジュール実行しよう
- Unityからストリーミングサーバへの要求が厳しいのか、ウソ穴を実行すると5分くらいでMJPEG-streamerが落ちるという課題があります。そこで、1分単位でMJPEG-streamerが止まっていたら実行するようにスケジュールを設定します。
mjpeg.sh#!/bin/sh /usr/local/bin/mjpg_streamer -i "input_raspicam.so -x 64 -y 64 -fps 10 -q 80" -o "output_http.so -p 8090 -w /usr/local/share/mjpg-streamer/www"
- スケジュール実行のルールを書いたファイルを作ります(ファイル名は任意)
cron.conf0-59 * * * * /bin/bash /home/pi/mjpeg.sh @reboot /bin/bash /home/pi/mjpeg.sh
- cronにジョブとして登録します。
$ crontab cron.conf※注意※
ルールを書いたファイルcron.conf
を編集した場合は、再度ジョブ登録が必要です。ラズパイOSイメージのバックアップ
- ラズパイOSのセットアップが完了したら、バックアップすることをオススメします。
- Disk Imageで、WindowsにラズパイOSのバックアップイメージを保存できます。
Unityプロジェクトを作ろう
- ここからはWindowsでの作業になります。Unityがインストールされていることが前提です。
- ストリーミングのスナップショットをテクスチャにマッピングするスクリプト
GetNetworkImage6.cs
を作成します。GetNetworkImage6.csusing UnityEngine; using System.Collections; using UnityEngine.UI; public class GetNetworkImage6 : MonoBehaviour { private float timeleft; IEnumerator RenewImage(){ string url = "http://{{ラズパイのIP}}:8090/?action=snapshot"; WWW www = new WWW(url); Debug.Log (www); yield return www; RawImage rawImage = GetComponent<RawImage>(); rawImage.texture = www.textureNonReadable; } void Start() { StartCoroutine( RenewImage() ); } void Update() { StartCoroutine( RenewImage() ); } }
GetNetworkImage6.cs
をAssetに登録します。
- 詳細は割愛しますが、各オブジェクトの設定はこのようになります。
以上でおわりです。