Search Unity

Component Icon and Scene-Gizmos

Discussion in 'Immediate Mode GUI (IMGUI)' started by gfrast, Apr 27, 2017.

  1. gfrast

    gfrast

    Joined:
    May 5, 2014
    Posts:
    30
    Does anybody know how to achieve something like this:

    lightComponent.jpg

    I've been looking for quite some time now on how to achieve something like that, but unfortunatly, without any results so far.

    What i need to know:
    1) How to create a different icon for your component and your icon-display in the scene view.
    2) How to make your component-icon selectable on multiple objects simultaneously via marquee-box

    I think once 1) is solved, it should be easy to switch icons depending on different values of the component or the component's variables.

    Thanks a lot upfront!
     
  2. flashframe

    flashframe

    Joined:
    Feb 10, 2015
    Posts:
    798
  3. gfrast

    gfrast

    Joined:
    May 5, 2014
    Posts:
    30
    Hi @flashframe, first of all thanks for your response. I'm really stuck on this one and i can't imagine that noone has tried this before.

    Gizmos.DrawGUITexture unfortunatly only works in 2D and not really in the scene view.
    By now i figured out, that you can draw an icon in the sceneview by using Gizmos.DrawIcon (https://docs.unity3d.com/ScriptReference/Gizmos.DrawIcon.html).
    BUT the big problem with that is, that you are actually drawing a gizmo, not an icon (and the gizmo disappears as soon as you collapse the script). Also, the Custom component icon is still visible in the scene view, and actually draws on top of the icon that is drawn by Gizmos.DrawIcon.

    In the example with the Light component, the light is actually drawing the component icon differently, and its not a gizmo (as you can see if you click the gizmo-dropdown and hide the light icon by clicking on it). The big advantage of that is, that you can collapse the script in the inspector and still see the icon in the scene view.

    gizmoProb.jpg

    Any help is highly appreciated! Also, if someone could just confirm that its not possible to achieve it, it would be a great help as well, so i could stop worrying about it...

    thanks upfront!
     
    Last edited: May 2, 2017
  4. flashframe

    flashframe

    Joined:
    Feb 10, 2015
    Posts:
    798
    Hey, sorry you're right, it's DrawIcon not DrawGUITexture.

    Not sure if I'm following your requirements, but I use this kind of thing in lots of my custom components and the icon is visible in the scene view regardless of whether the script is selected or not:

    Code (CSharp):
    1. void OnDrawGizmos()
    2.         {
    3.             Gizmos.DrawIcon(transform.position, "MyIcon", true); //File needs to be in a folder called Gizmos
    4.         }
    5.  
    (I don't use the custom component icon either - I usually create a custom editor if I want to show icons for toggling the state of an object)

    Not sure how Unity does it internally like with lights, hopefully someone will illuminate :)
     
  5. gfrast

    gfrast

    Joined:
    May 5, 2014
    Posts:
    30
    @flashframe: The problem is that everything that's being called from "OnDrawGizmos" disappears as soon as you collapse the script in the inspector (its the same as unchecking the Gizmo-checkbox for this script in the "Gizmos"-Dropdown of the Scene View).

    The standart light however, is still visible in the scene view (even if you collapse the light script in the inspector). Thats why i'm pretty sure that the Icon you see is not a Gizmo, but the Component-Icon (or something similar).....

    Anyway thanks for trying to help - indeed... it would be great if someone could "shed some light" on that issue :).
     
  6. flashframe

    flashframe

    Joined:
    Feb 10, 2015
    Posts:
    798
  7. gfrast

    gfrast

    Joined:
    May 5, 2014
    Posts:
    30
    Well, the good thing is, that the OnSceneGUI also executes when the component is collapsed. Therefore, in theory, it could be possible to draw an icon in this method. Now the question is - how to draw an icon in the scene without using Gizmos?

    A small script to test the OnSceneGUI:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3.  
    4. namespace IconTest
    5. {
    6.     /// <summary>
    7.     /// Draw an Icon for the Component in the Scene-View
    8.     /// </summary>
    9.     public class IconTestComponent : MonoBehaviour
    10.     {
    11.         SceneView.OnSceneFunc onSceneVar;
    12.  
    13.         /// <summary>
    14.         /// When this GO is enabled, force Perform "OnScene".
    15.         /// </summary>
    16.         void OnEnable()
    17.         {
    18.             onSceneVar = SceneView.onSceneGUIDelegate += OnScene;
    19.         }
    20.  
    21.         /// <summary>
    22.         /// Do Stuff
    23.         /// </summary>
    24.         void OnScene(SceneView sceneView)
    25.         {
    26.             // At the moment only forces focus to the scene-center - how to draw an icon in the sceneview here?
    27.             sceneView.LookAt(Vector3.zero);
    28.         }
    29.  
    30.         /// <summary>
    31.         /// Stop Performing "OnScene" on Disable.
    32.         /// </summary>
    33.         void OnDisable()
    34.         {
    35.             SceneView.onSceneGUIDelegate -= onSceneVar;
    36.         }
    37.     }
    38. }
     
  8. flashframe

    flashframe

    Joined:
    Feb 10, 2015
    Posts:
    798
    I do it using the Handles class:

    Code (CSharp):
    1. Handles.BeginGUI();
    2. GUI.DrawTexture(TextureRect(IconSize, pos), EditorResources.LightIcon);
    3. Handles.EndGUI();
    I have a class called EditorResources that stores static references to textures in my project. It loads a texture like this (must be in a folder called Editor Default Resources):

    Code (CSharp):
    1. lightIcon = (Texture2D)EditorGUIUtility.Load("Icons/Lightbulb.png");
     
  9. gfrast

    gfrast

    Joined:
    May 5, 2014
    Posts:
    30
    Unfortunatly GUI.DrawTexture only works on the 2D "screen" (as it requires a Rect for positioning, not a Vector3).

    I managed to draw an icon now using Handles.Label (https://docs.unity3d.com/ScriptReference/Handles.Label.html).
    The only problem is the icon-offset (it starts drawing at the top left corner instead of the center), and, that the icon is not selectable. Also, its not reacting to the "3D Icons" scale in the Gizmos-Dropdown (and therefore you're not able to hide it at all).

    i fear that the onSceneGUIDelegate was worth a try, but its not going to work out to really mimic unity's built-in icon behavior.

    EDIT: Try script at own risk. i had to restart unity after removing the component from a gameobject again to fix the scene view.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3.  
    4. namespace IconTest
    5. {
    6.     [ExecuteInEditMode]
    7.     /// <summary>
    8.     /// Draw an Icon for the Component in the Scene-View
    9.     /// </summary>
    10.     public class IconTestComponent : MonoBehaviour
    11.     {
    12.         SceneView.OnSceneFunc onSceneVar;
    13.  
    14.         /// <summary>
    15.         /// When this GO is enabled, force Perform "OnScene".
    16.         /// </summary>
    17.         void OnEnable()
    18.         {
    19.             if (onSceneVar != null) SceneView.onSceneGUIDelegate -= onSceneVar;
    20.             onSceneVar = SceneView.onSceneGUIDelegate += OnSceneEnabled;
    21.         }
    22.  
    23.         /// <summary>
    24.         /// Do Stuff when enabled
    25.         /// </summary>
    26.         void OnSceneEnabled(SceneView sceneView)
    27.         {
    28.             // Draw Icon (not selectable)
    29.             Handles.Label(transform.position, (Texture2D)Resources.Load("iconEnabled"));
    30.         }
    31.  
    32.         /// <summary>
    33.         /// Do other Stuff when disabled
    34.         /// </summary>
    35.         void OnSceneDisabled(SceneView sceneView)
    36.         {
    37.             // Draw Icon (not selectable)
    38.             Handles.Label(transform.position, (Texture2D)Resources.Load("iconDisabled"));
    39.         }
    40.  
    41.         /// <summary>
    42.         /// Stop Performing "OnScene" on Disable.
    43.         /// </summary>
    44.         void OnDisable()
    45.         {
    46.             if (onSceneVar != null) SceneView.onSceneGUIDelegate -= onSceneVar;
    47.             onSceneVar = SceneView.onSceneGUIDelegate += OnSceneDisabled;
    48.         }
    49.     }
    50. }
     
    Last edited: May 2, 2017
  10. flashframe

    flashframe

    Joined:
    Feb 10, 2015
    Posts:
    798
  11. gfrast

    gfrast

    Joined:
    May 5, 2014
    Posts:
    30
  12. danBourquin

    danBourquin

    Joined:
    Nov 16, 2016
    Posts:
    34
    I wanted to center the picture on a specific world point. This is how I corrected the position to give to the Handle.Label :
    Code (CSharp):
    1.         Texture2D texture = new Texture2D(1, 1);
    2.         var path = $"{Application.dataPath}/Gizmos/empty-box.png";
    3.         texture.LoadImage(System.IO.File.ReadAllBytes(path));
    4.         texture.Apply();
    5.         Camera sceneCamera = GameObject.Find("SceneCamera")?.GetComponent<Camera>();
    6.         Vector3 offset = Vector3.zero;
    7.         if (sceneCamera != null)
    8.         {
    9.             offset = sceneCamera.ScreenToWorldPoint(new Vector3(texture.width / 2f, -texture.height / 2f, 0f)) - sceneCamera.ScreenToWorldPoint(Vector3.zero);
    10.         }
    11.  
    12.         Handles.Label(center - offset, texture);
     
    Demexis likes this.