A Unity Programmer in Unreal Engine’s Court: Editor GUI Programming

Time for a snapshot of the kinds of details that video game programmers often have to fuss over when learning a new system. This time it’s a comparison of Unity and Unreal’s editor GUI frameworks.

In Unity3D, the editor GUI system is quite well-documented and understood. You fill an OnGUI function with all the functions that display your GUI.

LabelsDisable.png

Source: Unity Script API reference, Editor.OnInspectorGUI page

This is called an Immediate Mode GUI. Every frame that the GUI is displayed it looks at all of the functions being called as instructions on what to draw, what not to draw, and how the GUI should behave. It’s all fairly well-documented via Unity’s script API, which makes it fairly easy to learn the basics of how to create new editor GUIs.

So, what’s Unreal’s equivalent?

… Time to vent for a little bit.

ItCompilesButWhy.PNG

This is Slate, Unreal’s UI framework, in action. It’s the system the editor is built on and, ultimately, the underlying system for ingame HUDs in the Unreal Motion Graphics editor.

Those of you who aren’t programmers probably don’t see what’s wrong with the above. Those who are programmers and familiar with C++ are probably getting a sense like you’re looking at the first page of the Necronomicon. It is distant and arcane from recognizable C++ programming, and also likely the most poorly documented aspect of the engine.

I’m slowly beginning to understand how to work with it as I start to equate the Slate syntax with all the widgets you can use in the UMG editor.

For instance, SComboBox…

ComboBox.png

… is basically a representation of this guy…

ComboBoxReal.png

… which is found here:

RightHere.png

Therefore you can take most of the things you see in the UMG palette to be viable SWidgets in C++. Just put “S” in front of it, and bam. The square brackets, likewise, signify what’s nested inside that widget if it’s capable of acting as a container, and those chained function calls you see are parameters that you could otherwise edit and bind in the details panel inside UMG.

Likewise you could, just like in UMG, create custom widgets with encapsulated code for handling their own variables, input, and messages. If you get the hang of the widget definition syntax this is actually pretty quick to do.

… Other than the total incomprehensibility of any of this code to either Intellisense or Visual Assist, which both regard Slate syntax as completely alien and have little way of suggesting the correct way to use any of its functions. … Which are barely documented.

What’s especially not quick is deciphering which part of the editor framework you’re actually meant to be working out of for a given task. Here’s an example from my camera plugin:

TransitionInfo.PNG

I’ve got a custom struct for camera transition info. Thing is, not all these parameters here are useful all the time. If my camera transition type is a Hard Cut, for instance, I really don’t need transition duration, ease type, or ease power to be a thing, because the transition is an instantaneous cut to the next camera position. Ease Type is only relevant if the transition type is set to “interpolate,” and Ease Power is only relevant if the Ease Type is set to EaseIn, EaseOut, or EaseInOut.

Bottom line: I could do a lot to hide irrelevant information and convey to the user what items actually do stuff.

So I look into Details Customization a bit and find there’s a few different options for handling this kind of thing. You can customize a full Details Panel, or you can do a Property Customization, or there’s also a Struct Customization.

Score! I have a struct, I’m customizing it! Struct Customization go!

AllOfWhatsUseful.png

There’s the bulk of what’s useful — a function called Customize Struct Header and another called Customize Struct Children. They do what they sound like — handle the customizing of the Header and all the child elements of the struct respectively. You write slate code inside of them.

LikeSoMore.png

Like that. “HeaderRow” and “ChildBuilder” each are respectively the items that are responsible for creating Slate widgets. The “Handles” here are individual properties that live inside the struct. Once you’ve got them you have access to any and all information you need to build your details customizer.

Except this part.

ExceptThis.png

This was the important part. This was the whole point of customizing this display in the first place. Basically, if the transition type isn’t appropriate to display these values, I don’t want to display them.

Problem, CustomizeStructChildren gets called exactly once, and that’s when you select the object and display this struct in the details panel.

There is no message included in this customizer for when its values get updated and no means of telling it to “repaint” the details panel when these change. You either need to re-open the menu this struct is being displayed in or hit the “Compile” button to force the editor to repaint, otherwise those “if” values up there will never get updated.

Some slate widgets have the ability to add an OnValueUpdated-type message to them through their Slate parameters, but sadly there isn’t any means of feeding these functions the ChildBuilder so that you could ask it to repaint.

This, then, makes the concept of “declarative syntax” extremely clear. Your widgets work by simply building them and feeding them callbacks instead of using an “On Update” function that re-draws the GUI each frame. Since it draws once, and otherwise re-draws specific widgets on demand, Unreal’s very very fancy-looking GUI doesn’t actually soak up that much processing.

For this reason Unreal’s GUI system is infinitely more efficient resource-wise than Unity’s, which becomes hugely consumptive when displaying large amounts of data.

But it sure doesn’t make my intended customization easy to implement. There’s quite a lot of callback gymnastics that have to be done before that can be the case. What’s very likely is that I actually have to code a custom Slate widget and nest all the information I need to draw my struct inside that instead of trying to use the Struct Customizer … ostensibly for its intended purpose.

What bothers me is that at some point in the process someone at Epic did think about the need to do exactly what I’m trying to do, and in fact implemented it in the one and only official details panel customization tutorial. Observe:

NoneOfThis.PNG

That code, followed by all the gobbledegook inside the Lighting Category code, creates…

multibox_layout_horizontal.jpg

Source: Unreal Manual “Details Panel Customization” page

That is almost exactly what I’m trying to achieve, but the functions necessary to create this kind of layout are part of class customizers rather than struct or property customizers. This information here isn’t all contained inside one struct, they’re class members, along with all of whatever else was attached to this. So to utilize this method, I have to customize an entire class‘s details panel.

By contrast, Unity has Property Drawers.

PropertyDrawer.png

Source: Unity Script API reference, PropertyDrawer page

These have some obnoxious limitations as well, but they do work using rules consistent with the rest of Unity’s GUI system in that it’s still an immediate mode system, therefore you could take your custom serializable class and show and hide its sub-properties based on whatever logic you’d like.

This would apply across all uses of that custom type, whereas a custom Inspector window would only apply to… well, that one Inspector window.

That’s the limitation I am currently facing. What I’m wondering is if I can create a widget specific to this struct and then substitute in that inside my struct customizer. I’d be sort of crossing my fingers that slate widgets have their own internal capabilities to call a repaint on themselves.

What I think you’ll agree with me on in reading this is that it seems like you’ve got to do an awful lot of work just to hide a couple of unwanted variables. I have to wonder if I’m missing something.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s