GPUによるUnity3d UIの最適化(ミニマップなど)、または追加のカメラとスプライトなしでミニマップを作成

みなさんこんにちは!



「GPUで何かをカウントできる場合は、それを実行してください。」

//もちろん、理由の範囲内



画像



VS



画像

FPSの違いに注意してください



おそらく、背景から始めましょう。 プログラマーの1人がFPSの低下についてUIをチェックすることにしました。 興味深い依存関係が見つかりました。ミニマップをオフにすると、FPSがパーセンテージで上昇しました。 面白い。 問題を解決する必要があります。 アトラスやさまざまなプールについてはすぐに書きます。 そして、この問題にさらに詳しく取り組むことにしました。 そして、ここで私を訪れた最初の考え、UIはマテリアルを使用するので、すべてをGPUに転送できます、始めましょう。



私はグーグルを始めましたが、次のような悪い決定をたくさん見つけました。

すぐに実行したい場合でも、これを実行しないでください



上記の例がなぜ悪いのかは、コメントに記載されています。 しかし、怠け者のためにリストします。

streeter12 2016年7月4日14:51に

この方法は、その単純さにもかかわらず、明らかな欠点があります。



1.生産性が低い。

2.新しいタグを追加するには、新しい球体(プレハブの余分なゴミ)を作成する必要があります。

3.異なるプレーヤーに新しいタイプのタグとそのフィルターを追加することは非常に困難です。

4.ラベルの外観を変更するには、メッシュを作成する必要があります!

5.各シーンの追加オブジェクト=>追加の複雑さ=>開発とサポートはより困難です。

6.テストすることは困難です>>起こりうるバグ(アカウント3を考慮)。

7.リアルタイムの型置換。

8.偽の素材でシーンを圧倒する必要があります。

9.ローテーションを検討すべきではない人はどうですか? 更新にリセットするか、tranform.positionをドラッグします。

など



何も見つからず、最終的にシェーダーを書き始めました。



どこから始めましたか?



1.アイコン自体を何らかの方法で保存する必要があります。 アトラスが行います。 次に、テストに適したものを見つける必要があります。 ゲームWOWから取得しました。 そこで彼はすでに正しい内容でした。



2.この情報を何らかの方法でシェーダーに転送する必要があります。 さらに、可能であれば、たとえば、何かに関連する座標など、さまざまなUI変換を放棄します。



一般に、実装を開始します。



static const int MaxCount = 256; float4 _Targets[MaxCount]; float _WorldSizeX; float _WorldSizeY;
      
      





シェーダーでそのようなフィールドを宣言しました。 マップポイントで最大256個を配信しました。 残りは破棄されます。 float _WorldSizeXフィールドは変換の問題を解決したため、Vector3をそのままシェーダーにフィードすることにしました。 ずるい詐欺ではなく、インデックスと正規化された座標を取得し、それによってほぼ必要なものを取得しました。



ニュアンス:GCはyを嘘の底とは異なると見なします。 もちろん、左上のインデックスが0になるように反対の値を作成しました。しかし、このベンチャーを放棄することにしました。 これは上位層で解決する方が良いです。 たとえば、コード。



そして、Vector4(XZW)からの3つのフィールドは、私がYを占有するよりも私を占有していたということです。



テスト



シェーダーを作成したので、違いを確認することにしました。 これで、FPSは1つのUI要素のみを削除するレベルになりました。 速度が大幅に向上しました。最初の2つのスクリーンショットでは、違いがわかります。



たとえば、シェーダーのスクリプトはどのように見えますか?



 protected virtual void Update () { for (int i = 0; i < list.Length; i++) { list[i] = new Vector4(0, 0, 0, -1); } for (int i = 0; i < list.Length && i < targets.Count ; i++) { list[i] = new Vector4(targets[i].x *kx, targets[i].y, targets[i].z*ky, targets[i].w); } image.GetModifiedMaterial(image.material).SetVectorArray("_Targets", list); }
      
      





使い方は省略します。 ミニマップのポイントのリストを持つマネージャーがいるとします。 そして、あなたはそれを望むように使います。 サブスクリプション、シングルトン、静的なものがあります。 主なことは、不快な瞬間がないようにリストをリセットし、すべてをシェーダーに入れることを忘れないことです。



画像



作業の結果。 ご覧のとおり、回転も追加しました。 しかし、それを使用するためには、アトラスで互いに十分な距離にアイコンを作成する必要があります。 シェーダーで複雑なクリッピングアルゴリズムを発明したわけではありません。テクスチャを使用する方がはるかに簡単です。



同じフリーYを、アングルとして使用することにしました。 私はそれを個別にいじらなければなりませんでした、理由はより高い、つまりY座標の反転で、すべてをそのまま使用することにしたのは回転のためでした。



 fixed a = _Targets[i].y; fixed resultX = tX; fixed resultY = tY; if (a != 0) { fixed x0 = minX + (sizeX * 0.5); fixed y0 = minY + (sizeY * 0.5); resultX = x0 + (tX - x0) * cos(a) - (tY - y0) * sin(a); resultY = y0 + (tY - y0) * cos(a) + (tX - x0) * sin(a); }
      
      





これでシェーダーの準備ができました。 最後のタッチは、境界のアルファチャンネルをソフトにします。 affからbarrierまでの補間を使用しました。 だから、写真は良くなった。



結論



記事をテストします。 完全に準拠していません。 これは無意味なので、内容は異なります。 しかし、違いを理解するには、これで十分です。 次のステップでは、手が届くと、タイルインベントリを同様のシステムに転送します。



テストコードとプロファイラーの結果を投稿します。 スプライトでいっぱい。



  protected virtual void Start () { tests = new List<RectTransform>(); float x = 10; float y = 10; for (int i = 0; i < 256; i++) { int idx = Random.Range(0, prefabs.Count); GameObject obj = Instantiate(prefabs[idx].gameObject); RectTransform t = obj.GetComponent<RectTransform>(); t.SetParent(parent); t.localPosition = new Vector3(startPosition.x + x, startPosition.y + y, 0); if (useRotation) { t.rotation = Quaternion.Euler(0, 0, Random.Range(0, 360)); } x += step; if (i % 20 == 0) { y += step; x = 0; } tests.Add(t); } }
      
      





シェーダーのプロキシクラスを埋める

item.type = Random.Range(0、64); アイコンの種類を意味します



  void Start () { tests = new List<Item2>(); float x = 10; float z = 10; for (int i = 0; i < 256; i++) { Item2 item = new Item2(); item.position = new Vector3(x, 0, z); if (useRotation) { item.rotation = Random.Range(0, 360); } item.type = Random.Range(0, 64); x += step; if (i % 20 == 0) { z += step; x = 0; } tests.Add(item); } }
      
      





シェーダープロファイラー(ステージ上にさらに3つのキューブ)



画像



スプライトのプロファイラー(ステージ上には、プレハブとしてさらに3つの画像があります)



画像



最後にマスクを使用した例:



画像



UPD。

シェーダーの有無による違い

画像

著者がメッシュを生成したいというコメントの1つに非常に失望しました。 どうやら、著者はシェーダーが反射シャドウなどの照明を計算できることを理解していないようです。 それらのプリミティブな算術式を計算する価値は何ですか? 代わりに、彼はCPUをロードすることにしました。



アルファに関する質問に加えて。 だから私は柔らかい境界線を得た

画像



PS「GPUで何かを数えることができたら、それをしてください」



All Articles