Tutorial recommendation for aircraft-style HUD

I am going to implement a HUD like they have in airplanes:

image

I don’t actually do anything advanced. There is no need for the HUD to appear on some plane/windshield in the 3D world. I am fine with the HUD being a 2D interface. On top of that: no input wigdets (no buttons, no sliders, no text input).

I am browsing tutorial for quite a bit now, but none of those showed me how it’s done.

I am wondering

  • Am I going to have to use Slate/UMG?
  • Does my combination of Blueprint (for prototyping and assets) and C++ (for more complex programming logic) apply here?
  • Am I going to use widgets?
  • Given that I will just be drawing green lines and text: Should I create my HUD entirely in an image manipulation program like GIMP or Photoshop?
  • Related to the above points: How to draw a green bezier curve?
  • Is there a more suitable, more low-level alternative to Slate/UMG?

All help, any hint, any comment is appreciated

1 Like

Congrats on being one of the only google hits for UE aircraft huds. Did you ever figure it out, and if you did would you be able to point me to any resources you found helpful?

Thanks

Hi, so I am still busy developing other aspects of my game and did not try out a whole lot more with the HUD. But I learned a couple of things:

Drawing the HUD

I am still playing around with NativeDraw and a couple of helper functions to draw basic shapes (and bezier curves). I haven’t managed to make them look nice. They lack anti-aliasing. I will have to switch to 4k images. And even the most basic lines, I am going to produce in GIMP.

To me, this is a major pain. No clue how quickly I will get to a beautiful HUD. I am lacking experience in this kind of 2D graphic design. And thus i still need the tutorial. Maybe a simple “making a HUD in unreal” will still be useful to me.

I do think, however, that this is quite a design challenge. Right now my HUD looks amateurish. Reducing everything to green lines is quite a constraint.

Projecting points from 3D world to 2D

there is the simple case, where I place a HUD highlight on top of a 3D world actor that flies across the screen. Think of a green circle around an object you can target. In that case you can just use one of APlayerController::ProjectWorldLocationToScreenWithDistance or UWidgetLayoutLibrary::ProjectWorldLocationToWidgetPosition. I prefer the former, because the second one does stuff that I don’t understand. The second one also correctly deals with your viewport scale, which you need to apply manually with the first one.

Projecting whole meshes from 3D to 2D

Sometimes you are not done just projecting a point. I successfully set up a SceneCapture with a RenderTarget that I then show in a widget as material. I have the SceneCapture render only one whitelisted components, using

USceneCaptureComponent::ShowOnlyComponent and ESceneCapturePrimitiveRenderMode::PRM_UseShowOnlyList.

The render target covers the whole screen and needs to adapt to changes in the screen resolution. The result is a 3D mesh rendered flat on the HUD. In my case, the 3D mesh is a splinemesh that visualizes a trajectory of a floating object. Rendering the spline mesh inside the 3D world kills immersion.

I tried to construct the same visual effect in the HUD by calculating the 2D trajectory from the 3D SplinePoints, then using native paint to render it - but this turned out practically unfeasible. I got close but there were too many edge cases and my HUD trajectory was jumping around at times.

Project the HUD on a curved window/visor

“Project” here means a real-life optical projection.

I achieved a decent curved effect using a UV transformation with the RetainerBox widget. The problem, however: When you put the “curved UV transformation” on top of your widgets, you loose control over the exact position of widgets relative to the 3D cockpit. E.g. drawing a straight line in your HUD becomes a major headache. Drawing a proper curve that follows some window frame of your cockpit is suddenly impossible. “So why don’t you just apply the curved transformation on some of your widgets?” you ask. Well one of my widget is an arrow that follows some target when the target is off-screen. This arrow has to move along the HUD borders. Removing the curved effect on the arrow makes it jump out compared to the rest of the HUD.

I will have to see whether or not I put the curved transformation on top of my widgets (or some of them) when I put everything together.

Thanks so much for this reply! at the moment, I’m most unsure about how to get the moving parts of altitude and speed indication; I think both should be dynamically generated and placed in the widget, but will need both to move and be properly masked. If I find or figure out an implementation for that I’ll put it here.

1 Like

Hi!
After a bit of work, I managed to get a pretty good looking display for airspeed in the style of an aircraft hud.

Here’s how I did it: first step, get a canvas set up to cover the area you want your speed notches in, and set it to clip to bounds, like so

I populated mine with a function that just spins up a bunch of “notch” widgets and parents them to the area canvas during initialization (the notch widgets are the moving displays of airspeeds above or below your current). These widgets will display the speed values. These are all anchored to the top right corner of the display widget.

The real magic happens in the function which ticks the display area. It’s a monster of a thing, so here it is in two images:


Basically: we take in the canvas we’re ticking (my final widget has two of these canvases, one above and one below the current speed display), a display value (in this case our actual airspeed), a notch interval (do we want a notch every 10 knots? 20? etc), some vertical offsets (these say how far outside the canvas to go; if these are zero notches will seem to snap around whenever they hit the bottom or top of the display area), and a boolean which says whether the displayed value is above or below the canvas.

We use this information to figure out what the biggest and smallest airspeed values which we can display in this area are, and to figure out exactly how big the area in which these notches can be is.

In short, we now have two ranges; the first represents the range of airspeeds we’re showing, and the second is the ranges of positions we can display those airspeeds in. Positioning the notches is a matter of mapping one range onto the other.

Now, we go through the children of the canvas we’re ticking; these children are all the display notches. To find the speed displayed by the first one, we just snap the display value to the multiple of our notch interval immediately above it (that’s what the ceil with division/multiplication on either side is doing). To find the speed displayed by the second one, we just add the notch interval to it. For the third, we find add twice the interval, and so on (i.e. multiply the array index of the child by the notch interval and add to the “base” value).

The last step is to position things, which is pretty straightforward. Find where in the range of displayed values the thing lives, get that as a fraction, multiply by the range of positions we can have, and add to the “base” position.

Set the offsets as you like, and make sure that “notch display size” is set to the vertical size of your notch widget.

This was a rambling writeup which probably makes no sense, but feel free to ask questions if anything is unclear. At some point I might clean this up and turn it into a forum post, but that will be for another less busy day. Hope this helps.

1 Like

do you mind sharing a screenshot of the result?

I think the process of displaying numbers in the HUD, i.e. setting the text of widgets, is something I understand. It’s part of any HUD.

For an aircraft-style HUD, …

  • :white_check_mark: … the widgets move and rotate - ok, that’s something I know how to do, too.
  • :white_check_mark:… there are widgets that follow the 2D-projection of objects in the 3D world (I have that working in two different ways, see my latest reply above)
  • ☐ … there are a lot of green lines, which I would like to control with NativePaint, but I probably have to use images (this is something I don’t know how to go about), to get those lines anti-aliased
  • ☐ … one might want to see a projection of the HUD on a bend surface, see my last reply (not sure about this)
  • ☐ … I am interested in creating the visual effect of an actual HUD, real HUDs do have some depth of vision in them and the lines actually glow (maybe using an emissive color works for this)

Result
This is what the bar looks like. The diagonal is due to a skew render transform. In order to get green glowey lines, I’d use a tool like Inkscape to make the textures and then import them, and get any diagetic glow via materials. That’s how I got the shadow effects, anyhow.

2 Likes

awesome, thanks. Looks quite good!