In this episode we’re going to take some skeletal meshes and create dynamic icons for them to use in Unreal Engine.
This will be used to extend our inventory base in this post and the result can be found in the next post here.
The details for this post can be found in this video
The intention here is that I bought several assets for equipment, but they did not come with 2D assets – so I wanted to generate them dynamically.
I was thinking I could manually open each asset up and take some images for them, but that felt like it could take very long time, so I wanted to make something that would essentially dynamically generate the 2D assets for me run-time while I only provide the skeletal meshes for the items.
The inspiration for this came from the following video tutorial, and it will be a pre-requisite for the steps that I will cover below.
How do we generate the 2D assets?
From the YouTube tutorial above, you will come across 4 files that are created for this.
- 3D Mesh capture blueprint
- Mesh render target
- Render target material
- Widget with image displaying the material
Let’s discuss each file and what it’s purpose is and how we’ve modified it to get the results we desire.
3D Mesh capture blueprint
In this Actor
blueprint class, we have
- Spring arm
- Scene capture component 2D (held by spring arm)
- Skeletal mesh (as a variable – which you dynamically will change)
Here you may want to play around with some ‘default’ settings. For example I wanted my items to always have a bit of a curve to them and predefined rotation so I updated them in the skeletal mesh
settings.
You can set a skeletal mesh and play around with the settings to your liking.
Now let’s go into the construction script
This is doing quite a few things
- Show only actor components – this is covered by another tutorial, we only show actor components in the scene capture, no background is included – this prevents overlap of items
- set skeletal mesh (dynamically)
- Reposition to make item appear more in center
- update camera distance to handle zoom
Let’s talk a little more about step 3 and 4 as those are a bit more complex.
I inserted multiple items of varying length and height and their positions were a bit all over the place without those two steps.
I found that I needed to get the mesh to appear exactly center of camera, which was not happening by default – i.e. take a look at screenshots:
However some other items appeared completely different, like so:
The properties simply varied from mesh to mesh, so I tried to find programmatic way of adjusting it.
This is where Get Component Bounds
came into play
I will give quick sneak preview of me spawning
this item into the world:
This is where the -100
came from – this has to be the same as whatever you’ve set this to.
I.e. The component bounds provided the delta from the center, which I used to adjust the position of the skeletal mesh. Maybe there’s a better way of doing it but this is one solution that I’ve found that seemed to work.
Next, I adjust the spring arm length, which determines how far the camera is from the skeletal mesh that you’re capturing.
Note that I’ve set the SceneCaptureComponent2D
projection to a field of view of 30 degrees – which I believe means that for every 1 unit away, you can see around 2.5 units in height? I am not super confident in this but I think that’s roughly correct.
This is why from Skeletal mesh I get the box extent and obtain the Z axis (height of the mesh) and then I multiply it by 3 to set the spring arm length.
This gives me a nice field of view and the item has already been generally centralised.
Just note that after implementing the blueprints and compiling, you may not see the viewport as expected as the data is dependent on dynamic input (so testing can be more tricky). If you see something of the following, it’s expected:
Therefore you may want to disconnect the beginning parts of constructor (such as setting skeletal mesh dynamically) while working on the other pieces.
Mesh render target
There’s not much to say about this class – its basically one created in the tutorial video mentioned at start
The main thing to mention is that you have to link it to the Texture Target
from the Scene capture component
.
The result of it may look something like this:
Render target material
Again this is very similar to part from tutorial in video above but there is one small addition that you must make.
First of all this material should look something like this:
You need to have the texture sample inserted from the texture sample in previous step.
What you will also need to do is convert the texture sample
component to a parameter. This is because we will be creating material instances from this class. You can promote it to parameter by right clicking it and selecting Convert to parameter
.
Name this parameter as ItemTexture
or whatever you like.
Widget for the item
This is again from the tutorial but with some blueprint additions.
Generally you will have a Widget
class with an Image
component.
Note that the image can be set straight to the material that we’ve generated.
This could be enough if you needed to only ever display one image at a time, but here we’re looking at spawning multiple icons dynamically, hence the new additions in the blueprints.
In this class we will look at spawning of the 3D Mesh Capture
component dynamically.
Create a new custom event inside the Event graph
and create a new custom event, I called it Update mesh
.
When this function is called, we will spawn a new actor of the 3D mesh capture component class:
I get the player character and set the owner to the character – this is for future features of perhaps rotating the object etc. If you don’t need such features, you may leave the first block out.
Then I spawn the dynamic skeletal mesh
that we’re interested in. Note the skeletal mesh is public variable. Therefore I can set it from step above which I will again show – but this is the input of creating our dynamic icon.
Next, I put together some ‘random’ transform for the position of this skeletal mesh. This doesn’t matter too much as we make the actor invisible to other cameras, other than the 2D capture component. But you should keep note of this transform as its used in the image inside 3D Mesh capture component
– check for text widget transform
on this page to find it. Note that transform of 0,0,0
did not work for some reason, not entirely sure why, so there may be some edge cases – its best for the point to not intersect with any other object where possible.
Next you do some interesting things.
Next, the 2D canvas that you had before we will dynamically create – so you’re technically not using it – but it was important for your testing so please don’t skip it! I’ve set the width/height to 1024, but it will depend on your requirements. Make this value smaller if you don’t need high def! As it will have performance impact if you spawn a bunch of them.
Next bit I personally found interesting.
We’re creating dynamic material instance
object, which is really cool that UE allows this!
Note that the material you’ve created before is used here as the parent.
That’s why it was important to parameterize the texture property.
Here we are updating the Item texture
parameter with the canvas target that we’ve dynamically allocated.
Then we simply update the image inside the widget with the material instance object and we’re basically done.
Using the dynamic 2D logo
Part of my inventory components, I have a entity for a inventory slot
which has all properties for an item its storing, including the reference for skeletal mesh object
.
The ItemRotatingWidget
is the same widget that we looked at in the step above – I am also planning on making it rotatable in future!
For this moment, the setting of skeletal mesh
was still disconnected for ‘testing/visualization’ purposes.
But in order to use the dynamic widget all you need to do is set the skeletal mesh to whatever mesh you like, then simply call the Update mesh
custom event that we generated.
After this is done you can connect the setting of skeletal mesh dynamically and testing it for real.
Results
Here are just a couple items that I’ve dynamically set in my inventory and so far I think it’s looking great!
Here I am dynamically creating the 2D assets for each of my skeletal meshes. The cool thing is that the meshes are all of varying sizes but can still see them ok in the images.
Lighting
Feel free to add other things to your components, for example I thought the images looked dark so I can now add lighting to them. The beauty is that if I want to make a global change, ALL my icons are modified, making this scalable.
Disable the Cast shadows
function as otherwise it can slow down performance. Tweak the light intensity as you like and check the results again!
Now ALL the icons have the improved lighting effects. So play around with settings as you like to get the results you’re after.