20210724のUnityに関する記事は3件です。

Rx部品の命名案

はじめに 以前、下記記事にイベントハンドラの命名案を記載しました。 RxはC#のevent構文の上位互換と言われています。 では、同じ解釈を適用する場合、RxのIObservable等の部品の命名パターンはどのように構築すれば良いのか考えてみます。 今回の内容は下記記事に記載したRxの解釈に基づいたものとなります。 Rx全般に適用可能だと思いますが、ここではUniRxのみを検討範囲とします。 クラス別命名案 以下の形で整理できるのではないかと考えました。 Subject Subjectという型の名前自体は、恐らく「主題」という意味で使用しているのではないかと思います。 Observerと繋がるように「観測テーマ」と意訳しても良いと思います。 イベントを発火させる役割で利用する場合は、Subjectはイベントのフィールドの置き換えとなります。 イベント構文でのフィールド宣言部分 private EventHandler eventHandler; Rxでのフィールド宣言部分 private readonly Subject<Unit> eventHandler = new Subject<Unit>(); このため、イベントハンドラと同じ命名方法が使えそうです。 イベントハンドラの命名例 public class Enemy { public event EventHandler OnDead; } イベントハンドラの命名例をSubjectに適用 public class Enemy { private readonly Subject<Unit> onDead = new Subject<Unit>(); } Observable event構文を置き換える場合、Observableはイベントプロパティを置き換える部分となります。 イベント構文でのイベントプロパティ private EventHandler eventHandler; public event EventHandler EventHandler { add { this.eventHandler += value; } // removeの方は検討範囲外なので省略 } RxでのObservable公開部分 private readonly Subject<Unit> eventHandler = new Subject<Unit>(); public IObservable<Unit> EventHandler => this.eventHandler; このため、こちらもイベントハンドラ名と同じ命名方法でいけそうです。 イベントハンドラの命名例 public class Enemy { public event EventHandler OnDead; } イベントハンドラの命名例をObservableに適用 public class Enemy { private readonly Subject<Unit> onDead = new Subject<Unit>(); public IObservable<Unit> OnDead => this.onDead; } Observer Observerそのものについては、インスタンスに名前を付けて保持することがまずないので、検討対象外とします。 Observerに登録する、イベント発火時に呼び出すメソッドの登録処理は以下のように置き換わります。 イベント構文でのイベント購読処理 this.EventHandler += this.OnFired(); RxでのObservable購読処理 this.EventHandler.Subscribe(_ => this.OnFired()); このため、こちらはイベントハンドラのメソッド名と同じ考え方が使えそうです。 イベントハンドラのメソッド名の命名例 public class Enemy { public event EventHandler OnDead; } public class Player { public void StartBattle(Enemy enemy) { enemy.OnDead += this.OnEnemyDead; } } イベントハンドラのメソッド名の命名例をObserverに登録するメソッドに適用 public class Enemy { public IObservable<Unit> OnDead { get; } } public class Player { public void StartBattle(Enemy enemy) { enemy.OnDead.Subscribe(_ => this.OnEnemyDead()); } } 例文で検証 上記の考え方で書いたプログラムが「英語の自然言語に近いプログラム」となり得るのかどうか、例文を作って検証してみます。 Rx命名案検証用の例文 public class Enemy { // (1) private readonly Subject<Unit> onDead = new(); public IObservable<Unit> OnDead => onDead; public void Die() { // (2) this.onDead.OnNext(Unit.Default); } } public class Player { public void SratBattle(Enemy enemy) { // (3) (4) enemy.OnDead.Subscribe(onNext: _ => this.OnEnemyDead()); } private void OnEnemyDead() { // 敵死亡時の処理 } } (1)〜(4)それぞれのコードを英文になるように組み立て、翻訳サイトDeepLで翻訳して意味の通る日本語となるか検証します。 (1) Subject<Unit> onDead まずは(1)の部分を英文にしてみます。 RxをPub/Subパターンで捉えてみるの解釈では、Subjectのインスタンス生成は、Subjectの内部ObserverがSubject利用クラスを観測開始することを意味するのでした。 この役割を示すような英文を考えると、以下のようになりました。 A subject of onDead is messages published on the enemy’s being dead. →onDeadの観測テーマは、敵が死んだことで発行されるメッセージです。 翻訳サイトの翻訳結果から、Subjectの部分のみ「観測テーマ」に変更しています。 onDeadから創造されたとは思えない程長くなってしまっていますが、以下の部分以外はボイラープレートです。 onDead - フィールド名 enemy - クラス名 being dead - イベント発火タイミング (2) onDead.OnNext() 続いて(2)の方です。 自然な文となるように、onDead(Subject)をJohnとします。 John, do the process for on next message's having been published. →ジョンさん、次のメッセージが公開された時の処理をしてください。 OnNext()は、上記の文章の中で一番重要な部分のみを抜き出しているという考えです。 (3) enemy.OnDead.Subscribe() enemy.OnDeadとSubscribe()に分解して考えます。 enemy.OnDead RxをPub/Subパターンで捉えてみるの解釈ではObservableはBrokerとなるので、それを説明する文を作りました。 An observable one called OnDead is a broker for messages published on the enemy’s being dead. →OnDeadと呼ばれる観察可能なものは、敵が死んだ時に発行されるメッセージの仲介者です。 (1)と同じで、以下の部分以外はボイラープレートです。 OnDead - プロパティ名 enemy - インスタンス名 being dead - イベント発火タイミング Subscribe() RxをPub/Subパターンで捉えてみるの解釈では、Subscribe()はObservableに対して購読の手続きを行うように命令しているのでした。 これを説明するように英文を組み立てます。 自然な文となるように、今度はJaneにOnDead(=Observable)になってもらいます。 Jane, start procedure for subscribing to messages. →ジェーンさん、メッセージを購読する手続きを開始します。 命令文として訳してほしいところですが、残念ながら平叙文になってしまいました。 とりあえずそのまま貼っておきます。 (4) Subscribe(onNext: _ => this.OnEnemyDead()) Subscribe()の引数であるonNext: _ => this.EnemyDead()の部分はこのようになります。 Playerの代表はJackに務めてもらいます。 Jack, on next message's having been published, do the process on enemy's being dead. →ジャック、次のメッセージが公開されたら、敵が死んだときの処理をしてください。 こちらも以下の部分以外はボイラープレートです。 enemy - インスタンス名 being dead - イベント発火タイミング 文を繋げると… (1)〜(4)の英文とその訳を繋げました。 便宜上付与したJohn等の名前はメンバ名に戻し、理解しやすいように少し日本語訳に手を入れました。 A subject of onDead is messages published on the enemy’s being dead. "onDead, do the process for on next message's having been published. " An observable one called OnDead is a broker for messages published on the enemy’s being dead. "OnDead, start procedure for subscribing to messages." "Player, on next message's having been published, do the process on enemy's being dead." onDeadの観測テーマは、敵が死ぬことで発行されるメッセージです。 「onDead、次のメッセージが公開された時の処理をしてください。」 OnDeadと呼ばれる観察可能なものは、敵が死んだ時に発行されるメッセージの仲介者です。 「OnDead、メッセージを購読する手続きを開始してください。」 「Player、次のメッセージが公開されたら、敵が死んだときの処理をしてください。」 これだけで仕様を説明する文章を作ることができました。 おわりに 補完しているしている語句が多いので、こじつけのように感じられるかもしれません。 しかし、補完している部分は、クラス名やインスタンス名、イベントの内容が変わってもそのまま使えます。 このため、場面によって変わる部分のみコードに記載し、共通部分は脳内でテンプレート化しておいて随時脳内補完するという整理も可能なのではないかと思います。 この脳内補完と翻訳がスムーズに行えるようになると、プログラムを理解する速度が速くなると思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AzureKinectをUnity Humanoidにアタッチするためのメモ

