We want to have exchangeable equipment on our character
The goal is to give our players various items to choose from. For this example, our players will choose a weapon, armor for protection, and boots. We want to visualize these choices on the character.
The imagined system should enable quick equipment swaps. All items get rendered on a player avatar.
All items are mesh models #
Weapons are simple meshes. Armor and boots will use skinned meshes. We will use the same skeleton for all players, so we don’t have to rescale the meshes. After we create all these meshes, we can attach them to our existing torso. The weapon meshes will get attached to the left or right hand. Armor and boot skinned-meshes will share the armature with the base avatar.
That is tricky to achieve in Unity. There exist a lot of helper scripts for this problem. They enable you to reassign the bones of a SkinnedMeshRenderer. I attached my personal BoneSetter.cs
at the end of this tutorial.
After attaching all meshes and trying some animations we might discover this weird behavior:
That happens because the torso has a different mesh deformation than the armor.
We have to mask out parts of the torso that are invisible
We don’t want to render these glitchy parts anyway. We only want to render things that actually should be visible. To achieve this, we can mask parts of the torso, hidden by armor or boots. Every boot and every armor piece has its own “masking” texture. This texture uses the UV map of the torso and has an alpha value of “0” at the masked-out regions.
To get the result texture, we multiply the alpha values. The result will have an alpha value of zero, where either the boots or the armor masks out a region of the torso. We can now assign this texture to the torso, and the glitchy parts will mask out.
We added a shader for more performant masking
At first, I created the masking texture using Texture2D
and iterating over each pixel on the CPU. That is a compute-heavy task and results in a noticeable lag whenever a character spawns.
But we can put this computation off to the GPU. For this to work, we have to write a simple surface shader. We give this shader a color and a main texture. Additionally, the surface shader will have two Texture2D inputs. These are for the armor and boot masking textures. Furthermore, we need a _Cutoff
parameter for the alpha values.
That is the shader I ended up with:
void surf (Input IN, inout SurfaceOutputStandardSpecular o) {
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) *_Color;
// Set the albedo from main texture and defined color
o.Albedo = c.rgb;
// Calculate the alpha value by multiplicating the two textures
o.Alpha = tex2D(_BootMask,IN.uv_BootMask).a*tex2D(_ArmorMask,IN.uv_ArmorMask).a;
}
You have to experiment to find the queue and alpha blending settings that work best for you. You can have a look at the unity documentation for shader alpha blending. I attached the complete shader code at the end of the tutorial.
That fixes the glitchy parts of the torso.
If I hide the armor and boots, you can see that only the relevant parts render:
Wrapping up
Before implementing this system for Raiding.Zone, I did some research on how other games are implementing equipment. I found an interesting Reddit thread. My solution is an adaption to the ideas I read there. Each equipment piece has a torso mask that masks out parts of the torso. Every time the player swaps their equipment, the torso masks get updated in the torso material. The shader will combine them at runtime to show only the relevant parts.
I use the same system to render the equipment preview on a canvas through a render texture. I had to use a different shader because it would not work otherwise. I also attached it below.
The mentioned code pieces are available in this Gist: https://gist.github.com/klg71/552dfff2a22a8540eef6b4148d8e0f8e.