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

【Unity Q&A】シーン内オブジェクト等の元データを調べたい/地震を実装したい/物理系コンポーネントの要不要について

自分が関わっているプロジェクトの関係で、後輩からいくつか質問を受けたので、ここに回答を書きます。自分も Unity ライトユーザーなのでご指摘あればどうぞ。 Hierarchy ウィンドウにあるオブジェクト等の元データを調べたい 原文は「■■■(筆者の名前)さんが作ったものに使われている「人間」はどのパックを使っているのか」ですが、せっかくなので自分で調べる方法を書いておきます。(というか、どれのことを言っているのか情報がなかった。) この話をするには、まず Unity におけるアセット等のフォルダ構成が一般的にどのようなものか共有しておくべきかもしれません。 インポート済みのデータは基本的に Project ウィンドウから閲覧できるようになっています。最上位に Assets および Packages の2つのフォルダがあり、おおよそ、エディタ利用者が直接扱わないものは Packages、閲覧や編集を活発に行うものは Assets に配置されます。(この振り分けはアセットないしパッケージの開発者が設定する部分です。) さて、Hierarchy 上に配置されるものは大抵、Assets フォルダの配下にありますが、Hierarchy 上(シーン内)に配置されたオブジェクトや、そのテクスチャを探すのに少し手間取ることもあると思います。というのも、Unity の Assets におけるフォルダ構成はエディタ利用者が自由に変更できるため、想定されていない配置になっている可能性もあるからです。 ただ、個々人のフォルダ構成の流儀には色々あるとはいえ、普通はフォルダ名にソースに関わる情報を記述するはずです。アセットストアで配布されているアセットも、少なくともトップレベルのフォルダには、パブリッシャーないしアセットの名称といった、ほかのアセットと混合しない Unique な(一意に識別できる)名前が採用されています。 少し遠回りになりましたが、つまり「どのパックを使っているのか」は、そのデータがどのフォルダに所属しているのかを見ることで分かることが多いということです。逆に分からないものが混じっていた場合は、内部での実験用として使うに留め、誤って外部に公開しないよう適切に管理するか、いっそ削除する必要があります。 ところで Hierarchy 上のオブジェクトを見ても、それが Assets 配下のどこにあるのか分からない/忘れてしまった場合はどうすれば良いのでしょうか?もう、そのオブジェクトは出典不明としてお蔵入りさせるしかないのでしょうか? 救済策はあります。Inspector ウィンドウです。Inspector ウィンドウは選択中のオブジェクトの詳細設定を行うだけでなく、実は元データの位置を示すリンクも載せています。確認してみましょう。 手元の Unity プロジェクト(Project ウィンドウではありません)を UnityHub から開き、Hierarchy ウィンドウから、どれでも良いので青いキューブが添えられたオブジェクトを選択します。Inspector ウィンドウにはそのオブジェクトに関する各種設定項目が表示されています。 Inspector の上端に目を移しましょう。Tag や Layer の設定の下に項目があります。Prefab や Variant あるいは Model と書かれている項目があり(これは対象の設定によって違います)、その横に Open | Select ボタンが配置されています。 Open は元データである Prefab を直接編集したり、3Dファイルであれば、該当ファイルを専用のビューアー等で直接閲覧する際に使うボタンです。そして Select こそ、今回必要としていた元データの位置を示してくれるリンクボタンです。クリックすると Project ウィンドウ内の適切なフォルダが展開され、該当データがハイライトされます。 ちなみに Ovverrides は同じ Prefab を利用している他のオブジェクトに、選択中のオブジェクトの変更を同期させるボタンです。 ようやく話が繋がりました。まとめると「Hierarchy で対象を選び、Inspector のリンクから Project ウィンドウに飛んで、フォルダ名や構成から、ソースを推定する」というのが一連の手順になります。 でもちょっと待ってください。オブジェクト表面に描かれた模様(マテリアルや、それを構成するテクスチャ)の元ファイルはどうやって探せばよいのでしょうか。これも Inspector から調べられます。 マテリアルに関する項目は Inspector の最下部にあります。「ナントカかんとか(Material)」と書かれた箇所の右側にあるケバブメニュー(︙1)を押下すると、Select Shader 等のメニューが出現し、Select Material という項目も出てきます。 これでマテリアルの所在が分かります。また、マテリアルに利用されているテクスチャの所在が知りたければ、該当マテリアルを Project から選択した際に Inspector に表示される項目から、添えられている画像部分をクリックすることでも該当ファイルがハイライトされます。 おおよそ、素材のソースを確認する方法は分かったでしょうか。 地震を実装したい こちらの回答は、もう少し焦点を絞ります。 Unity において地震を実装するということは、地盤のずれや振動、その伝搬をシミュレーションしたいというよりも、単に部屋などを前後左右に揺らしたいということだと思われるので、その方法についてざっくり書きます。 まず既存の実装を利用する方法が挙げられます。   テキトウに GitHub で検索したら上のリポジトリが見つかりました。YouTube のタイトルには「with real data」とありますが、出典は明かされていません。(それか、自分が見逃しているだけかも) データは用途に合わせて置き換える必要があります。詳しい実装内容は忘れましたが、たしか X-Z平面における加速度データが用意されていて、それを読み取って AddForce() で地震動を再現していました。加速度データは Resorces/Data/Earthquake 配下にあります。必要ならこれを置き換えましょう。 データは以下のサイトなどから取得できます。(防災科研は登録が必要だったかも?) ・気象庁|強震観測データ ・防災科学技術研究所 強震観測網(K-NET,KiK-net)  ・地震検索&ダウンロード なお、このシステムのコードは若干エンタープライズ気味で、初心者としてはメンテナンスがしづらいものがあります。というわけで、スクリプティングが少しでもできるのであれば、上記データをパースしたものを、順次 AddForce() していくシステムを自作すると良いです。 加速度データを変位に変換して MovePosition() を回しても良いのですが、普通に時間で二階積分するだけだと位置ずれが大きいです。バターワースフィルタでどうのこうのするらしいですが、具体的な式がよくわからなかったので強制変位を反映する方法は保留にしています。 AddForce() の場合も、そのままのデータを使っていると、どんどん位置がずれていきますが、物理演算を使っているので、バネで動きに制約を加えることができます。Configurable Joint なら伸縮・回転の制限を細かく設定できます。 ちなみに、バネをひとつ付けるだけだと、反動がなかなか収束せず、回転運動が生じます。移動方向を制限したバネで各方位から押さえつけるような構造にしておくと安定します。(スクリプトで制御しても良いのですが、精度が必要な案件でもないですし、書かなくて済むものは書きたくないので、自分はこうしています。) さて、自分で組み上げる際の注意点ですが、Unity の物理は わりと雑 速度優先なので、オブジェクト間の相互干渉をできるだけ避けたり、シンプルな構造を採用するほうが良いです。 なので部屋を直接揺らしたり、直接バネを取り付けたりせず、まずは上の挿入画像のように地震動を再現する機構のみ作り、その動きを部屋に同期させるようにすると良いです。 結局同期させるなら、部屋を直接操作したほうが良さそうに思うかもしれませんが、Rigidbody が効いた箱のなかに Rigidbody を入れると箱やオブジェクト同士の干渉がひどくて地震体験どころではなくなります。何もしなくても本棚から本が飛び出て、椅子が転がり、机が跳ね回るならまだ良くて、設定次第ではあらゆるオブジェクトが爆発四散します。(あくまで設定次第ですが。) 箱(部屋)のなかのオブジェクトの挙動をある程度安定させるには、箱の「面」が物理的な反動を持たないようにしておく必要があります。そのため、箱には Rigidbody をかけつつも、当該コンポーネントにて isKinematic を True に(Inspector 上では✅)しなければいけません。 こういった諸設定を行ったうえで、加速度データに沿って AddForce() された地震動オブジェクトを参照し、MovePosition() で位置を同期すると、地震動を簡易的に再現できます。 物理系コンポーネントの要不要について Rigidbody や Collider を付けるべきオブジェクトはどう考えれば良いでしょうか? 単純な話、とりあえずシーンを再生(プレイ)してみて、なにか不都合があったときに、その問題に応じて必要なコンポーネントを設置すれば OK です。物理演算は軽くはないので、利用せずに済むなら、そうすべきだからです。一方、今回は地震を扱うということもあり、インタラクティブ性を維持するには物理系コンポーネントを多用することになると思います。 例えば、上の章では、地震動を再現する部分と、その動きに同期して揺れる部屋の部分と、それぞれに Rigidbody がアタッチされることを前提に書きました。もし部屋のほうに Rigidbody がなく、単に Transform コンポーネントの position プロパティの更新を直接行った場合、部屋の壁や床だけが動いて、家具類がまったく動かない、という状況が起きたりします。 これは仕様上、位置更新は実質テレポートであり、物理的干渉が観測できないことが原因です。確実に物理干渉を起こすには、Rigidbody コンポーネントの AddForce() メソッド or MovePosition() メソッドから対象を操作する必要があります。また、こうした物理系の処理は Update() メソッドではなく、物理演算のタイミングと同期できる FixedUpdate() メソッド内で実行することが一般的です(要件によっては例外あり)。 さて、質問の原文は「家具などを配置しましたが、重力や当たり判定などは付ける必要があるのか」でした。すでに述べたように、これはケースバイケースです。自分で動いてほしい(周囲の状況に反応してほしい)オブジェクトには Rigidbody を付ける必要があります。また、衝突判定や接触判定を反映させるためには、Collider が必要です。 次の例を考えてみて下さい。本棚が一つあり、なかにはいくつかの本や小物が入っています。このとき、どのオブジェクトにどのようなコンポーネントが必要でしょうか。もし、よく見るようなシンプルな脱出ゲームであれば、isTrigger にチェックを入れた Box Collider と、接触判定に応じて任意の処理を実行するスクリプトコンポーネントが棚にだけアタッチされていれば間に合いそうです。単に 3D で家具や部屋の内装をチェックするだけなら、それすら不要です。 逆に、棚を押したときに揺れたり倒れたりしてほしくて、また、内容物が(棚との相対座標・回転ではなく)慣性に従って動いてほしいのであれば、すべてのオブジェクトに Rigidbody と Collider が必要でしょう。(オブジェクト間の干渉がひどい場合は、部屋と同様に isKinematic を設定した外枠を併用する形式で対応できます。ほかにベターな方法はないものか…。) ところで、Mesh Collider を持つオブジェクトに Rigidbody を付けてシーンを再生すると、Mesh Collider を Convex に設定するよう警告が出ます。おそらく Unity が利用する NVIDEA の物理エンジン PhysX の仕様による問題だと思いますが、Convex にすると穴やくぼみが塞がれるため、オブジェクトの内部に Rigidbody と Collider を持ったオブジェクトを保持することが難しくなります。(そのままだと射出される。) Box Collider や Sphere Collider のようなプリミティブな Collider であれば、この問題は起きません。しかし、オブジェクトの形状に合わせて、複数の Collider を手作業でセット・調整するのは骨が折れます。そういった作業が必要ということなら、SA Collider Builder を使うことができます。 利用するアセットによっては、すでにこういったセッティングが済んでいるのですが、そうでない場合は上記のようなことを念頭にいじってください。 なお、物理演算が期待通りの挙動になっているかの確認には、Physics Debugger を使うことができます。また、あまりに早く動いてしまい、目視で状態を追えなかったり、インスペクター上の値の確認が間に合わなかったりする場合には、Edit > Project Settings > Time の Time Scale を小さい値に変更することで時間の流れを遅くできます。必要に応じて利用してください。 https://coliss.com/articles/build-websites/operation/work/name-of-menu-icons.html ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】ラムダ式とデリゲート型