Unityでアバターを動かす必要があったためAzureKinectの骨格検出を利用してのアタッチを試みた。 AzureKinect自体の環境構築は別記事。 Azure-Kinect-SamplesにUnity他、BodyTracking系の様々なサンプルプログラムが格納されているのでクローン Azure-Kinect-Samples/body-tracking-samples/sample_unity_bodytrackingにあるREADME.mdを読みながらUnityプロジェクトの環境構築。事前にAzureKinect自体の環境構築が必要。 3)のMoveLibraryFiles.batを実行中に2つのファイルが見つからないエラーが出るが、問題なかった。 自分の場合、いくつかのファイルがリスト通りに配置されないものもあったのでリストと目grepしながら問題ないか確認する。 Unityを起動してプロジェクトフォルダを開き、Kinect4AzureSampleSceneを実行するとrtx30系に起因するエラーが吐き出された。SkeletalTrackingProvider.csの46行目、 SkeletalTrackingProviders.cs (46) using (Tracker tracker = Tracker.Create(deviceCalibration, new TrackerConfiguration() { ProcessingMode = TrackerProcessingMode.Gpu, SensorOrientation = SensorOrientation.Default })) をTrackerProcessingMode.Cudaに変更することで解決した。 参考になったissue これで、動いた 骨格がきちんと表示されればOK 次にAzureKinectのBoneIdをUnityのHumanoidのIdにアタッチさせてポジションをリンクさせる。それぞれのIdは以下参照。 https://docs.microsoft.com/ja-jp/azure/kinect-dk/body-joints https://docs.unity3d.com/ScriptReference/HumanBodyBones.html HumanBodyBones enumの中身は以下(記述が冗長なのはご愛嬌...) #region アセンブリ UnityEngine.AnimationModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // C:\Program Files\Unity\Hub\Editor\2021.1.15f1\Editor\Data\Managed\UnityEngine\UnityEngine.AnimationModule.dll #endregion namespace UnityEngine { // // 概要: // Human Body Bones. public enum HumanBodyBones { // // 概要: // This is the Hips bone. Hips = 0, // // 概要: // This is the Left Upper Leg bone. LeftUpperLeg = 1, // // 概要: // This is the Right Upper Leg bone. RightUpperLeg = 2, // // 概要: // This is the Left Knee bone. LeftLowerLeg = 3, // // 概要: // This is the Right Knee bone. RightLowerLeg = 4, // // 概要: // This is the Left Ankle bone. LeftFoot = 5, // // 概要: // This is the Right Ankle bone. RightFoot = 6, // // 概要: // This is the first Spine bone. Spine = 7, // // 概要: // This is the Chest bone. Chest = 8, // // 概要: // This is the Neck bone. Neck = 9, // // 概要: // This is the Head bone. Head = 10, // // 概要: // This is the Left Shoulder bone. LeftShoulder = 11, // // 概要: // This is the Right Shoulder bone. RightShoulder = 12, // // 概要: // This is the Left Upper Arm bone. LeftUpperArm = 13, // // 概要: // This is the Right Upper Arm bone. RightUpperArm = 14, // // 概要: // This is the Left Elbow bone. LeftLowerArm = 15, // // 概要: // This is the Right Elbow bone. RightLowerArm = 16, // // 概要: // This is the Left Wrist bone. LeftHand = 17, // // 概要: // This is the Right Wrist bone. RightHand = 18, // // 概要: // This is the Left Toes bone. LeftToes = 19, // // 概要: // This is the Right Toes bone. RightToes = 20, // // 概要: // This is the Left Eye bone. LeftEye = 21, // // 概要: // This is the Right Eye bone. RightEye = 22, // // 概要: // This is the Jaw bone. Jaw = 23, // // 概要: // This is the left thumb 1st phalange. LeftThumbProximal = 24, // // 概要: // This is the left thumb 2nd phalange. LeftThumbIntermediate = 25, // // 概要: // This is the left thumb 3rd phalange. LeftThumbDistal = 26, // // 概要: // This is the left index 1st phalange. LeftIndexProximal = 27, // // 概要: // This is the left index 2nd phalange. LeftIndexIntermediate = 28, // // 概要: // This is the left index 3rd phalange. LeftIndexDistal = 29, // // 概要: // This is the left middle 1st phalange. LeftMiddleProximal = 30, // // 概要: // This is the left middle 2nd phalange. LeftMiddleIntermediate = 31, // // 概要: // This is the left middle 3rd phalange. LeftMiddleDistal = 32, // // 概要: // This is the left ring 1st phalange. LeftRingProximal = 33, // // 概要: // This is the left ring 2nd phalange. LeftRingIntermediate = 34, // // 概要: // This is the left ring 3rd phalange. LeftRingDistal = 35, // // 概要: // This is the left little 1st phalange. LeftLittleProximal = 36, // // 概要: // This is the left little 2nd phalange. LeftLittleIntermediate = 37, // // 概要: // This is the left little 3rd phalange. LeftLittleDistal = 38, // // 概要: // This is the right thumb 1st phalange. RightThumbProximal = 39, // // 概要: // This is the right thumb 2nd phalange. RightThumbIntermediate = 40, // // 概要: // This is the right thumb 3rd phalange. RightThumbDistal = 41, // // 概要: // This is the right index 1st phalange. RightIndexProximal = 42, // // 概要: // This is the right index 2nd phalange. RightIndexIntermediate = 43, // // 概要: // This is the right index 3rd phalange. RightIndexDistal = 44, // // 概要: // This is the right middle 1st phalange. RightMiddleProximal = 45, // // 概要: // This is the right middle 2nd phalange. RightMiddleIntermediate = 46, // // 概要: // This is the right middle 3rd phalange. RightMiddleDistal = 47, // // 概要: // This is the right ring 1st phalange. RightRingProximal = 48, // // 概要: // This is the right ring 2nd phalange. RightRingIntermediate = 49, // // 概要: // This is the right ring 3rd phalange. RightRingDistal = 50, // // 概要: // This is the right little 1st phalange. RightLittleProximal = 51, // // 概要: // This is the right little 2nd phalange. RightLittleIntermediate = 52, // // 概要: // This is the right little 3rd phalange. RightLittleDistal = 53, // // 概要: // This is the Upper Chest bone. UpperChest = 54, // // 概要: // This is the Last bone index delimiter. LastBone = 55 } } 以上をもとにそれぞれをアタッチする必要があるとわかる。 具体的には、以下の記事を参考にさせていただき、実装した。 ひとまずここまでで実行できる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Unity]Live Photosを作成する

