Help us understand the problem. What is going on with this article?

描画負荷がかからない透明なuGUI Imageを作る【Unity】

はじめに

uGUIの操作を制限するため手前に透明なImageを重ねることがあると思いますが、そのままでは1枚分の描画負荷がかかってしまいます。その負荷を軽減する方法を紹介します。

方法

スクリーンショット 2020-02-06 10.05.10.png

Imageと同じGameObjectについているCanvasRendererのCull Transparent Meshをオンにしてください。

スクリーンショット 2020-02-06 10.33.17.png

SceneビューのOverdrawモードで確認すると、設定したImage部分の描画がされていないことが確認できます。

ダウンロード (1).png

StatsでもBatchesが増えていないことが確認できます。

ちなみにCanvasRendererのCull Transparent Meshで全ての描画がなくなるのは全ての画像領域が完全に透明な場合のみです。アルファ値が0.1でも残っていると描画されてしまう点に注意してください。

おまけ: 最初から描画しないスクリプトを自作する

上記の方法とほぼほぼ同じことができるスクリプトです。途中から意味ないと気がついたのですが、折角なので紹介します。raycastも当たるやつです。

スクリーンショット 2020-02-06 10.20.18.png
^先ほどと同様にいくつ置いても描画されない

スクリプト

Gist: NoRenderImage.cs

NoRenderImage.cs
using UnityEditor;

namespace UnityEngine.UI
{
    /// <summary>
    /// 描画しない透明Imageコンポーネント
    /// </summary>
    [AddComponentMenu("UI/NonRenderImage", 2004)]
    public class NoRenderImage : Graphic
    {
        protected override void OnPopulateMesh(VertexHelper vh) { vh.Clear(); }

#if UNITY_EDITOR
        [UnityEditor.CustomEditor(typeof(NoRenderImage))]
        class NonRenderImageEditor : UnityEditor.Editor
        {
            public override void OnInspectorGUI() { }

            private static Vector2 s_ImageElementSize = new Vector2(100f, 100f);

            [MenuItem("GameObject/UI/NoRender Image", false, 2004)]
            public static void CreateNoRenderImage()
            {
                var parent = Selection.activeGameObject?.transform;
                if (parent == null || parent.GetComponentInParent<Canvas>() == null)
                {
                    var canvas = new GameObject("Canvas");
                    canvas.transform.SetParent(parent);
                    canvas.AddComponent<Canvas>().renderMode = RenderMode.ScreenSpaceOverlay;
                    canvas.AddComponent<CanvasScaler>();
                    canvas.AddComponent<GraphicRaycaster>();
                    parent = canvas.transform;
                }
                var go = new GameObject("NoRenderImage");
                var rectTransform = go.AddComponent<RectTransform>();
                rectTransform.SetParent(parent);
                rectTransform.sizeDelta = s_ImageElementSize;
                rectTransform.anchoredPosition = Vector2.zero;
                Selection.activeGameObject = go;
                go.AddComponent<NoRenderImage>();
            }
        }
#endif
    }
}

メインはこの部分だけです。メッシュ描画のコールバック関数であるOnPopulateMeshをoverrideして、頂点をクリアしています。これで描画だけがされないGraphicコンポーネントが実現できました。
参考: ボタンの当たり判定(タッチ範囲)だけ広げる【Unity】【uGUI】 - (:3[kanのメモ帳]

public class NoRenderImage : Graphic
{
    protected override void OnPopulateMesh(VertexHelper vh) { vh.Clear(); }
}

他の部分は便利に使うための記述です。

スクリーンショット 2020-02-06 10.25.39.png
^[Add Component]メニューのUIカテゴリから追加できる

スクリーンショット 2020-02-06 10.26.43.png
^Createメニューからも生成できる

スクリーンショット 2020-02-06 10.28.07.png
^Canvas以下でない階層で生成すると、自動的にCanvasを作ってくれる

この辺りは別の記事でまとめておこうと思います。

余談

Textコンポーネントも描画するテキストがない場合に描画がされないので、それで良い説もありますね。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした