Widget Components with Dynamic Instance Materials show default material in game

I have created a material that renders in-world UI as an LED board. It works pretty well, but it needs values passed to it to render correctly, namely LED width & height and the size of the widget in world space. This effect can only be achieved correctly/simply in 2 ways, via a custom dynamic material in a widget component, or in a Retaining Box. The custom widget material is the ideal solution as the Retaining box will double the render texture requirements of the system, which is not great.

This effect cannot be applied to the text widget correctly as the effect has a tendancy to clip and the LEDs misalign on a per glyph basis, which I don’t want in my effect.

Is this a bug in UE4 or is there a way around it?

Thanks.

Hey!

Just to make sure I got this right:

  1. You have an in-world widget with a Text Block on it so you can manipulate the message shown.
  2. You want to apply this effect on the text.
  3. You want to create a Dynamic Material Instance for this material and manipulate it with an animation.

All correct until now?

Your effect material needs an input to work properly. The only way to get that input (in your case text) would be render it out first. You are correct about the Retainer Box, it will render out its Widget children onto a texture and then you can apply your effect on that.

Now, about performance. In the Retainer Box you can tick the “Render on invalidation” box and untick “Render on phase” box. As far as I’m aware, this means that the Retainer Box will only re-render ONCE when one of its children components requests it (when a change is made) so it won’t be on every frame. In your case when you change your Text Block text it will re-render it once and you can manipulate that texture in your Retainer Box material. You can redraw the Retainer in-game whenever you change a value on a child component.

As for the 3D Widget component itself - it has its own re-render rules that you can access in its Details Tab.
Using the Redraw Time setting you can tell the Widget how often to redraw its contents. Higher values means more time between redraws.

So now we’ve told the Retainer to only Redraw once updated AND we can tell Widget how to often to Redraw individually.

I also made a little material that emulates what you have in your example.

Here is the final result.

319113-final-result.gif

Hope this helps!

1 Like

Thanks for the thorough reply and the solid advice! The performance is not really my concern though, I have already switched my Widget Component to manual redraw and that works fine without the dynamic material. My concern is the memory usage. The Retainer Box will create a RT which I can apply my effect to as you say, but then the Widget Component will render the Retainer RT to another RT, so for each instance of these world UIs there will be 2 RTs which feels like overkill to me (unless UE4 somehow uses the same RT from the Retaining Box and passes that to the Widget Component, but I highly doubt that).

All of that being said, I have a workaround that I like that is light on perf and memory but is slightly round about, I’ll post that as an answer though.

EDIT: This method requires a LOT of internal maintenance if you need to change your widgets text or animation or anything.

The solution I settled on is pulling the Render Target from the Widget Component and applying that RT to a material on a plane, the upside to this solution is that you can now apply UI to any mesh, so a full 360 cylinder is possible. Obviously this doesn’t allow for interactable UI, but for my particular needs that is just fine.

@JorjiCostava has a solid solution for others encountering this problem where interaction is needed.

Hey!

Thanks for the reply, this is a pretty elegant solution! You do lose direct interactivity but it’s an acceptable trade if you won’t be needing it AND I learned something new today. Never knew I could access the render target of a widget so easily, really opens up possibilities without the extra RT.

Cheers!

It’s not great in practice though, as soon as you need to change anything on the widget you need to do a loooot of maintenance to make sure everything matches up again. I found “the right way” though.

Okay, I found “the right way” of doing this is: use Widget Component > Get Material Instance. That returns the real Dynamic Material Instance that can then be modified in Blueprint and it behaves correctly too.

Low performance cost, low(er) memory cost, low maintenance cost.

1 Like

Noted. I might try this in a few projects of my own.

Meanwhile I found this article which is an absolute gold mine. It talks about the Slate system and how to optimize Widgets. A bit mind numbing due to the sheer amount of things to watch out for but it’s worth checking out.

1 Like

Hey! I’m probable too late, but I hope it helps somebody…
I wanted to increase the emissive intensity of the widget. So I created this simple material:

And this is what I use to change the intensity runtime:
image

1 Like

Nice find! What is the Material Domain, Blend Mode, and Shading Model for this?