20200720のUnityに関する記事は5件です。

Empty path name is not legal.(Unity,C#) の 意味と エラー対処

Unity(C#)でファイル書き込みをしようとした際にエラーが出ました.
あまりUnityやC#について日本語で書かれているものが見つからなかったので,残しておきます.

Empty path name is not legal. とは

これで検索をかけたところファイル名に使用できない文字が含まれていないか?
という原因がありましたが,
自分の場合は呼び出し位置の変更によってエラーが出たため、
ファイルパスには問題がないことが分かっていました。

⇒Empty path name is not legal.
 は単純に和訳しても「空のパス名は違法です」なので,
 上記で言っていることは全く違いますね……
 全然日本語の記事が見つからなかったので,
 素直に英文の意味を考えればこんなに悩むエラーでもなかったです.反省. 

エラー箇所

エラーが出たのは下記の記述部分でした.
最初はa,b,cを同じ関数の中で定義していたことから,
関数に引数を渡す時点(もしくは渡す前)に文字コード周りで
エラーが起きているのかな?と思いましたがそういうわけでもなく……

hoge.cs
public void WriteHeader(string a,string b,string c){
 using (StreamWriter sw = new StreamWriter(filepath, false, Encoding.GetEncoding("Shift_JIS")))
 {
      string[] s1 = { a,b,c };
      string s2 = string.Join(",", s1);
      sw.WriteLine(s2);
 }
}

結局,原因は?

Unityでありがちな問題ですがStart()の実行順序関連でした.
自分の場合はfilepathを同じクラスのStart()で定義しており,
それより前に別のクラスからWriteHeader()関数を呼び出しているため,
「FilePath」が見つからない,というようなエラーだったようです.
(それならもっと他のエラーが出てもよさそうな気はしますが……)

しかし,Start()の実行順は確か決まりがなかった気がするけど,
どうやって確実に元ファイルのStart()を実行後にこの関数を呼び出せるだろうか?
ということで調べなおしてみたところこんな記事がありました.
https://ekulabo.com/execution-order
どうやらスクリプトの実行順をEdit>Project Settingsから設定できるようです.

よくここまでこれ無しでやってきたもんだな……という便利さなので,
使ったことのない人,同じようなエラーで実行順に悩んでいる人がいたら(いるのか?)
ぜひ一度お試しいただければと思います.

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity 3D入門 #5 [メッセージウィンドウの作成]

ゲーム作成に不可欠なメッセージウィンドウを作ります。

UI->Panelを作成し、そこにテキストを追加したいと思います。
参考URL:https://xr-hub.com/archives/11782

参考URLに従い作成している途中、下のような画面となり、何か失敗したかと思いましたが、Gameビューで見ると、2枚目のように表示されていたので問題はなさそうです。
スクリーンショット 2020-07-20 17.41.29.png

スクリーンショット 2020-07-20 17.42.55.png

また、メッセージウィンドウを出し入れするプログラムを書きます。
プログラムはプレイヤーにアタッチし、特定のキーを入力することで表示/非表示されるようにします。

オブジェクト検索の参考URL:https://marunouchi-tech.i-studio.co.jp/2266/
キー入力参考URL:https://tech.pjin.jp/blog/2015/09/30/unityのキー入力まとめ-~inputクラス~/
キーコード参考URL:https://docs.unity3d.com/ja/2019.4/ScriptReference/KeyCode.html

しかし、下のようなコードを書いた場合、問題が発生しました。

void Update()
    {
        if (Input.GetKeyDown(KeyCode.I)){
            if (messagePanel.activeSelf){
                messagePanel.SetActive(false);
            }else{
                messagePanel.SetActive(true);
            }
        }
    }

一度「i」を押しただけで二回コードが呼ばれ、messagePanelのsetActiveがtrue->false->trueのように一瞬で変更され、結局メッセージウィンドウが表示され続けてしまいました。

>上のスクリプトを二つ別々のオブジェクトにアタッチしていたことが問題でした。

最後に、次に向けてタイマーを画面上に表示させようと思います。
タイマー作成参考URL:https://techacademy.jp/magazine/9311

float countTime = 0;
void Start() {
    Timer = GameObject.Find("Timer");
}
void Update() {
    countTime += Time.deltaTime; //スタートしてからの秒数を格納
    Timer.GetComponent<Text>().text = countTime.ToString("F2"); //小数2桁にして表示
}

簡単に書くと上のように実装。

GetComponent()でエラーが出た時の参考URL:https://monaski.hatenablog.com/entry/2015/11/03/125957

ezgif-7-676c0b901692.gif

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】 UI ElementsとUI BuilderでメニューのUIを作ってみた

Writer: Nhân
Translator: Yosuke Okusa
Director: Yosuke Okusa
Date: 2020-07-23

使ったバージョン

Unity LTS4.3f1
UI Builder 1.0.0

「UI Elements」とは?

UnityでのUIの作り方
UI Elementsとは、エディタおよびランタイムのUI開発向けにデザインされたフレームワークのひとつです。
UIの作り方として、これまでUnityには以下のようなやり方がありました。

  • IMGUI: エディタ拡張で使われるコードベースの方法。
  • uGUI: ランタイムUI向けにUnity 4.6で実装された方法。

しかし、これらの方法は次のような問題があります。 

・パフォーマンスが十分に上がらない。
・デザインとコードを同一ファイルに書く必要がある。
・そもそもC#とUnityに慣れていないと扱うのが難しい。

UIElementsでできること
従来のやり方に対して、UI Elementsには以下の特徴があります。

・新しいUIの仕組みである。
・エディタとランタイムのためにデザインされている。
・UXML/USS/C#など、WEB系(XML/CSS)に近い構築方法。
・パフォーマンスが高い。

UI Elementsの下準備

3つの基本

上記でちらっと触れましたが、次の3つが基本構造になります。
それぞれ別ファイルで管理します。

  • UXML:階層構造の定義
    uxml.png

  • USS:デザイン
    uss.png

  • C# Script:コード(イベント定義など)

また、こちらのチュートリアルが分かりやすくておすすめです。↓

Unity : https://learn.unity.com/tutorial/uielements-first-steps#
raywenderlich : https://www.raywenderlich.com/6452218-uielements-tutorial-for-unity-getting-started

UI Elements触ってみました

今回は上記チュートリアル内容を、UI Builderを使って実践していきます。

UI Builder とは:

・公式から出ている、UI Elementsのためのツール。
・UXMLやUSSを作成できる。
・Package Managerから参照できる。

公式から出ている便利ツールといったところでしょうか。
さっそく使っていきましょう。

UI Builderの操作

  1. Unityエディタから、 Open Window > Package Manager > Install Package UI Builderと選択していく。
    ui_install.png

  2. ランタイムで動作するように、"com.unity.ui.runtime": "0.0.4-preview" を manifest.json に追加する。
    import_runtime.png

  3. Window > UI から、UI Builderのウィンドウを開く。
    uibuilder.png

  4. ドラッグ&ドロップでUXMLとUSSを作成・調整し、インスペクタのプロパティを調整する。

  5. シーンにUXMLを追加するか、カメラに紐づける。
    後者の場合、PanelRenderer.csが紐づけられたゲームオブジェクトを使う必要があります。
    panel_renderer.png

できたもの

こちらが上記チュートリアルでUI Builderを使って作ったメニューです。いかがでしょうか?
example1.png

example2.png

まとめ

今回チュートリアルでメニュー完成まで漕ぎ着けましたが、実際に触ってみると、下記のようにいくつかバグや問題に直面しました。

  • インスペクタでフォントを変えるとUnityがクラッシュした。
  • プロパティ編集中、PositionをAbsoluteにしたらUnityがフリーズした。

ここまでを踏まえて、UI Elements/UI Builderを使ってUIを作ってみて感じたことをまとめてみました。

良かったところ ダメだったところ
設定が簡単。 まだ開発中のツールなので、現状の仕様から変更される可能性がある。
エディタを速く作れて時短になる。 UI Builderのインスペクタをいじるとバグが起こることがある。
構造がハッキリしていて分かりやすい。 インスペクタのプロパティがまだ完全ではない。

開発段階なので、不具合があるのは当然ですが、現状では実製作での利用にはまだ使えないことが分かりました。
Unityエディタのフリーズなど致命的なバグがあり、リリースバージョンの完成を待つ必要がありそうです。

というわけで、UI Elements/UI Builderを触ってみての総括はこんな感じです。
生産性が高く、エディタ拡張にも便利ですが、まだ開発段階というのが拭えないので、
UI Builderを開発に使うなら安定版のリリースを待った方がいいと思いました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Azure KinectのBodyTracking公式サンプルをUnityで動かしてみる

はじめに

Azure Kinectを使ってUnity上でBodyTrackingをする方法を解説しようと思います。
実は前にこの内容のLTをしたのですが、リポジトリに色々変更が入ったりして、せっかくなので記事にもまとめようと思いました。

LTスライド:Azure Kinect+Unityで軽率にBodyTrackingする

TL;DR

結果的に、下の動画のように人の骨格を認識してUnityのオブジェクトに反映させるまでができます。

ezgif-7-7554c637cf9f.gif

対象の読者

基本的に以下のような方をターゲットにしていますが、以下に当てはまらなくてもわかりやすいように解説するつもりです。

  • AzureKinectでボディトラッキングしてみたいひと
  • UnityでAzureKinectを触ることに興味がある人
  • AzureKinectで何ができるのかを知りたいひと
  • VTuberなどのトラッキング技術に興味がある人

扱わないこと

本記事は、公式サンプルを使ってボディトラッキングを動かすまでを目的としていますので、特にサンプルを発展させて何かをするようなことはしません(いずれ別記事にしたいですが)

  • AzureKinectSensorSDKやBodyTrackingSDKのインストール
  • キャラクターモデルを動かす方法
  • 点群を扱う方法
  • Windowsフォームアプリケーションでの実装(WPFとかUWPとかC++とか)

検証環境

今回の記事の内容は以下の環境で動作したものになります。

環境
OS Windows 10 Home
CPU Intel Core i7-7700
GPU GeForce GTX 1060 3GB(k4a動作非推奨)
Unity 2019.1.2
Sensor SDK 1.4.0
BodyTracking SDK 1.0.1

また、今回の動作を確認したのはmicrosoft/Azure-Kinect-Samplesの7/20現在のmasterブランチのコミット04b874...になります

AzureKinectのBodyTrackingをUnityで

AzureKinectとは?

一応AzureKinectとはいったい何なのかを簡単にご紹介しておきます。
AzureKinectとはMicrosoftが開発しているセンサーデバイスです。通常のカメラのようにRGB画像の取得に加え、深度情報の取得や骨格認識を可能にします。もともとKinectというデバイスをご存知の方は多いかもしれませんが、AzureKinectは一番新しいバージョンになります。

image.png
Microsoft Windows公式ブログより

AzureKinectのイマ

AzureKinectは2020年7月現在SensorSDKは1.4.1、BodyTrackingSDKは1.0.1がリリースされています。従来のKinectよりも高解像度のセンサ、高性能の推定エンジンを備えており、もともとXboxのセンサデバイスとして開発を始められたKinectですが、いまは汎用分野の開発向けにSDKが公開されています。(AzureKinectのXBox対応はまだ実装されていなかった気がします。いつの間にかターゲットが逆転していて面白いですね)
現状ネットの記事などはまだ少ないですが、MS公式のドキュメントは結構充実していていい感じです。(ホンマか?)
あと、ハイスペックPCでの動作が推奨されています。基本的にはGPUを積んでいるPCで、推奨はGTX1070以上のスペックを要求されています。(この時点で私の環境(GTX1060)は非推奨なのですが...)
ただ、前に上がったissueで「ロースペックマシンでも動作するようにしよう!」みたいな構想があるらしく、今後の開発に期待です!

Microsoft公式のサンプル環境を整える

ここではAzure Kinect Sensor SDKやAzure Kinect Body Tracking SDKの環境構築は終わっていることを前提とします。これが終わってない方はこちらこちらのドキュメントを参照しながら環境構築を行ってください。公式のViwerがございますのでそれが動いたら大丈夫です。
さてではサンプル環境を整えていきましょう。以下の手順で実行できます。

  1. GiHubからサンプルリポジトリをcloneする
  2. NuGetパッケージをインストールする
  3. ファイルを移動する
  4. ビルドする

実は今から説明する手順はこちらのREADME(英語)にすべて書かれていますので、そちらを確認してしていただいても大丈夫です。

まずこちらのmicrosoft/Azure-Kinect-Samplesというリポジトリをcloneします。このリポジトリにはUnity以外のサンプルも同梱されておりますので、そのままUnityHubでは開けません。Unityプロジェクトの場所はAzure-Kinect-Samples/body-tracking-samples/sample_unity_bodytracking/になります。現時点でUnityのバージョンは2019.1.2で開発されているみたいです。

image.png

開いてみると以下のような画面になると思います。コンソールを見てみると何やらエラーが出ているみたいですが、パッケージの依存関係によるものなのでそれを解決していきましょう。

image.png

Azure Kinect SDKのパッケージはNuGetからインポートできます。
NuGetからパッケージをインストールするためにUnityプロジェクトをVisual Studioで開きましょう。デフォルトのIDEがVSになっている方はそのままで結構ですが、そうでない方は[Eidt]->[Preference]->[External Tool]からエディタをVisual Studioに変更し、[Assets]->[Open C# Project]を選択し、Visual Studioを開きます。
Visual Studioを開いたらNugetパッケージをインストールしましょう。公式のREADMEではパッケージコンソールからコマンドをたたくよう指示されていますが、ソリューションを右クリックして[NuGetパッケージの復元]を選択すれば依存関係がインストールされるので、そうする方が簡単です。パッケージのインストールが完了したらVisual Studioは閉じてもらっても構いません。

image.png

そしたら、次にdllの移動を行います。とはいえバッチファイルを実行すれば良しなにしてくれるので、プロジェクトのルートディレクトリにあるMoveLibraryFiles.batを実行してください。
ここまでくればコンソールのエラーが消えているはずです。

image.png

それではAssets/Scenes/Kinect4AzureSampleSceneを開いて再生してみましょう。すると赤い棒人間みたいなものが自分の動きに追従しているのがわかるでしょうか?
見事Unity上でAzure Kinect のボディトラッキングを実行できました!
シェー(特に世代とかではないです)
image.png

トラブルシュート1:NuGetForUnityでインストールした

NuGetパッケージと聞いて、NuGetForUnityを思い浮かべる方もいると思います。自分は最初パッケージをNuGetForUnityを使っていストールした結果、動きませんでした。かならずVisual Studioからインストールするようにしましょう。

トラブルシュート2:nugetパッケージのインストールに失敗する

Azure Kinect BodyTracking SDKはそれ自体の名前空間の階層が深いせいで、ちょっと階層の深いディレクトリにUnityプロジェクト本体があった場合インストールに失敗するケースがあります。自分はいつものワーキングディレクトリで実行したらダメでした。

ビルドしてみる

それではプロジェクトをビルドしてみましょう。とりあえず通常のWindowsのスタンドアロン向けにビルドします。

image.png

そのあとにビルド先のフォルダに、以下のファイルをコピーしてください。これらはプロジェクトの直下にあったものと同じです。

  • cublas64_100.dll
  • cudart64_100.dll
  • cudnn64_7.dll
  • dnn_model.onnx
  • onnxruntime.dll

画像のようになると思います。
image.png

それができたら起動してみましょう。ビルドしても実行できていることが確認できたと思います。コロンビア

image.png

PuppetMasterについて

Assets/Scenesの中にはもう一つPuppetMasterというサンプルシーンがあると思います。こちらはHumanoidリギングされたアバターに対してAzureKinectのボディトラッキングを適用してモーションキャプチャさせたように動かしてみよう!みたいなサンプルになっているのですが、こちらのシーンが結構流動的に変わっていて動作も不安定なので今回は触れないでおこうと思います。(自分が触ったときには色々いじらないと動かなかった)

おわりに

いかがでしたか?(天下無双)
本当はビルドしたプロジェクトが終了時にクラッシュするバグについての対処法とか書こうと思ったんですが、一週間前にfixされていました、残念。(良いこと)
AzureKinectの情報を追っているとモーションキャプチャ利用を視野に入れているようなアナウンスがたびたび見られるので、今後Unityを組み合わせることでVTuberシステムであったりゲームのキャラクターアニメーションであったりを制作できるかもしれません。
そういえば3tene ProがAzureKinectのモーションキャプチャに対応したという発表もありましたね。今後の開発動向に注目です。
個人的にde:code2020の「Azure Kinect DKテクニカルTips」というセッションがすごく良かったのでそちらもよかったらご覧ください。

P.S. 自分の環境だけなのかわからないのですが、なぜかこのプロジェクトを実行した時にAzureKinectの白いランプがつきませんでした。動作に影響はないもののちょっと気になります。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityで、Instantiateの「引数で座標を指定する」のと「戻り値を使って設定する」のは挙動が違う可能性がある

環境

Mac , Unity 2019.4.2f1で実験しました。

結論から言うと

Instantiateで生成と同時に座標を設定したほうが良い

var obj = Instantiate(cube, new Vector3(1, 1, 0), Quaternion.identity);

生成と同時に座標を設定する場合はこの2つの方法が考えられます

引数に指定
var obj = Instantiate(cube, new Vector3(1, 1, 0), Quaternion.identity);
戻り値で指定
var obj = Instantiate(cube);
obj.transform.position = new Vector3(1, 1, 0);

https://docs.unity3d.com/ja/2020.1/ScriptReference/Object.Instantiate.html

とくにInstantiateは引数の組み合わせが多く、(何故か座標だけで設定できない)
第3引数にQuaternion.identityも設定するか、
Instantiateの戻り値を使って設定することになります。

後者のほうが見慣れないQuaternionを使わなくてもいいので特に初心者はわかりやすいと思ってしまうかもしれません。

同じフレーム内で設定しているはずなのでどちらも同じように見えますが実はこの2つは挙動が変わってしまうときがあります。

検証

適当に3Dオブジェクトを作り、Rigidbodyをつけました。

image.png

image.png

このような検証コードを書きました。

検証コード
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameController : MonoBehaviour
{
    public GameObject cube;


    private GameObject obj;

    // Update is called once per frame
    void Update()
    {
        if (obj != null)
        {
            RaycastHit hit;
            var raycastHits = Physics.RaycastAll(new Vector3(1, 10, 0), new Vector3(0, -1, 0));
            foreach (var raycastHit in raycastHits)
            {
                Debug.Log(raycastHit.collider.gameObject.transform.position);
            }

            Debug.Log(raycastHits.Length);

            if (raycastHits.Length == 0)
            {
                // レイキャストにヒットしなかった
                Debug.Break();
            }


            Destroy(obj);
            obj = null;
        }
        else
        {
            if (Input.GetKey(KeyCode.Space))
            {

                // A
                obj = Instantiate(cube);
                obj.transform.position = new Vector3(1, 1, 0);

                // B
                // obj = Instantiate(cube, new Vector3(1, 1, 0), Quaternion.identity);

                Debug.Log("put");

            }
        }
    }

    private void FixedUpdate()
    {
        Debug.Log("FixedUpdate");
    }
}

スペースキーを押したらオブジェクトを生成して、

(1, 1, 0) にオブジェクト生成され、生成されて次のゲームフレームで
Physics.RaycastAllで (1,10,0) から (0, -1, 0)方向に向かってRayを投げてます。

(1, 1, 0)に生成されているのであれば当たるはずです。

レイキャストがヒットしない?

Aとなっている方(上のコードそのまま)を動かしたら
スペースを押しっぱなしにしたときにいずれUnityが一時停止すると思います。
(一時停止をするのは Debug.break() の影響)

raycastHits.Length == 0 になっている つまりレイキャストがヒットしなかったということになります。

つまり、 (1,1,0) にオブジェクトがいないみたいです。  
ちなみにobj.transform.position を見てみると (1,1,0)には、いるみたいです。

すぐ止まるときと止まらないときの差を調べてみると、上のコードでもしれっと書いてあるFixedUpdate が重要なことがわかりました。

意図した挙動のときのログ

image.png

putはオブジェクトを生成したとき,

「座標」と「最後の1」はレイキャストの接触したオブジェクトの座標とヒット数ですが、これは次のゲームフレームで呼ばれています。

その途中で「FixedUpdate」が呼ばれています。

FixedUpdateについては他の記事に参考にしてほしいのですが、物理演算の前に呼ばれるものであり、ゲームのフレームレートとは無関係に呼ばれます。

https://qiita.com/yuji_yasuhara/items/6f50ecdd5d59e83aac99

意図しない挙動のときのログ

一方 Unityが一時停止したとき (レイキャストが反応しなかったとき)はputの直後に0 (レイキャストがヒットしなかった)が出力されています。

image.png

このときに「FixedUpdate」が途中で呼ばれていないことがわかります。

つまり、物理演算がされていないことがわかります。

一時停止するときは、すべてこうなっていたため、これが原因だと言えそうです。

Instantiateの引数で座標を与えたとき

AをコメントアウトしてBだけを使うようにしてみると、つまり下のコードを使う

obj = Instantiate(cube, new Vector3(1, 1, 0), Quaternion.identity);

Unityが一時停止することはありませんでした。

ログを見ると 「FixedUpdate」 が挟まっていないこともありましたが ちゃんと1つ見つかっています。
image.png

つまり、物理演算が挟まっていなくても大丈夫のようです。

同じゲームフレーム内でやってみると

先程はあえて別のゲームフレームでやっていましたが、
同じフレームでやってみました。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameController : MonoBehaviour
{
    public GameObject cube;


    private GameObject obj;

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKey(KeyCode.Space))
        {

            // A
            obj = Instantiate(cube);
            obj.transform.position = new Vector3(1, 1, 0);
            Debug.Log("put");

            // B
            // obj = Instantiate(cube, new Vector3(1, 1, 0), Quaternion.identity);

            var raycastHits = Physics.RaycastAll(new Vector3(1, 10, 0), new Vector3(0, -1, 0));
            foreach (var raycastHit in raycastHits)
            {
                Debug.Log(raycastHit.collider.gameObject.transform.position);
            }

            if (raycastHits.Length == 0)
            {
                Debug.Break();
            }

            Destroy(obj);
        }
    }

}

するとAのときは、止まらなかったのに対して、 Bの方はほぼ確実止まるような感じでした。

結論(予想)

  • Instantiateの引数で座標を与えたときは、その瞬間に処理がされるのか 物理演算に認識される状態になります。

  • 座標を与えない場合(0,0,0) に置かれ (0,0,0)としては認識する模様。
    その後すぐに

obj.transform.position = new Vector3(1, 1, 0)

としても変数上では座標は移動しても物理演算的には移動していない。

Updateの後に「FixedUpdate」が呼ばれた場合の物理演算処理で初めて、その座標で認識される状態になる。

そのため、タイミングが悪くFixedUpdateが呼ばれない状態だった場合、
何故かたまにバグが起こるみたいになってしまうようです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む