UI Image component raycast padding needs a gizmo

Please add a scene visualization of the raycast padding property on UI Image components. It’s not entirely obvious if values need to be positive or negative to expand the clickable area and then it’s relatively cumbersome to tweak the expanded rect, since I either have to create a temporary RectTransform, play around with that, then copy the values and delete or try to debug this by hovering over my button and looking at the EventSystem preview inspector.

Both could simply be solved by showing a light green scene gizmo if the raycast padding is non-zero.

I don’t think it needs interactive handles. This would either clutter the scene view or require another button in the component inspector, and I think it’s ok to type in the values, but they need to be visually shown before I have to enter play mode.

Thank you for considering!

7 Likes

Good idea i’ll put it on the list

8 Likes

+1 for a visual indicator of the collider when using Raycast Padding!

I also agree but while on the topic… can we make the Vector4, of raycastPadding, order match the order of the Inspector or vice versa. I just tried changing that value dynamically and they were all over the place with bottom being y and top being w. It was all very confusing.

The order on the inspector is:
Left
Right
Top
Bottom

The order of the Vector4 is:
X = Left
Y = Bottom
Z = Right
W = Top

Could the inspector either match this or have the vector 4 match the inspector? It would just make it easier to understand out of the box.

2 Likes

Yes, it is very annoying to work as a blind person when trying to make the clickable area bigger or smaller. I am using now the latest version (2020.2.6) and this feature is still missing …

Plus one here (2020.2). I get difficult times deciding between negative and positive values.

2 Likes

I also needed this resource for a while, so I decided to make a MacGyverism.
it is only a partial and visual remedy in response to the topic:

how to config: RaycastPaddingHelper.cs - Album on Imgur
I hope it helps.
@AllanSamurai


RaycastPaddingHelper.cs:

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
#if UNITY_EDITOR
using UnityEditor;
#endif
/// <summary>
/// I also needed this resource for a while, so I decided to make a MacGyverism.
/// it is only a partial and visual remedy in response to the topic:
/// https://discussions.unity.com/t/819884
/// how to config: https://imgur.com/a/NVpHgzu
/// I hope it helps.
/// @AllanSamurai
/// </summary>
[RequireComponent(typeof(Image), typeof(RectTransform))]
public class RaycastPaddingHelper : UIBehaviour
{
#if UNITY_EDITOR

    #region https://github.com/Unity-Technologies/UnityCsReference/blob/61f92bd79ae862c4465d35270f9d1d57befd1761/Editor/Mono/Inspector/RectTransformEditor.cs#L24-L26
    private static Vector2 kShadowOffset = new Vector2(1, -1);
    private static Color kShadowColor = new Color(0, 0, 0, 0.5f);
    private const float kDottedLineSize = 5f;
    #endregion

    void OnDrawGizmos()
    {
        Image image = GetComponent<Image>();
        RectTransform gui = GetComponent<RectTransform>();

        #region https://github.com/Unity-Technologies/UnityCsReference/blob/61f92bd79ae862c4465d35270f9d1d57befd1761/Editor/Mono/Inspector/RectTransformEditor.cs#L646-L660
        Rect rectInOwnSpace = gui.rect;
        // Rect rectInUserSpace = rectInOwnSpace;
        Rect rectInParentSpace = rectInOwnSpace;
        Transform ownSpace = gui.transform;
        // Transform userSpace = ownSpace;
        Transform parentSpace = ownSpace;
        RectTransform guiParent = null;
        if (ownSpace.parent != null)
        {
            parentSpace = ownSpace.parent;
            rectInParentSpace.x += ownSpace.localPosition.x;
            rectInParentSpace.y += ownSpace.localPosition.y;

            guiParent = parentSpace.GetComponent<RectTransform>();
        }
        #endregion

        // patSilva's post: https://discussions.unity.com/t/819884/4
        // The image.raycastPadding order of the Vector4 is:
        // X = Left
        // Y = Bottom
        // Z = Right
        // W = Top

        Rect paddingRect = new Rect(rectInParentSpace);
        paddingRect.xMin += image.raycastPadding.x;
        paddingRect.xMax -= image.raycastPadding.z;
        paddingRect.yMin += image.raycastPadding.y;
        paddingRect.yMax -= image.raycastPadding.w;

        // uncomment below line to show only when rect tool is active
        // if (Tools.current == Tool.Rect)
        {
            //change the color of the handles as you wish
            Handles.color = Color.green;
            DrawRect(paddingRect, parentSpace, true);
        }
    }

    #region https://github.com/Unity-Technologies/UnityCsReference/blob/61f92bd79ae862c4465d35270f9d1d57befd1761/Editor/Mono/Inspector/RectTransformEditor.cs#L618-L638
    void DrawRect(Rect rect, Transform space, bool dotted)
    {
        Vector3 p0 = space.TransformPoint(new Vector2(rect.x, rect.y));
        Vector3 p1 = space.TransformPoint(new Vector2(rect.x, rect.yMax));
        Vector3 p2 = space.TransformPoint(new Vector2(rect.xMax, rect.yMax));
        Vector3 p3 = space.TransformPoint(new Vector2(rect.xMax, rect.y));
        if (!dotted)
        {
            Handles.DrawLine(p0, p1);
            Handles.DrawLine(p1, p2);
            Handles.DrawLine(p2, p3);
            Handles.DrawLine(p3, p0);
        }
        else
        {
            DrawDottedLineWithShadow(kShadowColor, kShadowOffset, p0, p1, kDottedLineSize);
            DrawDottedLineWithShadow(kShadowColor, kShadowOffset, p1, p2, kDottedLineSize);
            DrawDottedLineWithShadow(kShadowColor, kShadowOffset, p2, p3, kDottedLineSize);
            DrawDottedLineWithShadow(kShadowColor, kShadowOffset, p3, p0, kDottedLineSize);
        }
    }
    #endregion