C++でお世話になっていたラムダ式を、Unityでも利用したいと思い調べました。 C++のラムダ式 auto Func = [](){}; Func(); C#のラムダ式 Action Func = () => {}; Func(); C++ のようにいちいちデリゲート型を宣言せずに型推論で利用したいところですが、「var」にラムダ式で生成した関数を入れようとするとコンパイルエラーになるので、どうしても利用したい場合には補助メソッドを作る必要がありそうです。(追記:C# 10.0 ではすでに実装可能とのことです) 主なデリゲート(関数を入れる変数) Action Action<引数の型> Func<返り値の型> Func<返り値の型, 引数の型> ラムダ式やデリゲート型については下記サイト様が詳しく説明されています?  ➡ https://qiita.com/toRisouP/items/98cc4966d392b7f21c30
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UnityのインスペクターでEnumの一部項目を隠す方法

やりたい事 シリアライズされたEnumFieldの中身を変えずに、Editorで表示できる項目を制限したい: // サンプルEnumの定義 public enum ColorEnum { None = 0, Red = 1, Green = 2, Blue = 3 } そのままEditorで表示させる場合、すべての項目が選択可能 [SerializeField] ColorEnum myColor; このように、「HideEnumItem」という魔法Attributeをつける事で、Editorで表示された「myColor」から「None」と「Red」を隠したい [HideEnumItem("None", "Red"), SerializeField] ColorEnum myColor; 「HideEnumItem」という魔法Attributeは下記の「Custom Attribute」と「Custom Property Drawer」で用意する。 「Custom Attribute」を用意する 「Custom Attribute」はc#標準機能で、「SerializeField」のようなAttributeを自作することができます。 まずは通常のScriptsフォルダで下記の「HideEnumItemAttribute.cs」ファイルを作成: using System.Collections.Generic; using UnityEngine; // AttributeUsageで使用できる変数をクラスのフィールドに限定 [System.AttributeUsage(System.AttributeTargets.Field)] public class HideEnumItemAttribute : PropertyAttribute { // 隠したい項目を保存用 public HashSet<string> Filter { get; private set; } public HideEnumItemAttribute(params string[] filters) { Filter = new HashSet<string>(); for (var i = 0; i < filters.Length; i++) { Filter.Add(filters[i]); } } } 「Custom Property Drawer」を用意する 「Custom Property Drawer」はUnityEditorの機能で、Editorのインスペクター周りの描画をカスタマイズする事ができます。 上記のHideEnumItemAttributeを受け取って、指定された項目を隠す「HideEnumItemAttribute.cs」ファイルを作成(こちらはUnityEditorのAPIを使っているので、Editorフォルダに置く必要があります): using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; // 自作のAttributeを指定 [CustomPropertyDrawer(typeof(HideEnumItemAttribute))] public class HideEnumItemDrawer : PropertyDrawer { int selectedIndex; public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { // Attribute取得 var filterInfo = (HideEnumItemAttribute)attribute; // eunmValueIndex変換用 var enum2index = new Dictionary<int, int>(property.enumNames.Length); for (int i = 0; i < property.enumNames.Length; i++) { var enumEntry = Enum.Parse(fieldInfo.FieldType, property.enumNames[i]); enum2index[(int)enumEntry] = i; } // 表示項目を加工 var filteredItems = property.enumNames.Where(item => !filterInfo.Filter.Contains(item)).ToList(); // Editor表示の同期 selectedIndex = filteredItems.IndexOf(property.enumNames[property.enumValueIndex]); // シリアライズされた値が範囲外だった場合、最初の項目に設定 if (selectedIndex < 0) { selectedIndex = 0; var mappedEnum = Enum.Parse(fieldInfo.FieldType, filteredItems[selectedIndex]); property.enumValueIndex = enum2index[(int)mappedEnum]; } // オリジナルの代わりに、加工されたリストを描画 using (var check = new EditorGUI.ChangeCheckScope()) { selectedIndex = EditorGUI.Popup(position, label.text, selectedIndex, filteredItems.ToArray()); if (check.changed) { // 元のEnum値に変換 var mappedEnum = Enum.Parse(fieldInfo.FieldType, filteredItems[selectedIndex]); property.enumValueIndex = enum2index[(int)mappedEnum]; } } } } まとめ このように「Custom Attribute」と「Custom Property Drawer」を組み合わせることで、汎用的かつ効率的なEditor拡張ができるようになるので、重宝したいですね。因みに、このような便利な「Custom Attribute」をたくさん用意してくれてるUnityアセットが「Odin Inspector And Serializer」になります。興味ある方はぜひチェックしてみてください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

アバターアップロードするときに陥った罠(備忘録)

始めに とても緩く行っているゆえに発生した罠。 もっとこうしたほうがいいよとかあればコメントしてもらえると喜ぶと思います。 ここから本題↓ ●アバターアップロード成功したけど透明だ……アバターの枠はあるけど表示される3Dモデルが透明だ…… ●原因 "VRC Avater Descriptor(Script)"を入れている"hierarchy"の階層が変なところに入れていた。 正解は、アバターのプレハブ一番上 なぜかbodyに入れてもアップロードできたのが悪いw 仮想"hierarchy" ◆アバター(OK :ここに入れるのが正解)  ┠body (NG :ここに入れてもアップロード成功するので起こった)  ┗アーマチュアーとか   ┗Hips     ┠以下省略 ●アニメーションで表情をセットしたけどなんか表情が崩壊する……どこかのタイミングでなんで? ●原因 アニメーションは暗黙的に指定していないブレンドシェイプを0にしてくれないときが多い ●対策 idol(初期状態)のアニメーションはすべてのブレンドシェイプを表示しておくこと。 項目増やすとこうなるので入れているもので対応すること。 MMDもそんな仕様だった気がする(書いてないものは対応しない) 締めの言葉 多分ちゃんと手順見れば書いてあったんだろうけど、遭遇しないと頭に入らないからね、仕方ないね。 気が向いたときに更新 以上
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity2020でNewtonsoft.Jsonを入れる

