- 投稿日:2021-01-24T20:13:38+09:00
Unity: VuforiaのImageTargetにオブジェクトを動的に追加する方法
How To Dynamically Add Content to Targets in Unity(https://library.vuforia.com/articles/Solution/Working-with-Vuforia-and-Unity.html)
を参考にしたがPrefabを表示出来なかったので、こうやったらOKだった。環境
OS macOS 10.15.7
Unity 2019.4.2f1
Addressable 1.16.15手順(上記マニュアルGoogleで直訳)
Unityプロジェクトを開くか作成し、ImageTarget GameObjectを追加します(メニュー:GameObject> Vuforia> Image)
実行時に、カスタム3Dモデルを画像ターゲットに動的にアタッチするとします。
プロジェクトビューの[アセット]フォルダーの下に、Prefabというサブフォルダーを作成します(まだサブフォルダーがない場合)。
PrefabオブジェクトをPrefabフォルダーに追加します。 3Dオブジェクトを表すカスタムPrefabを作成する方法はたくさんあります。たとえば、次のことができます。
- シーンビューで単純なCubeゲームオブジェクトを作成し、それをシーンビューからプロジェクトビューのPrefabsフォルダーにドラッグします。 または
- Unityでサポートされている形式(FBX、OBJ、DAE、3DSなど)で3Dモデルをインポートします。さまざまなファイル形式の3Dモデルからプレハブを作成する方法の詳細については、UnityのWebサイトを参照してください。
- たとえば、C#スクリプトを作成し、それをLoaderと呼び、それをイメージターゲットオブジェクトにアタッチします。
次のコードをスクリプトに挿入して、スクリプトを保存します。
using UnityEngine; using Vuforia; using System.Collections; public class loader : MonoBehaviour, ITrackableEventHandler { private TrackableBehaviour mTrackableBehaviour; public GameObject model; // Use this for initialization void Start () { mTrackableBehaviour = GetComponent<TrackableBehaviour>(); if (mTrackableBehaviour) { mTrackableBehaviour.RegisterTrackableEventHandler(this); } } // Update is called once per frame void Update () { } public void OnTrackableStateChanged( TrackableBehaviour.Status previousStatus, TrackableBehaviour.Status newStatus) { if (newStatus == TrackableBehaviour.Status.DETECTED || newStatus == TrackableBehaviour.Status.TRACKED) { OnTrackingFound(); } } private void OnTrackingFound() { if(model!=null){ GameObject obj=GameObject.Instantiate(model); obj.transform.parent = mTrackableBehaviour.transform; obj.transform.localPosition= new Vector3(0f, 0f, 0f); obj.transform.localRotation = Quaternion.identity; obj.active=true; } } }
なんでマニュアルでは
public Transform myModelPrefab;
ってしたんだろう。こうするとPrefabを登録できない。(マニュアルにはUIにPrefabを登録すると書いているのに)。公式マニュアルに掲載されているのでこれが正しいはずなのに。
- 投稿日:2021-01-24T17:29:57+09:00
UniRxのUIにまつわる処理3選
様々な使い方のあるUnityのライブラリ「UniRx」の中でも、
UIにまつわる処理を紹介します。その1. ReactiveProperty
その2. BindToButtonOnClick
その3. BindToOnClickその1. ReactiveProperty
Sample1using UnityEngine; using UniRx; public class Sample1 : MonoBehaviour { //int level; とほぼ同じ使い方ができる。 ReactiveProperty<int> level = new ReactiveProperty<int>(); void Start() { level.Subscribe(Talk); //level.Subscribe(arg => Talk(arg)); のようなラムダ式でも可 } void Update() { if (Input.GetKeyDown(KeyCode.Space)) { level.Value++; //.Valueで中身にアクセスする } } void Talk(int level) { Debug.Log("level up!" + level); } }Spaceを押すとlevelが上がり、levelが上がると当時にlevel up!と表示される。
ReactivePropertyは、ざっくり言うと、値の変更を通知してくれる変数のようなものです。
new ReactiveProperty()で作成し、Valueから値を取得・設定します。
(UniRxのReactivePropertyについて より引用。詳しい使い方も書かれています。)Subscribe関数から、値の変更時に呼ばれて欲しい関数を登録することができます。
値と常に同期して欲しいことの多いUIの変更に便利です。その2. BindToButtonOnClick
Sample2using UnityEngine; using UnityEngine.UI; using UniRx; public class UniRxSample2 : MonoBehaviour { [SerializeField] Button button; //bool can_press; とほぼ同じ使い方ができる。 ReactiveProperty<bool> can_press = new ReactiveProperty<bool>(); // Start is called before the first frame update void Start() { can_press.BindToButtonOnClick(button, _ => Click()); } private void Update() { if (Input.GetKeyDown(KeyCode.T)) { can_press.Value = true; } if (Input.GetKeyDown(KeyCode.F)) { can_press.Value = false; } } void Click() { Debug.Log("Click"); } }can_pressというReactivePropertyの値が、Tキーを押すとtrueに、Fキーを押すとfalseに変更される。can_pressの値が変更されるとbuttonのinteractableも変更される。
BindToButtonOnClickは、ボタンに"押下された際の処理"と"押せるかどうか"、つまりonClickとinteractableを同時に登録するような関数です。
bool型のReactivePropertyから呼び出すことができます。ちなみに、can_press.SubscribeToInteractableでinteractableのみ登録ができます。
ButtonのOnClickAsObservable()関数は、onClickをIObservableに変換する関数です。
Where関数で、bool型の関数を入力することができます。そのbool型の関数の結果がtrueの場合のみしか登録した関数を呼びださない、という処理が可能になります。その3. BindToOnClick
Sample3using System.Collections; using UnityEngine; using UnityEngine.UI; using UniRx; public class UniRxSample3 : MonoBehaviour { [SerializeField] private Button button; void Start() { button.BindToOnClick(_ => Observable.FromCoroutine(LevelingUp)); } IEnumerator LevelingUp() { int level = 0; for (int i = 0; i < 100; i++) { level++; yield return null; } Debug.Log("level up!"); } }buttonを押すと、コルーチンが呼ばれ、完了するまでButtonのinteractableがfalseとなる。
BindToOnClickはButtonにIObservableを返す関数を登録することができる関数です。
入力したIObservableが完了するまで、interactableがfalseとなります。
アニメーションを伴う処理や、サーバーと通信する処理などをする間、Buttonを押せなくするのに便利です。
CoroutineはFromCoroutine関数でIObservableに変換することができます。
- 投稿日:2021-01-24T14:40:01+09:00
Unity ML-Agents 導入 macOS Big Sur
1.前書き
Unityの機械学習、ML-Agentsをいろんな記事をフラフラ彷徨いながらやっと導入できました。
目次載せておきますんで「途中でエラー出て詰まってるよー」って方はビュンビュンスキップしてもらってOKです!2.必要なツール
Unity バージョン2018以降
Anaconda-Navigator
Python 3.7(Macは3.7じゃないとバグるので3.7は厳守)これらがインストールできたら次の項目へ〜。
3.仮想環境の作成とML-Agentsのインストール
ターミナルを開き以下のコマンドを順番に打ち込んでください。
[ Python仮想環境の作成 ]
1行目で仮想環境を作成し、2行目で仮想環境を起動します。
※既に同じ名前の仮想環境が作成されている場合はエラーが出ます。作り直しましょう。conda create -n ml-agents python3.7 conda activate ml-agents[ ML-Agentsのインストール ]
※既に「ml-agents」という名前のファイルが開いているディレクトリ内に存在する場合エラーが出ます。
git clone https://github.com/Unity-Technologies/ml-agents.git[ Pythonパッケージのインストール ]
cdコマンドで先ほどインストールしたml-agentsファイルの中に移動します。
そして、その中にあるPythonパッケージをインストールします。cd ml-agents pip install -e ./ml-agents-envs pip install -e ./ml-agents[ 完了! ]
これでターミナルはOKです!
Let‘s go to Unity!!4.Unityで学習環境を作成
今回は、ボールが立方体に向かって転がるように訓練する学習環境を作ります。
2018以降のUnityでプロジェクトを作成します。
まずメニューバーのWindow > Package Managerを開いて下さい。
下の画像のように右上の検索欄に「ML Agnets」と入力すると出てくるので右下のinstallボタンからインストールして下さい。ProjectウィンドウのPackaegフォルダ内に「ML Agents」とあればインストール完了です!次に、PlaneとCubeとSphereを作成してそれぞれ順番に「Floor」「Target」「RollerAgent」という名前にして下さい。
それぞれにMaterialをつけるとこんな感じです↓そして、「RollerAgent」という名前でスクリプトを作成して下記のコードをコピペして下さい。
using System.Collections.Generic; using UnityEngine; using Unity.MLAgents; using Unity.MLAgents.Sensors; // RollerAgent public class RollerAgent : Agent { public Transform target; Rigidbody rBody; // 初期化時に呼ばれる public override void Initialize() { rBody = GetComponent<Rigidbody>(); } // エピソード開始時に呼ばれる public override void OnEpisodeBegin() { // RollerAgentが床から落下している時 if (this.transform.localPosition.y < 0) { // RollerAgentの位置と速度をリセット this.rBody.angularVelocity = Vector3.zero; this.rBody.velocity = Vector3.zero; this.transform.localPosition = new Vector3(0.0f, 0.5f, 0.0f); } // Targetの位置のリセット target.localPosition = new Vector3( Random.value * 8 - 4, 0.5f, Random.value * 8 - 4); } // 観察取得時に呼ばれる public override void CollectObservations(VectorSensor sensor) { sensor.AddObservation(target.localPosition); //TargetのXYZ座標 sensor.AddObservation(this.transform.localPosition); //RollerAgentのXYZ座標 sensor.AddObservation(rBody.velocity.x); // RollerAgentのX速度 sensor.AddObservation(rBody.velocity.z); // RollerAgentのZ速度 } // 行動実行時に呼ばれる public override void OnActionReceived(float[] vectorAction) { // RollerAgentに力を加える Vector3 controlSignal = Vector3.zero; controlSignal.x = vectorAction[0]; controlSignal.z = vectorAction[1]; rBody.AddForce(controlSignal * 10); // RollerAgentがTargetの位置に到着した時 float distanceToTarget = Vector3.Distance( this.transform.localPosition, target.localPosition); if (distanceToTarget < 1.42f) { AddReward(1.0f); EndEpisode(); } // RollerAgentが床から落下した時 if (this.transform.localPosition.y < 0) { EndEpisode(); } } }スクリプトが作成できたらRollerAgent(オブジェクト)にAddComponentでRIgidBody、Behaviour Parameters、RollerAgent、DecisionRequesterを順番に追加し、下の画像のようにパラメータを変更して下さい。
これで学習環境の設定は完了です!
5.Pythonスクリプトで学習
[ 訓練設定ファイルの作成 ]
ターミナルコマンドでダウンロードしたml-agents > configフォルダ内にsampleという名前でフォルダを作りその中にyamlファイルを作成します。
config内の他のフォルダにもyamlファイルがあるのでそれを複製して書き換えるのでもいいでしょう。
では、作ったyamlファイルを「RollerBall」という名前に設定し以下のコードをコピペして下さい。RollerBall: summary_freq: 1000 batch_size: 10 buffer_size: 100 normalize: true ↓ behaviors: RollerBall: trainer_type: ppo hyperparameters: batch_size: 10 buffer_size: 100 learning_rate: 0.0003 beta: 0.005 epsilon: 0.2 lambd: 0.95 num_epoch: 3 learning_rate_schedule: linear network_settings: normalize: true hidden_units: 128 num_layers: 2 vis_encode_type: simple reward_signals: extrinsic: gamma: 0.99 strength: 1.0 keep_checkpoints: 5 checkpoint_interval: 500000 max_steps: 500000 time_horizon: 64 summary_freq: 1000 threaded: true[ Terminalで学習開始 ]
では、ターミナルをもう一度開いて次の2つのコマンドを入力!
cd ml-agents
mlagents-learn ./config/sample/RollerBall.yaml --run-id=RollerBall-ppo-1 --forceこれで下のような画面が出たらUnityの[▶︎]を押して学習スタートです!
▄▄▄▓▓▓▓ ╓▓▓▓▓▓▓█▓▓▓▓▓ ,▄▄▄m▀▀▀' ,▓▓▓▀▓▓▄ ▓▓▓ ▓▓▌ ▄▓▓▓▀' ▄▓▓▀ ▓▓▓ ▄▄ ▄▄ ,▄▄ ▄▄▄▄ ,▄▄ ▄▓▓▌▄ ▄▄▄ ,▄▄ ▄▓▓▓▀ ▄▓▓▀ ▐▓▓▌ ▓▓▌ ▐▓▓ ▐▓▓▓▀▀▀▓▓▌ ▓▓▓ ▀▓▓▌▀ ^▓▓▌ ╒▓▓▌ ▄▓▓▓▓▓▄▄▄▄▄▄▄▄▓▓▓ ▓▀ ▓▓▌ ▐▓▓ ▐▓▓ ▓▓▓ ▓▓▓ ▓▓▌ ▐▓▓▄ ▓▓▌ ▀▓▓▓▓▀▀▀▀▀▀▀▀▀▀▓▓▄ ▓▓ ▓▓▌ ▐▓▓ ▐▓▓ ▓▓▓ ▓▓▓ ▓▓▌ ▐▓▓▐▓▓ ^█▓▓▓ ▀▓▓▄ ▐▓▓▌ ▓▓▓▓▄▓▓▓▓ ▐▓▓ ▓▓▓ ▓▓▓ ▓▓▓▄ ▓▓▓▓` '▀▓▓▓▄ ^▓▓▓ ▓▓▓ └▀▀▀▀ ▀▀ ^▀▀ `▀▀ `▀▀ '▀▀ ▐▓▓▌ ▀▀▀▀▓▄▄▄ ▓▓▓▓▓▓, ▓▓▓▓▀ `▀█▓▓▓▓▓▓▓▓▓▌ ¬`▀▀▀█▓ Version information: ml-agents: 0.24.0.dev0, ml-agents-envs: 0.24.0.dev0, Communicator API: 1.3.0, PyTorch: 1.7.1 2021-01-24 12:05:49 INFO [learn.py:269] run_seed set to 223 2021-01-24 12:05:49 INFO [environment.py:205] Listening on port 5004. Start training by pressing the Play button in the Unity Editor.[▶︎]を押したらReward(報酬)が記録されていきます。
他にStepという値があるはずなのでそのStepが50000を超えたら学習をストップ(Unityエディタの[▶︎]を押す)してください。
これで学習完了です![ 推論モデルを実行 ]
ml-agents内のresultというフォルダの中を調べていくとRollerBall.onnxというものがあるはずです。それが推論モデルになります。それをUnityにインポートしてRollerBall(オブジェクト)のBehaviour ParametersのModelsにドラッグ&ドロップしてください。そのまま[▶︎]を押せば学習した内容の通りに動きます!
後書き
これで一人でも「嗚呼分からない。嗚呼。」という方を減らせれば幸いです!
- 投稿日:2021-01-24T09:45:29+09:00
Unityを始める - Unityの画面構成 -
はじめに
以前、Unityで開発を始める場合に必要な事をまとめました。
Unityでゲーム開発を進める中で、知っておく必要があるUnityの画面構成についてまとめます。
また、一般的な基本操作もまとめます。参考になる本
参考になるサイト
準備
Unityのプロジェクトの作成
- UnityHubの起動
- 新しいプロジェクトの作成
詳細は「Unityを始める - Unityインストールからプロジェクト作成 -」にまとめました。
Unityの各画面説明
Sceneビュー
Sceneビュー は、作成しているゲーム世界に相互作用できるビューです。シーンビューを使って風景、キャラクター、カメラ、ライト、その他のすべての種類の ゲームオブジェクト を選択し配置します。
Gameビュー
Gameビュー はゲーム内のカメラから見た絵をレンダリングしています。それは最終的にパブリッシュしようとしているゲーム画面です。プレイヤーがゲームをしている時に、実際に見ていものを制御するには 1つ以上の Camera (カメラ) を使う必要があります。
Hierarchyビュー
Hierarchy (ヒエラルキー) ウィンドウには現在のシーンにおける各ゲームオブジェクトのリストが表示されます。これらのいくつかは Asset ファイル (3D モデルなど) のインスタンスそのもので、その他は、プレハブのインスタンスで、ゲームのほとんどを構成するカスタムオブジェクトです。オブジェクトはシーンの中で加えたり、削除したりするので、Hierarchy ウィンドウでも、表われたり、消えたりします。
デフォルトでは、オブジェクトは作成された順に Hierarchy ウィンドウにリストされます。オブジェクトをドラッグして上下に順番を替えたり、「子」や「親」のオブジェクトにしたりできます。
Inspectorビュー
Inspector を使用して、ゲームオブジェクト、アセット、マテリアルなどの物理的なゲームアイテムや、Unity エディター内の設定や環境設定など、ほぼすべてのプロパティーと設定を確認および編集できます。
Unityエディタ画面の構成
各ビューのタブをドラッグして、好きなところに持っていくことで、レイアウトを変更できます。
構成のカスタマイズと保存
画面上部の「Window⇒Layouts」にて始めから登録されているレイアウトを使用する事ができます。
まとめ
今回はUnityの画面構成についてまとめました。
これらの使い方を知っておく事で、今後のUnityによるゲーム開発のスピードや精度を一気に高める事ができます。また、他の人が作成したUnityのプロジェクトの内容も理解しやすくなります。
- 投稿日:2021-01-24T09:10:35+09:00
[Unity]DOTS(主にECS)の素晴らしい記事リンク集(随時更新中)
概要
普段ECSの勉強でお世話になっているサイトのリンク集です
記事
テラシュールブログさん
【Unity,ECS】他のEntityが持つComponentDataを追跡する - ComponentDataFromEntity
【Unity】ECSで配列を格納する Dynamic Buffersエフアンダーバー 個人開発の記録さん
【Unity】 ECS まとめ(前編)
【Unity】 ECS まとめ(後編)EF Blogさん
@VeyronSakaiさん
Unity DOTSとUnity Physicsでただ単純に球を動かしてみる
Unity DOTSでRoll a Ball(玉転がし)を作る
PrefabからEntityを生成する方法メモ(Entities v0.8.0)
➡DeclareReferencedPrefabsnpakaさん
Unity DOTS の概要
Unity DOTS サンプル
Unity DOTS 入門 (1) - 従来のUnityの設計をDOTSの設計に変換
Unity DOTS 入門 (11) - トリガーイベント
Unity Physics 入門
Unity NetCode 入門 (1) - チュートリアルsimplestarの技術ブログさん
unity LearningMaterialsさん
Hybrid ECSで高速Transform更新
ECS初学者に向けてのTips集
たのしいDOTS 〜初級から上級まで〜
大量のオブジェクトを含む広いステージでも大丈夫、そうDOTSならねYouTube
Code Monkeyさん
- 投稿日:2021-01-24T00:27:55+09:00
MessagePack for C#で、Genericな変数をIL2CPP環境で使いたいときのメモ
前提
このライブラリの応用?的な使い方の話をしています。
現時点の最新版、2.2.85で動作確認済み。
https://github.com/neuecc/MessagePack-CSharpUnityエディタでは動いてたのに、IL2CPP対応(iOSとかWebGLビルドだと強制)で
FormatterNotRegisteredException 出てキッツい人向けお役立ち情報。やりたいこと
変数部分をGenericにして、要処で使いわけたいパターンがあるとする。
テストコードとしてはこういう感じ。public class TestClass { [MessagePackObject(keyAsPropertyName: true)] public class TargetClass<T> { public T param = default; public TargetClass(T param) { this.param = param; } } // Tには [MessagePackObject] が付いた別クラスのインスタンスが来る想定 public void ExecuteTest<T>(T parameter) { var bytes = MessagePackSerializer.Serialize(new TargetClass<T>(parameter)); MessagePackSerializer.Deserialize<TargetClass<T>>(bytes); } }Unityで通常実行すると普通に通るんだけども、何も考えずIL2CPP設定でビルドすると通らない。
IL2CPP環境では動的コード生成が行えないので、事前にGeneratedResolverを生成しておく必要がある。
事前生成のやり方は、公式ReadMeのAOT Code Generation (support for Unity/Xamarin)の項目で説明されている。
https://github.com/neuecc/MessagePack-CSharp#aot-code-generation-support-for-unityxamarin問題は、AOTコード生成をやっても上のコードはまだ通らない。
なので、もうひと手間を加える必要があるぞ、というのが今回の記事。解決方法
[MessagePackObject(keyAsPropertyName: true)] [MessagePack.Union(0, typeof(TargetClass<GenericClass_0>))] [MessagePack.Union(1, typeof(TargetClass<GenericClass_1>))] [MessagePack.Union(2, typeof(TargetClass<GenericClass_2>))]// 対応させる必要クラス分、Unionをこの要領で追加すること public class TargetClass<T> { public T param = default; public TargetClass(T param) { this.param = param; } }Union機能を使うことで解決ができます。
https://github.com/neuecc/MessagePack-CSharp#union
Unionを追加した後に、先述のAOT Code Generationの作業を(再)実行する必要があるので注意してください。
AOT Code Generationで生成したコード内を見ると、対応できてそうかは目視確認できます。// 前略 internal static class GeneratedResolverGetFormatterHelper { private static readonly global::System.Collections.Generic.Dictionary<Type, int> lookup; static GeneratedResolverGetFormatterHelper() { lookup = new global::System.Collections.Generic.Dictionary<Type, int>(193) { // 中略 { typeof(global::TestClass.TargetClass<global::GenericClass_0>), 30 }, { typeof(global::TestClass.TargetClass<global::GenericClass_1>), 31 }, { typeof(global::TestClass.TargetClass<global::GenericClass_2>), 32 }, // 後略こういう感じで、TargetClass<T> 項目の反映がなされていれば多分OKです。
追記(2021/01/26)
一応ですが、これはバッドノウハウに相当する可能性があります。
Unionを追加した状態でAOT Code Generation手順を忘れると
UnityエディタでDynamicUnionResolver(非IL2CPP環境で、対応コードを自動生成してくれるやつ)が
Union can only be interface or abstract class.
というエラーを吐きます。
エラー表示通り、本来Unionはinterfaceとabstractクラスだけを対応するつもりのものっぽいですね。
後々の仕様変更で死ぬ可能性はあるので、その際はまた別途解決策を模索したほうがよさそうです。Unityエディタで暫定回避をするための対応としては、下記みたいな方法があるんじゃないでしょうか。
- Union部分を#if ENABLE_IL2CPP
とか#if !UNITY_EDITOR
で括って、発生を回避する
- 逆に何もせず、エラーを都度出して見落とさないようにし、AOTコード生成を都度行う運用でカバー