    #region https://github.com/Unity-Technologies/UnityCsReference/blob/61f92bd79ae862c4465d35270f9d1d57befd1761/Editor/Mono/Inspector/RectHandles.cs#L278-L296
    public static void DrawDottedLineWithShadow(Color shadowColor, Vector2 screenOffset, Vector3 p1, Vector3 p2, float screenSpaceSize)
    {
        Camera cam = Camera.current;
        if (!cam || Event.current.type != EventType.Repaint)
            return;

        Color oldColor = Handles.color;

        // shadow
        shadowColor.a = shadowColor.a * oldColor.a;
        Handles.color = shadowColor;
        Handles.DrawDottedLine(
            cam.ScreenToWorldPoint(cam.WorldToScreenPoint(p1) + (Vector3)screenOffset),
            cam.ScreenToWorldPoint(cam.WorldToScreenPoint(p2) + (Vector3)screenOffset), screenSpaceSize);

        // line itself
        Handles.color = oldColor;
        Handles.DrawDottedLine(p1, p2, screenSpaceSize);
    }
    #endregion

#endif
}

6944165–816476–RaycastPaddingHelper.cs (4.81 KB)

15 Likes

Oh man… this is still not implemented…

2 Likes

At this rate this will never be implemented.

Probably not in the UGUI. I can see to popup in the UI Toolkit though.

A better solution altogether might be a custom editor tool like this:

// Author: Chris Yarbrough

namespace Nementic
{
    using UnityEditor;
    using UnityEditor.EditorTools;
    using UnityEngine;
    using UnityEngine.UI;

    [EditorTool("Raycast Padding Tool", typeof(Graphic))]
    public class RaycastPaddingTool : EditorTool
    {
        [SerializeField]
        private Texture2D icon;

        private GUIContent iconContent;

        public override GUIContent toolbarIcon => iconContent;

        private void OnEnable()
        {
            iconContent = new GUIContent
            {
                image = icon,
                text = "Raycast Padding Tool",
                tooltip = "Interactively edits the raycast padding " +
                          "property of any UI.Graphic component."
            };
        }

        public override void OnToolGUI(EditorWindow window)
        {
            var graphic = target as Graphic;

            // Seems like an issue with Unity, but target can sometimes be a GameObject.
            if (graphic == null)
                return;
           
            RectTransform rectTransform = (RectTransform)graphic.transform;
            using (new Handles.DrawingScope(rectTransform.localToWorldMatrix))
            {
                Rect rect = rectTransform.rect;
                Vector4 padding = graphic.raycastPadding;
                rect.xMin += padding[0]; // Left
                rect.yMin += padding[1]; // Bottom
                rect.xMax -= padding[2]; // Right
                rect.yMax -= padding[3]; // Top

                Handles.DrawSolidRectangleWithOutline(rect, Color.clear, Color.cyan);
            }
        }
    }
}

This would make it possible to actually use draggable handles in the scene view, but for now I use it to simply draw the padding Gizmo. It would also be possible to extend the builtin Image component editor, but I’ve encountered some issues with the order of execution in which Unity loads assemblies in packages, so in fact, I wasn’t able to override the default editor for Image. Works with other types such as Transform or MeshRenderer, but not for Image. But also not in all cases, might be a little random. Hence the custom Editor Tool seems more robust and cleaner to implement.

3 Likes

Over 10 years of using unity, I find so many small yet crucial features that you actually in need when you are making a game, are so overlooked by Unity. The worse part is that you feel like a lot of the actual problem is not because of the lack of the features, but the communication about it between community and Unity. It has been half an year since Unity responded anything about this…

Thank you for sharing this tool! However, how can I use it?

I’ve dropped your script on the Editor folder and nothing happens when I select a Graphic UI.
The OnEnable function is called but the OnToolGUI is not.

https://docs.unity3d.com/Manual/UsingCustomEditorTools.html

It should work just by dropping it into the editor assembly and show up as a custom tool in the toolbar or when any Graphic is selected. It’s not perfectly polished though and like I said it would make even more sense if if were interactive, so you could actually drag on the handles in the scene when activated, but it should be a starting point.

3 Likes

Is there any update about when this will be available? It is a must have.

Its done, i’m not 100% what version it landed in i think 2021.1 has it if not 2021.2 will

10 Likes

How can I use it?
(2021.3 lts)

It’s work in 2021.2. Toogle all gizmos and you can see it ^^

8444711--1119635--Sans titre 2.jpg

@phil-Unity @Von_Kiefferbach
All gizmos are toggled on (I’ve checked the list too, nothing turned off), where is it? (LTS 2021.3.14)
P.S. Image component won’t do any difference.

4 Likes

It’s not there either on 2022.3.8f1 LTS… It would really be helpful!