この記事について Unity2020でNewtonsoft.Jsonをプロジェクトに入れるとMultiple precompiled assemblies with the same name Newtonsoft.Json.dll included or the current platform. Only one assembly with the same name is allowed per platform.のようなエラーが発生することがあります。 これの回避法メモです。 原因 Unity2020以降のVersionControl(旧UnityCollaborate)がNewtonsoft.Jsonを利用するようになり、すでにNewtonsoft.Json.dllが含まれているため。 対処法 Newtonsoft.Json.dllを消す 単純に自前のNewtonsoft.Json.dllを消せば解決します。 Unity2020, Unity2021では何もせずとも最初からNewtonsoft.Jsonが使えます。 また、Newtonsoft.Jsonへの依存を明示するためにPackageManagerでパッケージを追加しておくといいです。 PackageManager左上の+ボタンから、「Add package from git URL...」でcom.unity.nuget.newtonsoft-jsonを追加します。 これでNewtonsoft Jsonのパッケージが追加されます。 "com.unity.nuget.newtonsoft-json"というのはVersionControlが依存しているNewtonsoft.Json.dllを含むパッケージです。 VersionControlを消す Unityのバージョン管理機能を使っていなければVersionControlパッケージを消しても大丈夫です。 PackageManagerからVersion ControlをRemoveするだけです。 com.unity.nuget.newtonsoft-jsonのNewtonsoft.Json.dllを消す VersionControlは消さずにパッケージ内のdllだけを消すこともできます。 Library/PackageCache/com.unity.nuget.newtonsoft-json@2.0.0ディレクトリをPackagesディレクトリ内にコピーします。 こうするとcom.unity.nuget.newtonsoft-jsonの中身を編集できるようになります。 あとはその中の不要なdllを消せば、自分で必要なdllを使えます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む