Unity の iOS 実機で Live Photos を作成する Unity の RenderTexture から Live Photos を作成する事ができました Unityからlive photosの保存できた! pic.twitter.com/2YUFStIUj2— ふじき (@fzkqi) July 23, 2021 リポジトリ リポジトリはこちら アセットの導入 Examples/UnityExample/Assets/Plugin/VideoCreator をコピーしてプロジェクトに取り込みます Live Photos を作成する Live Photos の実体は mov と jpeg ファイルです それぞれ同一の Content Identifier を設定する必要があります そこで、mov の作成の時に、uuidを生成し渡します string uuid = System.Guid.NewGuid().ToString(); string cachePath = "file://" + Application.temporaryCachePath + "/tmp.mov"; MediaCreator.InitAsMovWithAudio(cachePath, "h264", width, height, uuid); マイクロ秒で時刻を指定して、録画を開始します long startTimeOffset = 0; MediaCreator.Start(startTimeOffset); Texture を動画に書き込みます サンプルでは RenderTexture を利用しています Texture texture = Get Texture; long time = startTimeOffset + Elapsed time from Start; MediaCreator.WriteVideo(texture, time); 書き込みを終了します Live Photos には時間制限があるので注意です MediaCreator.FinishSync(); mov が指定されたパスに保存されているので、サムネイルに使う texture と動画と同じ uuid を指定して Live Photos を保存します MediaSaver.SaveLivePhotos(texture, uuid, cachePath); 終わりに Unity から見た時にシンプルなインタフェースで、Live Photos を作成させる事ができました Live Photos は時間の制限などありますが、iOS 固有の機能などで活用して行きたいです
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む