Unity自身のナビシステムで特定点の高さを取得する方法
今回の主な話題:Unity自身のナビシステムで特定点の高さを取得する方法、GPU Instancingはさまざまなテクスチャをサンプリングする方法、Text.get_cachedTextGeneratorのMonoメモリを最適化する方法。
ナビメッシュ
Q1: Unity自身のナビシステムに基づいてパスファインディングロジックを作っていますが、特定点の高さを取得する方法はわかりませんので、キャラクターのy値を設定できません。現在考えている方法は、一セットのHeightmapと一セットのナビメッシュを自分で生成します。先にHeightmapの高さを調べて、失敗ならナビメッシュの射線検査を実行することです。しかし、そうするとメモリは若干増えますが、何かUnity自身のナビシステムで特定点の高さを取得する方法ありませんか?
①
1)前に使ったのはNavMesh.SamplePositionでした。より高い点から線を伸ばし、射線で点を取って球の中心としてSamplePositionをコールします。
2)もう一つの方法は、アーティストにMesh Colliderを作らせて、高さを調べる射線を接受するために使用します。
https://docs.unity3d.com/540/Documentation/ScriptReference/NavMesh.SamplePosition.html
②
前に似ているもの作りましたが、NavMeshを使っていませんでしたらか、効率がNavMesh.SamplePositionよりも優れているかどうかはわかりません。
解決策:エディターで前処理を行い、シーン内で衝突のあるオブジェクトを一つのメッシュに合併し(MeshColliderではなくBox、Sphere、Capsuleなどのものがありますが、このようなMeshは自分で手動的に生成します)、問題を光線と三角形面の交点問題に変更します(MeshCollider射線検査に対して、これは本質的な問題です)。
もちろん、これは最も基本的なものです。さらに一歩進めると:
1)隣接する面の法線が近接すると、一つの多辺形になります。それじゃまた射線と多辺形の交点問題になされます。
2)多辺形のAABBを計算し、先にAABBを使って検査します。
3)多辺形を並べ替え、面積の大きい多辺形を優先に検査します。
4)実現していない:多辺形をXZ面に投影し、y値が保存のみに使用し、交点計算に参加しません。
5)実現していない:四分木で空間を分割することを試します。
③
以前もこの問題に会いまして、さまざまな方法を試しました。Unity公式は良い解決策を提供しませんでした。直接にNavmesh.SamplePositionをコールすると、球の衝突に基づいて最も近い位置を取得するため、間違った位置を取りやすいです。そして、この関数のパフォーマンスは、球の半径が大きくなるにつれて急激に低下します。テストした結果は、半径1.5メートルでコストはほぼ同じです。ですから、高さを取得するために、一番いいのは物理衝突を参照することです。キーポイントはこのメッシュを生成することであります。Navmesh.CalculateTriangulation関数を使用して、既にブラシ処理されたNavmesh領域を取得し、メッシュを生成できます。
この記事を参照できます:https://blog.csdn.net/huutu/article/details/52672505(中国語注意)
UI
Q2:UWA Monoメモリレポートで、私たちのロジクコードにあるText.get_cachedTextGeneratorという関数が6MBほどのMonoメモリを占めているとわかりましたが、どうやって最適化できますか?
各Textコンポーネントは、コンストラクターを一回実行します、これはTextGenerator ... ctorです。上図のようにこのMonoメモリは高いのは、メインプロジェクトにTextコンポーネントは多すぎることを示しています。UIインターフェイスにある同じような情報を詳しく調査することをお勧めします。
レンダリング
Q3: GPU Instancingは、インスタンスごとに異なるテクスチャのサンプリングをサポートできますか?このようなやり方を試しましたが、コンパイルは間違いました。
UNITY_DEFINE_INSTANCED_PROP(sampler2d, _MainTex)
これはサポートしていません。Textureはinstancedの属性としてさせられません。問題主にTexture2DArrayをお勧めします。スクリプトでTexture2DArrayを作成し、ArrayのIndexをinstancedの属性としてShaderに渡します。それてさまざまなindexで異なるテクスチャをサンプリングできます。
エディター
Q4:何かスクリプトのある値がInspectorに変更された時に関数をトリガーする良い方法はありますか?主に数値を変更する時にいくつかの検出およびリマインダー機能を実行したいです。
①
OnValidateイベントを使用できます。
https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnValidate.html
②
OnInspectorGUIをお勧めします。
③
インスペクタービューを書き直して、スクリプトをバインドします。
[CustomEditor(typeof(Test))] public class TestEditor : Editor { public override void OnInspectorGUI() { Test test = (Test)target; test.isSure= EditorGUILayout.Toggle(“確認しますか?”, test.isSure); test.Name= EditorGUILayout.TextField(“名前”, test.Name); if (GUI.changed) { Debug.Log("change"); } } }
ロジックコード
Q4: 自分が作成したプラグインには、IL2CPPで問題があります。
お先にコード:
byte[] bytes = System.Text.Encoding.Default.GetBytes(strMsg);
int ret = FTCode.ftcode(seed, 1, ref bytes, bytes.Length);
ftcodeステートメント
[DllImport(LibName, CallingConvention = CallingConvention.Cdecl)]
public static extern int ftcode(int _seed,int type, [MarshalAs(UnmanagedType.LPArray)] ref byte[] data,int length);
Plugins/Android/libsに一つのsoを入れます。Monoでftcodeをコールすれば欲しい結果はもらえます。つまり、長さ20のbyte配列を渡し、暗号化され後に長さ20のbyte配列を正常に手に取れます。しかし、IL2CPPでコールするとこの配列の長さは1になります。これはCPPに変換した後のBugですか?
パラメーターを変えました。
int ftcode(int seed, int type, void* data, int length)
コール
string strMsg = “{“userId”=111}”; byte[] bytes = System.Text.Encoding.Default.GetBytes(strMsg); GCHandle hObject = GCHandle.Alloc(bytes, GCHandleType.Pinned); IntPtr pObject = hObject.AddrOfPinnedObject(); int _ret = Utility.FTCode.ftcode(seed, 1, pObject, bytes.Length); Marshal.Copy(pObject, bytes, 0,bytes.Length); if (hObject.IsAllocated) hObject.Free();
UWA公式サイト:https://jp.uwa4d.com
UWA公式ブログ:https://blog.jp.uwa4d.com
UWA公式Q&Aコミュニティ(中国語注意):https://answer.uwa4d.com