A question about UI optimization with Unreal (Compass)

I’m retired now, so this is just idle curiosity.
But back when I was working on game UI one of the things I worked on several times with first/third person games was the compass. I never felt I implemented compasses very well and wondered if folks could point out better ways to have implemented them?

As an overview of a simple HUD game compass, here’s a screenshot from the recent Elder Scrolls 4: Oblivion Remastered (courtesy of https://www.youtube.com/watch?v=Bz5c51p-MCQ ) that shows their Unreal 5 engine compass in the upper center.
NOTE: I did NOT work on this game, nor ever for any company in the Zenimax family.

The main compass UI appears to consist of:

  • a foreground consisting of the opaque boarder
    • The nub in the bottom center indicates the player’s direction of view
  • the (moving) data layer(s), consisting of the vertical ticks along the bottom and the compass letters
    • only the four cardinal compass points (N,E,S,W) are displayed in this game, indicating positions 90 degrees apart
    • the vertical ticks are indicating 22.5 degree separations
    • this data can also display other icons, such as quest markers or certain locations
  • a semi-transparent black background (which probably conforms a few pixels smaller than the shape of the foreground

In the screenshot, we see that the ‘S’ is partially vertically faded, indicating that either a mask or gradient (shaped) image was used.

My compasses operated the same but I always felt my compass mechanisms was using too much processing time.

For my data layers, I would normally:

  • use a mask to fade out the left and right edges
  • use a premade 0 - 360 degree image with ticks as a background layer for the data
    • I thought this was better than dynamically moving a bunch of text fields for the each 22.5 tick.
    • The cardinal labels would be dynamically-instantiated text fields, attached to the premade data image
      • Many countries do use the same letter abbreviation for directions but not all
        • Yes, most countries accept games with the English versions being used, but that’s not really embracing localization
    • The code would move the premade data image (or rather a containing object) back and forth horizontally, based on the player’s directional vector to the map’s North.
      • Moving the object would, of course, also move any attached text fields
      • Initially, this would be done in blueprint, then moved to an ActorCompass C++ component once the compass interface was established and working.
  • insert additional marker references for a compassUIIIcon data asset table into each actor or object that would have icons on the mape. The code would attach the icon image onto the data layer relative to the correct position ( actors would also be labels at positionally-static or not, so the system would know to update their position more often if dynamic - usually about every 1/10 second seemed ‘comfortable’).

Initially, this would work fine until the player turns more than 270 degrees or less than 90.
Because then the edge of the premade data image would be seen.
So additional images were put on each end.
These were not new images but instead - because the premade image was already cached in memory - duplicates of the premade image. The edge masking would block any extra from being seen (and since the data layer masking was set to allow visuals instead of blocking them, it didn’t require a mask the size of all 3 premade image instances).

So, that’s the whole sloppy mess (in a looong post).
One thing I could have done was bake the compass directions into the premade image and just make localized versions when needed and load the appropriate premade image based on the language chosen.
But I’m wondering what better ideas others have come up with that I just never thought of?

1 Like

Yeah, this is pretty similar to how I would handle it (coming from someone who does materials, not necessarily UI).

I think the biggest optimization you could make is controlling changes within the shader instead of through external code, since then you wouldn’t need to update the player/camera direction every tick.

This gives you a full 4 point rotational value in one float, which you could then modify to the correct range and add to your texture coordinates to get your compass rotation. This would also theoretically give you perfect tiling.

I imagine the map icons would still have to be controlled through code though, as doing it through a shader would be pointless unless you have a set maximum number of markers and that number is reasonably low.

For the localization issue, I imagine the best solution that mixes optimization with ease of use is to separate the 4 cardinal values out into a separate texture, which you can then easily replace with the correct letters, like you mentioned. Then just apply the same rotational logic to keep it in line.

Totally just my opinion as a non-expert! Sounds to me like the way you handled it makes complete sense.

1 Like

Well I think your method is already highly optimised and its a constraint between performance, usability and quality how we nail down things.

Using atlas is a common method still in UE however new compass and ux requirements are much more demanding, landscape is changing and leaning towards UX more.

New compasses like, animated icons, Icons transitioning between compass and world, dynamic distance texts, 3d rotations and many more. Depending on the game/engine I used different approaches and in UMG, I generally go with materials on shader level solutions.

One of the approaches I used is: having a compass manager spawning indicators that is relevant to the players look direction and discard if not look direction or relevant ( like distance too much). This enables to control sizes and emphasis on objectives in different scales, colors, so player can know what is a meaningfull target just by looking. Still this is not less costly than yours but have different pros ofc.

Worked on some different compasses or atleast be in the team working on those in a compass that has vertical information also directional.

An interesting one that i did using another engine for a space game prototype.
On that I literally used 3D thin cylinders with textures and actual objects embedded on it. Rendered with additional camera as overlay into a shader, where actual objects are in world but not player viewing. It was cost efficient even though it doesn’t sounds like that.

Interestingly this apprach enabled couple of things. First the animations are super since its real 3D they ease out in the edges even turn before dissappear, thus gives a super realistic feeling almost like a gyroscope feeliing or analog ui. (I love physical interfaces)
Secondly, it gave me some more artistic advantages like adding physics to 3D meshes. So when vehicle is hit or there is a acceleration, those effects are visible on compass. Think I can do that in unreal too but don’t think would be nice without writing something custom to viewport hud renderer.

Edit : Maybe can do something like that with niagara actually, could be an interesting one.