Search Unity

  1. We've closed the job boards. If you're looking for work, or looking to hire check out Unity Connect. You can see more information here.
    Dismiss Notice
  2. Unity 2017.2 is now released.
    Dismiss Notice
  3. The Unity Gear Store is here to help you look great at your next meetup, user group or conference. With all new Unity apparel, stickers and more!
    Dismiss Notice
  4. If you're a macOS 10.13 High Sierra user take be sure to read this before updating Unity.
    Dismiss Notice
  5. Introducing the Unity Essentials Packs! Find out more.
    Dismiss Notice
  6. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice
  7. Unity 2017.3 beta is now available for download.
    Dismiss Notice

Custom Editor Repaint Specified Element only

Discussion in 'Extensions & OnGUI' started by joduffy, Dec 1, 2017.

  1. joduffy

    joduffy

    Joined:
    Jul 30, 2011
    Posts:
    30
    Hi,

    I have been creating my own custom editor for a node graph.
    I am using GUILayout.Window to display each of the nodes.

    What I am trying to do is to Repaint only the node that is being edited.
    So if I drag the node around, only this selected node should be repainted and the rest should be left alone.

    I figured repainting only the node that is being focused on would be better for performance rather than redrawing everything.

    I have been looking through the unity documentation and looking online for a while now but can't seem to find any way of doing this.

    Does this type of method exist?

    Is the Repaint restricted to updating the whole editor or can you update only the part that is being edited/focused on.
     
  2. shawn

    shawn

    Unity Technologies

    Joined:
    Aug 4, 2007
    Posts:
    541
    Unfortunately, it's a limitation of Unity's IMGUI framework that an entire editor window gets repainted when a repaint is requested. At the moment, there's no way to isolate repaints to a region.
     
  3. joduffy

    joduffy

    Joined:
    Jul 30, 2011
    Posts:
    30
    Oh wow,

    I got Shawn. Thats crazy. I have watched your unite 2013 talk a few times and gone through docs based on what you have talked about. I tried to find a way to reach out to you but no luck.

    The main issue I am facing right now - which is why I asked about the repaint, is performance reasons with the node editor.

    I had made my node editor using Recs and custom drag controls. But in the talk you mention that GUI.Window is what unity uses for its own node editor. So I went back and re-wrote my graph editor to use GULayout.Window

    But I still ran into performance issues.

    I thought it was due to the fact my nodes implement a dynamic size feature.
    The node editor itself is a State Machine. But rather than having a property window to edit the contents of each node (like a custom node inspector). I have each node setup with a drag and drop area for actions. So each node expands and shrinks its height depending on the contents placed inside it.

    My overall theory, and point of difference to other node editors, is to display each state of a State Machines contents at once via node lists.

    After some more tests, I realize I now have to go about serializing the editor(my current implementation is explained below).

    I did have two types of questions I was hoping you could point me in the right direction of:

    1) - IMGUI
    Which is better for performance reasons. Custom nodes with Rects or Custom nodes using GUILayout.Window. I am guessing maybe the former?

    Will using nodes of dynamic size and displaying their contents be too much of a performance issue for the IMGUI framework.

    2) - Serialization
    I seen that most custom tools create an asset database file when the user wants to use the tool. I understand that this is for serialization reasons. But I noticed that playmaker seems to store its graph information inside each FSM component. It then uses asset databases for creating template files.

    I did research and had thought private variables with the SerializeField was how playmaker achieved this. Which is how I went about implement my own graph editor. But it looks like I need to re-read my understanding of how private variables with the SerializeField works.

    I am just confused over how Unity stores Component information vs Asset Database files.
    How can one achieve both use cases via a custom editor?

    Thanks for taking the time out to help answer my questions.
    I really appreciate it.
     
  4. shawn

    shawn

    Unity Technologies

    Joined:
    Aug 4, 2007
    Posts:
    541
    Twitter is reliable! Or Mastodon if you're feeling hipster-y. :)

    There's also a handful of Unity devs on the community slack. https://forum.unity.com/threads/slack-unity-dev-group.313672/
    I hang out in the #editor-scripting channel, you should join us!

    Yeah, IMGUI has performance issues, especially when it comes to graph-like systems. This is why we're currently developing UIElements, to handle non-inspectorlike windows. I recommend you take a look at that framework.

    If you still want to use IMGUI, I still recommend using the GUI(Layout).Window. Performance is going to be about the same, but the Window api properly handles event propagation for overlapping IMGUI elements (which happens quite often for graphs). If you can avoid using GUILayout and hardcode your Window rects, you'll get a performance boost. The layout logic is easily the slowest part of the IMGUI framework.

    Not sure I understand your issue yet, however, I can add some info.

    Unity's serialization system doesn't really know anything about assets vs Components vs ScriptableObjects vs whatever. When you create a object in Unity it's always initially serialized into memory. Then you can take that object and serialize it to disk using AssetDatabase.CreateAsset. You can do this with pretty much any Unity type that inherits from Component or ScriptableObject (and all of the natively backed built-in Unity types, like GameObject, Texture, Material, Shader, etc, etc.)

    When it comes to private vs public for serialization. Unity's serialization system just has default behavior for private (not serialized) and public (serialized) fields. You can add [SerializeField] or [NonSerializable] to these fields to change the default behavior. Personally, I like adding one of those attributes to every field (even if it's redundant) in a class just to make it super clear the intention.
     
    Last edited: Dec 4, 2017
  5. joduffy

    joduffy

    Joined:
    Jul 30, 2011
    Posts:
    30
    Awesome. Thanks for the invite and making me feel welcome.
    I have joined in on the Editor Slack. So I might see you there :)

    One thing is for sure. I am learning a lot more and growing taking on this project.
    So I appreciate all the help.

    I went through each of the Examples and created new files for them to see how they work. I did try and download a copy of the github project but got some errors:

    But I got some errors:
    UIElements - Reimport.PNG uielements errors.PNG

    But I am keen to make the node editor in the new UIElments.

    I managed to get the two approaches I wanted working.
    Which was to use an asset file and not need to use an asset file.
    So I now have a MonoBehaviour Component that uses a ScriptableObject to store data but doesn't need to write it to disk. But still persists through scene loads.

    The other is a ScriptableObjects that is written to disk which the MonoBehaviour can use.
    Before, I thought I could store this data in a variable that uses the [SerializedField] attribute. Maybe it still can. But ScriptableObjects are working for me so I am happy enough with that.

    My main issue now is to see why my performance problems are so high.
    High Performance Cost - calls and ms.PNG

    I have been looking through other node editors and samples provided online by others and the performance has been in the range of:
    Low Performance on another editor.PNG

    I am currently reading my way through this article to try and help me find the cause:
    https://unity3d.com/learn/tutorials...ion/optimizing-garbage-collection-unity-games

    All I am doing is creating an editor window, then I have two subview: one for a workview and another for a propertyview. In the workview I go through my graph and draw each node. I don't have any additional logic or code complicating the issue. Just drawing GUILayout.Window within a scrollable view.

    Thanks again for all the help.

    [Edit: I should have mentioned that the spikes in the image on the node graph, are created when I drag a node around to test how smoothly it updates. So far I have been creating 8 nodes and moving one of them to see its impact via the profiler.]
     
    Last edited: Dec 5, 2017
  6. shawn

    shawn

    Unity Technologies

    Joined:
    Aug 4, 2007
    Posts:
    541
    Your first profiler screenshot seems to show that there's a bunch of Debug.Logging happening every frame, which is quite slow because it needs to grab the call stack ever frame.
     
  7. joduffy

    joduffy

    Joined:
    Jul 30, 2011
    Posts:
    30
    Thanks Shawn.

    The Debug was what was slowing things right down. I didn't think it had that much of a performance loss. But it makes sense after all the documentation I have been reading through the Unity blogs.

    I am now going through and using Profile.BeginSample() to identify parts of my code taking the longest. It seems GUI.Utility is around 16ms which is a lot better than it was before.

    I did want to ask what this is:
    unaccounted time between guiutility process events and gc alloc.PNG

    With the new UIElement to replace IMGUI it says you can use IMGUI code inside of a VisualElement. There wouldn't be any performance difference between using pure UIElements vrs mixing the code with IMGUI, is there?

    From my current understanding, its just the OnGUI call that is the main bottle neck isn't it?

    I am debating whether to scrap all my IMGUI code and just use UIElments or wrap my current code inside a visual element.
     
  8. shawn

    shawn

    Unity Technologies

    Joined:
    Aug 4, 2007
    Posts:
    541
    OnGUI is only as slow as the stuff that's called inside of it. So the IMGUI controls within UIElements will have the same performance profile as other usages of IMGUI. With that said, UIElements can minimize the impact of IMGUI by only running the events on the visual elements that require it, rather than the entire window.
     
  9. joduffy

    joduffy

    Joined:
    Jul 30, 2011
    Posts:
    30
    Awesome. Well I will go and try my best at coding it up.
    I will keep you posted with screenshots and my progress when I have something to show.

    Thanks again for all your help.