Making a Multiplayer WEB RPG - Part 8: Instancing & VAT Animation
Tags: gamedev, babylonjs, colyseus
Published: 2024-04-16 03:59:59

Demo: https://t5c.onrender.com
Github: https://github.com/oriongunning/t5c

---

Hi All,

It's been a long time since last update and as some of you may know, to improve performance, I've been trying to implement instances & baked animations.

### What is Baked Texture Animations?
Usually, animations are computed by the CPU, applying the bone effects to the mesh. This is reasonably slow and for several animated objects can be a bottleneck. One way to optimize this is pre-computing (or baking) the animations, storing them into a texture (usually called Vertex Animation Textures, or VAT) and using it on the vertex shaders. This frees the CPU, with the trade-off that you need to perform this initial baking step (which can be done at development time), add a new texture file to your downloads and consume more GPU memory. This trade-off is usually quite good, since the CPU tends to be the bottleneck.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lf3v9qzauteymx7qjnel.png)
_This is what a VAT texture looks like_

### Attaching Items to Instances

Since I've transitioned to using instances for my models, attaching items to a bone, as I've been doing until now, is no longer feasible (since instances share the same mesh/animation). I've identified several methods I could use:

- Attaching to a bone via Blender (the easiest but less flexible approach).
- Continuing to attach to a bone, but this would require having a cloned skeleton for each different animation * each model.
- Bone weighting via code (this would require having a clone of each item * each model).

Initially, I went for the third option due to its potential for greater flexibility. However, in hindsight, the simplest solution may have been more appropriate.

### Initial Implementation

After seeking advice on the helpful Babylon.js forum, I successfully implemented the solution. I could now have over 200 different models, with multiple equipment pieces dynamically attached to models via bone weighting at runtime, all while maintaining a smooth 60 frames per second. 

Victory! Unfortunately not.

Upon further observation, I noticed some peculiar animation artifacts (only on the items) as soon as I introduced more than one different model.

For a clearer understanding of the issue, please refer to this video (NO AUDIO): {% embed https://www.youtube.com/watch?v=Nkfi4uxvSa0 %}

### Resolving the BUG

After struggling for months and nearly abandoning the project, I finally managed to resolve the issue. Surprisingly, it only required changing 2 "silly" lines of code to finally fix it.

```
// https://github.com/orion3dgames/t5c/blob/feature/vat-skin/src/client/Controllers/VatController.ts

// line 172
// previous was: let rawMesh = this._game._loadedAssets["ITEM_" + item.key].meshes[0];
// note: this._game._loadedAssets[key] is an array of ContainerAssetTask
let rawMesh = this._game._loadedAssets["ITEM_" + item.key].meshes[0].clone();

// line 234
// commenting the line below was necessary too
// itemMesh.setEnabled(false);

```

As mentioned earlier, each model should have had its own set of cloned items, but for some reason, they all appeared to be attached to the wrong model. 

Nevertheless, I'm still not entirely sure why these 2 lines fix this issue, and I'll need to investigate further in due course.

### The result

I've now refactored and merged everything back to the master branch and updated the demo. See results below:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/da9u9nqltdl99xyl6ogc.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jk5g9llfu6kzzi9klls6.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ocs488qdchrqcm1wefpl.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dw0y6k2n9144c8xoxnzh.png)

Cheers,
Orion