This is the 3rd post for the following steps:
- Overview for character creation
- Dealing with complex nested options
- Applying the options to skeletal mesh (using n-hance assets) – This post
- Connect character creation to custom server
- Populate character selection screen from server
The objective of this post is to apply the settings from the right menu to the skeletal mesh on the left
I’ve integrated with several asset packs from N-Hance Studio (human male/female etc, I am not affiliated with them, but simply like their content.
Note that you the steps that we cover will be relatively universal. I.e. we’re taking a generic approach to the problem, so solution should work for this asset pack and many others.
Ok let’s divide this post into few steps that we need to achieve:
- Create the skeletal mesh on screen for us to use/modify
- Create the data transfer objects (DTOs) between the widget and the skeletal mesh to apply styles
- Create resolvers for the skeletal meshes and materials
- Create the custom events to apply changes
Create the skeletal mesh for character create
So first of all, let’s find the base asset you want to use for your skeletal mesh.
I think one of the peasant
ones is a good start for me from the assets I’ve purchased, here it is for reference:
Make a copy of this asset (in a folder of your choice) and call it something like BP_Create_Character
– or anything else that makes sense to you.
It will look something like this by default:
Essentially for most generic stylized character blueprints you will find that the options are essentially different components inside the components window. If you have this, its a good sign.
Now this blueprint has a parent class of Character
as seen in top right. You will want to change this to skeletal mesh actor
, by clicking File -> Reparent blueprint
and selecting skeletal mesh actor.
You want to reparent because the character
class will try move the mesh on input, consume controls and other similar behavior. For instance, it will block you from rotating the object if you wish to have that implemented.
Once done, confirm that this has worked.
Next, all pieces in the event graph related to controls can be deleted.
Note that you may need to add a blueprint to Set Master Pose Component
. This was in previous version of this blueprint but for some reason was removed in the updated version.
If you’re missing it, do add it.
This basically synchronizes the pose of all nested components to the root one. So set all nested components to target
and set the root component as the master pose component.
Ok now you’re ready to spawn it inside the Create Character Blueprint
.
Find the constructor in CreateCharacterWidget, and create a new function to spawn the character.
The full constructor for reference will look like this, and you will cover the rest of the functions soon.
Remember to call update character appearance at the end to refresh the expected appearance.
Inside the spawn character function we have:
About getting the location for where to spawn, just drop something in the map and check the transform of it and use that as starting reference, then just play around with it until you’re happy.
You want to enable input incase you want to be able to rotate the character, which was covered here.
Understanding the stylized modular character mesh
Before we jump on building the resolver, let’s quickly summarize what we need to control in the character blueprint.
If you click on the skeletal mesh components inside the blueprint, you will load individual settings for them.
The key ones are:
- anim class (not too relevant in this post, but will be important for you to recognize it in general)
- skeletal mesh
- material
So, the key is that each component has a mesh and appearance in separation. This implies that you will need to load them through 2 separate calls. It also means that items can share meshes and have alternating materials, giving you further flexibility in future if you require it.
Click on the magnifying glass on the skeletal mesh to find the blueprint and open it.
Inside here, you will find the relevant materials that the skeletal mesh requires. This is very important as different assets will have different names for the slots.
This is particularly important because some meshes will have more than 1 material – so perhaps you could use apply material by index (0), but as soon as you have >1 material assigned, your logic will break.
So make sure you find the relevant names and always apply materials by name.
Ok, now let’s explore the material instance.
This can be even more complicated to look at, but we can try simplify it and just implement the basics and iterate over it.
I would suggest opening 2 materials side by side and comparing what’s changed. For example, the material above is from human body when not equipping any items.
Below is when equipping brown cloth items.
So we can see that Body_D
is consistent – i.e. this is effectively the natural skin color for the skeletal mesh then.
The other pieces, such as Chest, Gloves, Pants are materials for individual items that the character has equipped.
This means that when ‘drawing’ the character mesh, we always need to:
- fetch correct individual skeletal meshes
- compose a correct material instance, overriding relevant texture maps based on items
- applying correct material to skeletal meshes using slot names
Building mesh and material resolver
Ok now we will start building the skeletal mesh and material resolvers.
To help with it, I created 2 models: CharacterAppearance
struct and AppearanceKey
struct.
The CharacterAppearance
struct simply tries to encapsulate ALL options that we can define in the character selection process. This is directly linked to the options we created in part 2.
The appearance key is a simply composite key that we’ll use in Maps to fetch the data we desire.
Remember that when looking at material, we had material for skin color and we also needed to evaluate material for cloth.
This means we need at least 2 parameters to determine the material, the base skin option and the item that we have equipped. Hence BaseKey
and ItemId
. This could potentially be expanded in future.
I now created a new blueprint function library in the Characters/Appearance
folder which we will use in character creation AND to resolve character appearance for in-game characters. The blueprint is called AppearanceResolver
.
The content of this class is as follows:
So you can see in this example, I have ResolveHairMesh
which has an input of the CharacterAppearance
struct. We could’ve had the key
directly, but to keep the input/output of these functions closer together I made it like this.
The output for a mesh resolver is a Skeletal Mesh
. Note we also build the Material
resolvers in some of the functions, which we will cover shortly.
You can see for the time being, I am not evaluating by ItemId
. This is because in character creation screen I don’t yet need them, but when I will integrate it with my inventory system, I will expand the use here.
So the main objective is to create a local variable, containing all the data that you’ll require.
So these variables will contain all the available options, including different races, genders, etc.
Let’s have a look at few other functions.
Here I simply used the gender to evaluate the skeletal mesh. This is one of the reasons I passed in the Character Appearance
struct instead of the Key
. This will allow me to change this in future fast and easy.
So I’d suggest you to simplify it to your requirements to potentially avoid duplicate entries. i.e. for my races (human and undying) actually share same skeletal mesh, but have different material options.
Let’s have a look now at the material evaluators, we can start with more odd one:
You can see here that the resolve hair color actually returns two materials.
This is because some styles require one type of hair material, and other styles require another. This is potentially an odd limitation of the asset, but let me quickly demonstrate.
So for me it was simply easier to locate both at all times and apply based on slot name, which only will apply relevant material. This will be covered below, when we’re applying skeletal meshes and materials to our character.
But I want to highlight that you can modify these functions to your requirements, stay flexible!
The hair materials variable contains the following
And again we can see the base key is directly connected to the hair options that we setup in the options before.
Let’s look at a more simple material resolver – face material resolver.
And again a more complicated piece – body material evaluator.
The reason its more complicated is because we use the one material instance to apply to multiple different skeletal meshes. However that one material instance contains multiple texture sets.
For the character creation screen, I only want to modify the body skin tone. Therefore I pass in the character appearance
structure AND the material instance
that’s currently set. Then I evaluate what the skin texture should be, based on selected options and override that texture in the material instance, before passing it back.
Applying the options on the character
Now go back to the BP_Create_Character
and I would suggest creating a new graph for this work, I called mine AppearanceModifierGraph
. It will be responsible for updating all appearance options.
Ok in this graph, we will need to create a new custom event to Resolve All Appearance
.
These custom event calls will not exist yet, but that’s what we’re going to be building now. Each piece of the mesh will need a custom resolver.
We’ll begin with Character Resolve Hair
. This is perhaps one of the more complex ones.
There’s 4 things we’re doing
- getting hair skeletal mesh, apply it
- get hair color, we obtain 2 materials, apply them both
- Get
brow
mesh, which includesbeard
, apply it - Resolve
brow/beard
color (based on hair color above)
They are numbered 1-4 above respectively.
The reason why its a bit more complex is because we fetch 2 different materials and apply 2 of them to the different slots. In this case we’re actually only using 1 of them, but it is possible that you’d need two, so its good to see it in practice anyway.
Furthermore, I’d like to maintain the beard/brow color to be the same as the hair color, hence its integrated here. In practice, you could have a separate call for that too.
Let’s look at the next example, resolving facial features – a bear in our case.
We can see this is more straight forward. We fetch one skeletal mesh, then we fetch the desired material for it and apply.
Then we have resolve face:
And the rest of the resolvers will now follow the same pattern:
So basically for each modular piece:
- get the skeletal mesh
- set the skeletal mesh to correct component
- get the material
- apply material to the component (by slot name)
In our case, the body material is consistent, because the appearance struct
holds all the necessary values. But you can be obtaining it individually as with skeletal mesh if your requirements are different, using the same technique.
The hard work is now complete and we just need to reference this back into the character creation widget.
Prepare Dynamic Material Instance
You may find the Material Instance Dynamic variable used in certain places, its prepared as part of constructor like so:
This simply creates a dynamic material instance that we can use on the go, and populates the default values within.
For me, I am able to find some default values by checking an example:
This essentially tells me which values I need to set.
So, some functions are simply overriding the materials on this one, such as chest resolver.
Character creation widget addition
So going back to the Create Character Blueprint
(where you spawned the character blueprint from).
Here you want to populate your Character appearance struct
, this was briefly introduced in Building mesh and material resolver
section.
The struct contains all the properties from the selection widget. So anything that could potentially impact the characters appearance.
Then in the blueprint populate all fields from the options you have currently selected.
Notice that at the end, we call the function from the character blueprint to resolve all appearance, which references all the functions that you’ve built in the previous steps.
Note that its very likely I will be adding the item object(s) to the Appearance struct as well, to reference them in the resolvers. I have not determined the best way to do that yet (currently I think Map<String, Item>
will probably be ideal, as I can specify which component the item will be adjusting. But this is not essential for the character creation part, but will be important quite soon, when integrating with the inventory.
In the next post I will look to integrate this work with the backend custom server and perhaps make a very basic character selection screen.
Pingback: 21. Unreal Engine – character creation part 2 – complex nested options – The web tech journal
Pingback: 23. Unreal Engine – character creation part 4 – connect to custom server – The web tech journal
Pingback: 24. Unreal Engine – character creation part 5 – select character with server – The web tech journal
Pingback: 20. Unreal engine – mmo style character creation with n-hance assets – The web tech journal
Pingback: 24. Unreal Engine – logging into a custom server – The web tech journal
Pingback: 28. Unreal Engine – Synchronize nearby player appearance – The web tech journal
Pingback: Unreal Engine – Create character and Login with OWS – Unreal game dev with Yaz
Pingback: 35. Unreal + PlayFab: create/get character – Unreal game dev with Yaz