Tutorial: Dynamic "Mesh Widgets" -- *Now with 33% less voodoo required!*

Dynamic “Mesh Widgets”

When I envisioned my inventory system, I pictured a rotating 3D representation of the item as a tooltip. This turned out to be quite a bit more complicated than I anticipated, but I believe I have landed on a good solution, being a Widget class that only requires a “Mesh” input at its creation. Bonus: all in Blueprints!

Link to higher res

Before we get started, props to for writing a good starting point for projecting meshes into widgets. A good primer just in case I don’t explain this well enough.

1. Create your assets

5084f55456c0a2d6475933ae0f59767523d98843.jpeg

A. MeshWidget - This is a standard “Widget Blueprint” that we will use to project on the screen.

B. MeshWidget_actor - This is a standard “Actor Blueprint” that we will use as the 3D visual.

C. MeshWidget_mat - This is a base “Material” asset that will be used to transfer the visual from the actor to the widget.

2. Setup your material

A. Open up your MeshWidget_mat material. It should be a base, empty material with just two nodes.

B. Right-click in empty space, and type TextureSampleParameter2D. This should allow you to create the node you need.

C. Name the resulting node anything you want, but remember what you named it. I name mine Source.

Co5Ccg.jpg

D. Configure the Result Node to use the Material Domain: User Interface

E. Lastly, ensure the two nodes are connected as seen above, and you’re done.

3. Setup your actor

A. Open up your MeshWidget_actor. It should be a base, empty actor with just a DefaultSceneRoot.

B. Add a SkeletalMesh component. Configure it for any mesh you want, or none at all. Name it something you can remember. (DollMesh)

C. Add a SceneCaptureComponent2D, and move/rotate it to face the SkeletalMesh. This is your camera. Name it something you can remember. (Mirror2D)

0662785601b0ca34bd5ac7b3ba234bd6e0ce9016.jpeg

D. The above two components are the only ones truly necessary to make this actor work, but this is where you have artistic freedom. I personally added a backdrop using a StaticMesh, and some fire effects using a ParticleSystem. Add whatever you want, so long as you remember…

E. Configure the Rendering and Collision settings for every component you use. You do not want these showing up in the world or colliding with anything. The principle method to achieve this is by checking the OwnerSoSee option.

3bb3cfdd8918e633d590df35630c90220bf810c9.jpeg

F. Head on over to the EventGraph, and create a new Function that we will use to setup the camera. I named mine MakeMirror.

G. Configure the function like so:

c6084869f793dca37afa04654c6f55e92b49a569.jpeg

H. This is the juicy stuff… but it’s not as complicated as it looks. We are dynamically creating a new RenderTarget2D, and configuring our Mirror2D (facing the mesh) to send its live feed to it. We are then going on to create a dynamic instance of the material we made previously, and assigning its Source to our new RenderTarget2D.

I. On the tail end of the function, promote the dynamic material we made to a variable for future use. I named it MyMirror because it’s essentially a 2D image of what’s going on with that actor.

J. Head back to the event graph, and configure a new SkeletalMesh variable. This is what we’re going to use to be told, at the time this actor is spawned, what mesh to put on display. Ensure that you check Editable and ExposeAtSpawn. This allows us assign this variable to something at the time of spawning it. I named mine InputMesh.

K. Next, Configure the main event graph like so. Note that we are taking the aforementioned InputMesh and using it so set the DollMesh in the scene. Immediately following, we run the MakeMirror function we just created.

L. The rotation Tick event is not necessary, but looks really cool.

4. Setup your Widget

A. Almost done! Open your MeshWidget. It should be blank.

B. Configure your variables like so. You will need a SlateBrush, Actor, and SkeletalMesh. For the SkeletalMesh, ensure that you set Editable and ExposeAtSpawn the same way we did before. You’ll see why in the next section.

ed2a9890c7d12e308508cfe930cbf02168e76869.jpeg

C. Next, configure your ConstructionScript like so. Note that when we select our MeshWidget_actor as the actor to spawn, we get a handy little pin to set the mesh! Thanks, Editable & ExposeAtSpawn! Also note (and make sure you don’t miss this…) that the owner is set to the player’s Pawn. This is very important, because the previous OwnerNoSee option will not work otherwise. After elevating the resultant actor to a variable for future use, we take the actor’s MyMirror variable and assign it to a brush variable.

20763b2e8101b4e3672cf83d5a9c6704d3438d30.jpeg

