UMG parabolic distortion effect

Hi,

I’m trying to make HUD that looks like it is projected on a helmet visor or something like that. So I made a widget and set “parabola distortion” value. But there are two things that I don’t know how to resolve:

  1. Widged itself intersects with world objects.

  2. Widget “suffers” from all post process effects, like motion blur.

So it is kinda useless to make HUD this way.
Is there any way to fix this or maybe there is another (better) solution for that goal that I’m trying to achieve?

Thanks and sorry for my bad english! :slight_smile:

Well, after some research I’ve found a way to do it. All in Blueprints. It’s a bit weird for my opinion, but here we go:

  1. Create standart UMG UI, and add inside it all what you need to be shown.

  2. Create new BP and in seach field for the base class select SceneCapture2D and set it somewhere in scene (under floor or in any “hidden” place)

  3. Add Widget inside this blueprint in components section and apply your UMG to it and set parabola distortion value like 0.3 or whatever you fell ok. Move Widget in position to be correctly shown in SceneCapture2D camera (+you need to rotate it to 180 by Z).

  4. Create new RenderTarget2DTexture and set size to 2048 (for best quality) and apply it to your SceneCapture2D as texture target.

  5. Select your SceneCapture2D BP in a level and in details tab go to Scene Capture section and open Advanced (little arrow). Turn off all flags except Translucency (so we will get on render target our UMG Widget and nothing else)

  6. Create new material (in material domain - user interface and set it translusecent)

  7. Add Texture Sample and assign to it our RenderTargetTexure. Connect color → final color and alpha to opacity (but use “1-x” operator since we need to turn “translucency” to “opacity”).

  8. Now create new UMG (this will be our “desired” UI), create image inside (set it to full size) and apply to it just created material. This is your final UI, add it to viewport.

  9. PROFIT!!! :slight_smile:

It’s a bit complicated in words, but pretty simple in action. Feel free to ask questions if you need some explanations about it.

Well, now pros and cons of this method.

PROS:
Since you “rendering” your UMG through SceneCapture2D, you can “break” your UI to parts and align them in front of the capture camera in different angles to get cool effects.

CONS:
In the end you showing on screen not actual UMG, but an “image” of it, so adding input for it will be tricky (but possible!)

P.S. I will be happy to hear other solutions how to render HUD in 3D space.

There is a better way to do it right now (since UMG has RetainerBox):

  1. Create desired HUD via UMG blueprint.
  2. Create another one (lets call it container), use RetainerBox and put first UMG into it.
  3. Add container to viewport.

RetainerBox allows you use UI Material to process it’s content. So now you can apply material with any desired effects. For example you can set up parabolic distortion like that:

3 Likes

I just wanted to say that your solution works out really well Airuen. I had tried the instanced screencapture technique and it has all kinds of problems. With a UImat and a Retainer box you can build a UI just like you would normally without doing any kind of wonky workarounds. Thanks!

How you did rotate image? Как ты сделал повернутое изображение HUD

Hi Airuen, I know this is a really old post but on the off chance you will see this message I want to ask a little about the material you show here. I created this material copying the screenshot but for me it shrinks my UI vertically and then tiles it vertically, meaning my UI exists like three times on the screen, really scrunched up vertically. The screenshot doesn’t show the values you have in your TextureCoordinates, so I just set them all to 1, 1. Maybe this is the problem? Could you tell me what yours were set to? Thanks!

Hey MarsMiner, I got your solutions!

While Airuen did most of the legwork on this, they did not provide a couple critical bits that I had trouble with. But we figured it out!

  1. I’ve attached a picture with the RIGHT side of his material graph, for anyone wondering what the heck was going on over there. I have NO idea what their “BackColor” vector parameter was for, I did not use it.

  2. You MUST set your material (by clicking on the final input node) to Material Domain: User Interface, and Blend Mode: Translucent.

  3. The name of your Param2D must also be put into the Retainer Box “Texture Parameter.” (Shown in one of my screenshots there as well.)

  4. Your HUD will repeat. So to fix that, you will need to click on the Texture Parameter 2D (SlateUI or whatever you’ve called it) and set “Sampler Source” to “Shared: Clamp”.

The float 0.2 worked well for a ParabolaDistortion value, but you can tweak that to whatever you want. Boom, that’s it. Enjoy your curved HUD!

  • Zag

Thanks so much! I had almost given up on this. However my widget now no longer interacts properly. When I hover over a button, it doesn’t detect it but when I hover just under it it does. I think perhaps the effect material is not distorting the interaction in any way. How can I work around this?

Unfortunately not. I actually wrote a blog post detailing how to set all this up, including a note about this issue.

The problem is this is only a shader effect, which means it’s visual and has NO bearing on what you’re actually clicking on – that is to say it makes absolutely no change to the actual borders or shapes of the buttons in screen coordinates for your mouse cursor.

Right now the only “solution” I can think of is making your buttons invisible and extend them differently based on the curve, but that sounds like a total mess to work with and I would not recommend it at all. So for now I would only recommend using this effect on HUDs and other things you never click on with a mouse cursor. (It would also work on console/gamepad only games, since there’s no precision cursor in those, typically.)

Hope that helps.

Sorry to drag this back up but I just had one question about a slight modification to the material.

Right now the material makes it look like the HUD is on a curved surface, but only curved in one direction if you see what I mean. How could I make it so it looks like it is on part of a sphere that is curved in both directions? I’m not sure if that makes sense…If it doesn’t I can try to explain it better.

Unfortunately that’s not quite what parabolic distortion does, and I don’t have the mathy skills to figure that one out.

If you make your UI less wide it will look more like a sphere, but that’s all I could suggest right now.

OK don’t worry. Thanks for the help!

If you want distortion along X and Y google “barrel distortion”. But I just want to say that due to its nature you will achieve really weird and undesired corners: how to make lens distortion work? - Cinematics & Media - Unreal Engine Forums

Hi there, just wanted to confirm one detail.

The TextureSamplerParameter2D node, what exactly are you using for the texture base? Just a plain white box texture?

In the Retainer Box details panel (in the Designer panel of your HUD) you will see “Texture Parameter” with a blank input. Make sure that says SlateUI.

Follow my blog post if you get stuck. [see Step 3]

Hi all, has anyone solved the problem with mapping mouse coordinates to the distorted UI? Thanks

Well, I actually tried to use the brain and i figured it out :smile: … sort of.

So how to compensate mouse coordinates to HUD / UI distortion?

TL;DR: You hide the mouse and create “virtual” cursor that will be updated with recalculated coordinates.

  1. HIDE mouse cursor from UI
  2. Create a custom “virtual” cursor brush / texture
  3. Calculate new cursor position using the same algorithm you’re using to distort UVs of your UI (inversely)
  4. In OnMouseMove or OnPaint, move your “virtual” cursor around using these recalculated coordinates.

Problems:

  1. It gets a little lag but it’s bearable.
  2. Some components (slider, text box, etc) that change the cursor needs to be told not to do that
  3. The “curvature” is not exactly same in the viewport and in the material. But I expect I’m having some basic mistake there that will be fixed.

Try it out. If you have found some better solution, let me know :slight_smile:

This is my current implementation:


1 Like