Search Unity

Slow custom editor

Discussion in 'Scripting' started by shmomo, May 27, 2015.

  1. shmomo

    shmomo

    Joined:
    Oct 11, 2011
    Posts:
    127
    hello experts

    i have a custom editor showing a bunch of arrays. its quite slow to respond to input. are there any techniques im not aware of that can speed it up? is it not possible to handle showing many arrays?

    thanks!

    J
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    We can't tell you what's slow about your code without seeing your code.
     
    NomadKing likes this.
  3. shmomo

    shmomo

    Joined:
    Oct 11, 2011
    Posts:
    127
    oof! there is a lot of it. i was just wondering if there was any general tips for faster custom editors. no worries. thanks anyway!

    J
     
  4. Jamster

    Jamster

    Joined:
    Apr 28, 2012
    Posts:
    1,102
    We only need to one editor file! You might as well as someone might be able to improve it and make it faster!
     
  5. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,706
    General tip: In OnInspectorGUI, only draw. Don't do any processing. If you have to do processing, cache it.
    For example, don't do this:
    Code (csharp):
    1. public override void OnInspectorGUI() {
    2.     string[] textures = AssetDatabase.FindAssets("t:Texture2D");
    3.     EditorGUILayout.LabelField("Num textures: " + textures.Length);  
    4. }
    Instead, do something like this:
    Code (csharp):
    1. private string[] textures;
    2. private string numTexturesMessage;
    3.  
    4. void OnEnable() {
    5.     textures = AssetDatabase.FindAssets("t:Texture2D");
    6.     numTexturesMessage = "Num textures: " + textures.Length;
    7. }
    8.  
    9. public override void OnInspectorGUI() {
    10.     EditorGUILayout.LabelField(numTexturesMessage);  
    11. }
    This is admittedly a contrived example. The point is that you shouldn't spend time in OnInspectorGUI() doing anything other than drawing.

    Also, if you can get away with showing only one array at a time, you could fold the others into foldouts. When the user opens a foldout, show only that array and close the other foldouts.

    Depending on your needs, you could use ReorderableList to draw the arrays. It's pretty fast.
     
    Last edited: Aug 1, 2022
    Oyedoyin1 likes this.
  6. shmomo

    shmomo

    Joined:
    Oct 11, 2011
    Posts:
    127
    thanks guys! i will look at foldouts and ReorderableList.

    its a custom editor showing a list of classes. the objects are displayed using a property drawrer. Each object has 10 fields (half are enums) and the list has 20 of those. maybe its just too much.

    thanks!

    J
     
  7. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    I've seen some very complex editor scripts, more complex than what yours sounds like. I'd like to help you optimize it, I just have nothing to optimize!
     
  8. shmomo

    shmomo

    Joined:
    Oct 11, 2011
    Posts:
    127
    Fold out completely solved that problem! thanks guys!

    question..

    is it possible to use the a string value from a serialised property as the label in custom editor? e.g. is i have a string variable in the property im displaying can i get it and use it as the string value for a label?

    thanks!
     
  9. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    Yes. You pass the string to the label. Not quite sure what the issue is.

    Code (CSharp):
    1. string label = mySerializedProperty.stringValue;
    2. EditorGuiLayout.LabelField(label);
    3. //#profit
     
  10. shmomo

    shmomo

    Joined:
    Oct 11, 2011
    Posts:
    127
    thanks! what if the serialized property is an class object, the string being only one of a few fields?

    EDIT:
    no worries FindPropertyRelative was what i was looking for
     
    Last edited: Jun 1, 2015
  11. Spacew00t

    Spacew00t

    Joined:
    Mar 24, 2013
    Posts:
    21
    Hey all,

    Sorry to resurrect an absolutely deceased thread, but since it's the first result on google for "unity3d custom editor lag" and none of these solutions satisfied my problem, I'll add what worked for me. Since a lot is going to change in the next update, I'll mention that this fix is for my custom editor on 2018.3.10f1, and written entirely with the IMGUI (stuff like EditorGUILayout) and not the upcoming UIElements.

    Adding foldouts to the entries in my editor helped, but I needed to support worst case scenarios, when someone had all of them open at once. Once I discovered that elements inside a scrollable area have rects that don't change their values as they scroll, it became easy to cache those and check them against the scroll value. I tried to make a cleaned up example of that below:

    Code (CSharp):
    1. float verticalScroll;
    2. List<EntryModel> entries = new List<EntryModel>();
    3. Dictionary<string, Rect> entryRects = new Dictionary<string, Rect>();
    4.  
    5. void OnGUI()
    6. {
    7.     verticalScroll = GUILayout.BeginScrollView(new Vector2(0f, verticalScroll)).y;
    8.     {
    9.         foreach (var entry in entries)
    10.         {
    11.             Rect entryRect;
    12.             if (entryRects.TryGetValue(entry.Id, out entryRect))
    13.             {
    14.                 if (entryRect.yMax < verticalScroll || verticalScroll < (entryRect.yMin - position.height))
    15.                 {
    16.                     // The boundaries of this entry is above or below the area we're looking at,
    17.                     // so we put some space in and skip rendering this entry.
    18.                     GUILayout.Space(entryRect.height);
    19.                     continue;
    20.                 }
    21.             }
    22.  
    23.             // ~~~
    24.             // Your normal logic for showing an entry here!
    25.             // ~~~
    26.  
    27.             if (Event.current.type == EventType.Repaint)
    28.             {
    29.                 // If this is a repaint event, and we've rendered this entry, update its cached rect.
    30.                 entryRects[entry.Id] = GUILayoutUtility.GetLastRect();
    31.             }
    32.         }
    33.     }
    34.     GUILayout.EndScrollView();
    35. }
    36.  
    37. // Use this if major changes to your list of entries are made.
    38. void BustRectCache()
    39. {
    40.     entryRects.Clear();
    41. }
    Obviously, there are a lot of ways to further optimize this, and my example assumes you have some unique Id to address your entries by. For me, however, this simple pass made my custom editor go from unusable when you had more than a dozen entries, to very zippy and performant with many times that.

    I hope this helps the next person that googles this problem!

    Edit:

    I forgot to mention, if you're having issues with it not lining up properly, remember that the margins of styles are not taken into account when calling
    GUILayoutUtility.GetLastRect()
    . To solve this, I just wrapped my entry's interface logic in a
    GUILayout.BeginVertical(style) ... GUILayout.EndVertical()
    call where
    style
    is a
    GUIStyle
    that has top and bottom margins equal to zero.
     
    Last edited: Apr 12, 2019
    aka3eka likes this.
  12. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    I've tried different culling solutions, and they run into a pretty big problem when scrolling.

    See, the way Unity's editor handles "what input field are you writing in" is by counting. Every time it draws a field, it's assigned a counter (through GUIUtility.GetControlID), so when you're writing in a field, it "remembers" that field by checking if it's the same ID.

    This means that if you cull earlier elements for speed, and then scroll, your selected field might move. You can try that for yourself - select and input field, write some text, and without hitting enter or tab, start scrolling. There's a good chance the text you've input will follow the text fields down as you go.
     
    aka3eka likes this.
  13. Spacew00t

    Spacew00t

    Joined:
    Mar 24, 2013
    Posts:
    21
    True, but that's a minor inconvenience compared to the editor being so laggy you can't type. There's probably a hacky way to fix that, too. If you just want to stop it following you as you scroll, setting
    GUIUtility.keyboardControl = 0
    when they scroll too far will accomplish that.

    Hopefully UIElements will save us the trouble and make for more efficient editors, though.
     
  14. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    Yeah, UIElements isn't immediate mode, so the entire editor isn't redrawn every frame. That's a pretty big improvement.
     
    image28 likes this.
  15. TrueJollyRoger

    TrueJollyRoger

    Joined:
    Dec 23, 2017
    Posts:
    9
    This is an old thread, but because google leads here I leave my experience, maybe it will save your time.
    After research and experimentation I found out that it's not about custom editor as is. It looks like Unity editor isn't able to support a big amount of game objects in editor mode. For example if you are making a map editor with 50x50 cells its to be 2500 cells. It's far beyond comfort amount to work with.
    Based on foregoing, I think it's worthwhile to plan making your tools directly in game mode from start. For example: Map editor => Json/Xml => Game.
    It will save you time and frustration. As a bonus, tool could be incorporated into the game for players to mod it. ^_^