D. To keep things clean, I added an EventDestruct event that destroys the actor we spawned. This way, when the widget dies, so does the actor.

E. Finally, in the Designer tab, make an image of some sort, and Bind the Brush Variable we just made to it. Like this:

b4afce0aac07d1e532e3d0f5677e49bf2db5f649.jpeg

D. You’re done! Let’s make some Widgets!

5. Create an instance of your fancy new widget

A. Because we made sure to configure our InputMesh variable correctly, we can assign any mesh we want at the time of creation:

1b5a39c5eb077dbf324401c66a50055cd229c8a8.jpeg

I hope this helps some people with the same goal I had. There are plenty of possibilities in modifying and improving this method, using the widget to take mouse input and rotate the actor for example. Like this. Please let me know if I can answer any questions, you have suggestions to improve the tutorial, or you see a typo.

Happy Blueprinting

1 Like

This is awesome, thanks!

This is a very nice tut, thank you

Great tutorial, had it up and running in no time at all.

Unfortunately I found it also to be really laggy to use a render target, even with low resolutions (not a reflection on this tutorial in anyway!). How are you finding the impact on frame rate? Do you have any idea’s for making it run better?

I tried having it capture only base colour/really low resolution but it seemed like just adding a render target at all had a fairly substantial overhead.

I tried spawning 10+ of these instances without any issues, but maybe I’m not being considerate of setups without a high-end card. Where are you changing the resolution? The only place that makes sense to me, as far as performance impact goes, is the “Create Render Target 2D” node. I set it to 256x512, which seems relatively tiny to me.

Also, is the “Show Only Actors” node configured correctly? I can see a significant performance hit if the Capture2D was capturing the world and not just the actor.

[edit] Also, check your object window when the game is running for how many actors you’re spawning. I made a mistake at one point when configuring tooltips, and ended up spawning hundreds of such render targets.

I have the “create render target 2D” set to make 128x128. The “show only actors” is definitely only rendering the one actor I have placed. When opening just widget I don’t see much/any impact but as I open more the frame rate loss per widget grows rapidly. By 9 render targets (The minimum I think I would need at 128x128) the frame rate of the game has more than halved for me. This is on pretty high spec computer (980ti). Maybe something else is causing the lag though since one on its own has little impact.

Edit:

An image so you can see what I am looking at. With 9 128x128 renders spawned randomly around my frame rate drops to around 45fps average. before spawning any I am at 90fps average

Hate to say, I’m not sure. I will explore this myself as well. Maybe try spawning some instances without a mesh? That can isolate whether it’s the capturing or the shear polycount you’re creating.

Game looks sweet by the way.

Thanks, and thanks for responding! I’m testing stuff out right now to see if I can isolate what causes the lag. Some stuff I’ve tried so far.

  • No meshes
  • Checked I am spawning only 1 actor as you suggest
  • Disabled fancy things like distance field lighting
  • played the game in unlit mode
  • Turned FPS cap on/off
  • Triple checked everything is plugged in and doing what it should be

If I set the render targets to not render every frame (so just doing an initial image) then there is no lag. I tried playing around with the framerate by making the render targets not update themselves and instead have a timer tell them to update but it behaves very strangely. If the timer only fires 10 times a second they seem fine but if I set it to fire 30 times per second the game crushes to a halt (1fps~ with 9 instances of the actor) for some reason so perhaps the manual capture isn’t as efficient as letting it manage itself.

As far as I can tell if there is multiple render targets, so long as they are rendering per frame, regardless of size, the game will start to accumulate lag. But if you can open 10 instances of your 256x512 renders without notable slow down though something else must be causing this in my game. Which I really hope because I would love to get this working in game. I appreciate any help or further ideas/testing you might have.

So I did some testing as well, and found that changing even the capture resolution did little to change the performance hit. (I did see a performance drop after 12+ instances…)


Unfortunately, outside of limiting the FPS or number of instances, this method is probably only reliable for ~5 or so at a time. Sad times. Thanks for working this, .

I think the rendering impact is in the cost of switching between render targets. No matter how big or small it is, setting up a second render target has a fixed overhead.
(Also, that overhead may be more dependent on your CPU performance than your GPU performance.)

If CPU truly is the bottleneck here, the performance increase is starting to make more sense…

Db1NVL.jpg

That’s unfortunate, still great implementation @Bewbies! Thanks for double checking for me so that I can rest easy. On the UE4 roadmap they have 3D models in widgets as possible work for January and February so maybe the concept can be revisited if the functionality is added in a more official capacity.