DevLog #8 - Manual optimization of VRoidStudio VRM Avatars for WebXR VR using Blender

Welcome to VR Me Up developer log number 8. This is following on from where I left off last developer log 7. I was showing you how I went about optimizing VRoid Studio VRM models so they ran a little faster in VR in a browser by just setting some export options. We managed to almost half the file size and load times and significantly save on the amount of memory the models were taking up. In this article I am using Blender to manually optimize the model.

Make sure that you have the Blender VRM add-on installed and enabled Edit | Preferences | Add-ons | "Import-Export : VRM format".

Overview

Start by importing the VRM into Blender. It may take a minute of so, as the VRM files can be large. Once it’s imported it should appear in the viewport with both the model mesh and the armature rig visible. I’m assuming you know how to use Blender, so I’m not going to go into the details of everything I’m doing, but I will try to explain each step.

This article is going to be broken into three steps.

  1. Reduce the texture memory usage by reducing the texture images sizes.

  2. Reduce the mesh memory usage by removing, decimating or optimizing the mesh.

  3. Reduce the CPU processing required to display the model by removing some of the animation bones.

It is important to note that step 3 does remove some functionality from the model that you may want to keep. This step can be skipped if the hair or clothes physics animations are required.

I use the Play Canvas GLTF viewer to gather valuable model statistics information like load times, memory usage, etc. Another useful tool is on the three-vrm GitHub page. This Animation Example is great for testing VRM models along with animations.

Step 1 - Resize Textures

Blender texture images
Blender texture images

Open the image viewer pane for the model in Blender. The number of images may vary depending on the VRoid Studio options used when exporting the model.

Resize each of the images to a point where you think they look adequate for your usage. The original sizes will be very large (2048 or 4096) so as you resize the images watch the effect on the model to make sure that you’re happy with the results. If not just hit control-Z to undo the change and try a different resolution.

It is important to keep the textures sizes to a power of two like 2, 4, 8, 16, 32, 64, 128, 256, 512 or 1024.

  1. You can sometimes get away with reducing the textures significantly especially if the actual texture does not appear very large on the model. You can reduce the resolution of the face, for example, as there is not a lot of detail in it, and it does not affect the look of the model very much.

  2. The textures that are going to have the most visual impact are those associated with clothing. Try not to reduce these as much.

Blocky texture example
Blocky texture example

In some cases, the textures might be blank or appear very blocky, in which case it’s okay to make those textures very small (8x8 or even smaller).

  1. Don’t forget to resize the thumbnail image. It’s actually quite large and takes up a lot of file space and you don’t really need it.

When you finish this step, save and review all the changes. Export the model as a VRM file and have a look at the changes in the Play Canvas Viewer . It’s always good to see what the actual results look like in a web Browser.

To view at the model in play canvas viewer, change the file extension from “VRM” to “GLB” (GLTF binary formatted)

Texture optimization statistics
Texture optimization statistics

In my tests, the file size was reduced by half to about 4.7 MB, but we had a significant reduction in the texture VRAM from 7.9 megabytes down to 5.5MB, with a small reduction on load times. Also use the three-vrm animation example to make sure that it looks and moves as you would expect.

You can drag and drop the VRM model and FBX animation into the three-vrm animation example browser window to test it. You can download excellent FBX animations from a site like Mixamo.

Step 2 - Optimizing the Mesh

Optimizing the mesh is a complex process, but it can be broken down into a few simple steps, removing some unnecessary polygons, fixing up any model errors (like the parts that should not be showing) and reducing the number of triangles in the meshes. The aim of this step is to reduce the polygon count so that the model will load and render faster.

Enable blender mesh statistics
Enable blender mesh statistics

Turn on the blender statistics so you can keep track of the number of faces and triangles in your model as you optimize it.

Generally, the mesh will appear in two parts, the body and the head.

Optimizing the head mesh

The head is a good place to start as there are lot of really simple changes that will reduce the polygon count. The face mesh for the avatars is very dense so using a decimate modifier to reduce the number of polygons can have a significant impact.

If you’re not using mouth animations (or emotes), remove the mouth components like the teeth, toung, etc. Go to the back of the head and select the mouth parts using the “L” (loop select) and “X” (delete) to remove the unwanted meshes.

Decimating Edit Mode| Mesh | Cleanup | Decimate Geometry the mesh will also help remove some of the unwanted polygons. However, be careful with this value as it can have a huge impact on the look of the model. It can turn from something that looks good into a few boxy polygons with only a few decimals different. I found a value of around 2.0 works well as it keeps the profile of the nose and eyes.

Run the “clean up” and “Merge by distance” operations. This will merge together any duplicate vertices and free up a little bit of mesh vertex space.

Optimizing the body

You can spend a lot of time and effort optimizing the body mesh, as the mesh is very complex, and you have to consider how any changes to make to it will affect its animation like running, walking, etc. These are the areas I usually focus on.

  1. If you hide the head mesh object “H” and only show the body mesh, you’ll see that the back of the head is still present. This can be removed.

  2. Some of the polygons may appear to be poking through the other polygons. This is especially noticeable at the feet and clothing. The model is actually made up of different layers, for example the legs (skin) and then the pants on top of the legs, or the feet and the shoes on top of them. Remove those underlying layers.

  3. Remove the toenails from the feet and fingernails from the hands, as they are small meshes and they take up valuable space. A tip to make sure you’ve got them selected, is to select the arm or the feet meshes and instead of removing them just hide them with ‘H’. This will reveal any fingernails or toenails and you can just select them and delete.

  4. If lower layers of clothing are showing through upper layers, then you may have to remove the connected triangles. In other cases, you may have to do a little “editing” to move the mesh around or just remove the unwanted triangles altogether.

  5. Running Decimate will reduce the model polygons a little bit more, just remember to deselect the hands. I don’t decimate the hands because you are looking at the hands a lot when the model is in VR. You want a decent amount of detail to make them look good and deform well, especially the fingers.

  6. One last thing I like to do is remove hidden polygons from the model. Turn off x-ray mode and then use box select ‘B’ to select all the visible polygons. Just scroll around the model and try to find all the visible surfaces by box selecting them. Once you have selected all these visible meshes, you then can invert Select | Invert the selection and remove, essentially, the hidden polygons. This can remove polygons that may be under other polygons that you will never see.

  7. Finally, run the “Clean Up” and “Merge by distance” operations. This will merge together duplicate vertices and once again free up a little bit of space.

Mesh optimization statistics
Mesh optimization statistics

It’s time to export and have a look at it again. In my tests these changes resulted in lower polygon counts, load times and file size. Don’t forget to test the Avatar with the three-vrm animation example and with some animations to make sure that you’re still happy with the results.

Step 3 - Removing unused animation bones (optional)

Warning : Removing bones from the Avatar will affect the animation quality of the clothes and of the hair, so you may choose to skip this step.

Remove all the unnecessary bones from the model. This will reduce the amount of CPU and GPU processing requirements to animate the Avatar and hopefully speed it up a little. For example, if your character does not have a skirt or the hair isn’t long, it doesn’t need all those bones.

  1. Removing the bones for the skirt and the hair. Make sure you don’t remove any of the body or head bones as they’re required for running, walking and dancing, etc.

  2. Once you’ve removed the bones you also need to remove all the colliders. They are not longer required, as there’s nothing really to collide.

Blender VRM spring bones menu
Blender VRM spring bones menu

Finally you have to remove the links between the bones and the colliders. This is done by selecting the armature, then going into Object Properties | VRMsection settings and then down into “spring bone” section. Just remove all the “Spring Bone Colliders”, “Spring Bone Collider Groups” and all the “Spring Bone Springs”.

Test the results of your changes using the three-vrm animation example or your own application.

Orphan Mesh Vertexes

I’ve intentionally left a problem in my example avatar in the YouTube video so that I can show you how to fix it if you see it.

Blender vertex weights
Blender vertex weights

If you see the hair of the character lagging behind, then this is because the bones that control that part of the hair have been removed in step 3. This can also happen with clothing.

A simple way to fix this for the hair is to just go back into the model and select all the hair. Then go to the “object data properties” and scroll up in the “vertex groups” list until you find the “J_Bip_C_Head” vertex group. Make sure you have all the hair polygons selected, set the weight to 1 and then press assign. This will assign all the hair to the Head vertex group, so all the hair will move with the head.

Now when you apply a “run” or “walk” animation, you should see everything moving as one. In the case of clothing, you may need to do some more complex vertex weight painting to get the results you want.

Removing the bones will have a small impact on the load times and file size of the model, however, on low end VR devices or a web browsers, these changes can improve performance especially when you have multiple avatars on the screen at the same time.

Final optimization statistics
Final optimization statistics
  Default Quality VRoid Studio Optimized Texture Optimized Mesh Optimized Bone Optimized Percent
File Size (KB) 17.7 7.9 4.7 1.2 1.2 6.8%
Load Time (ms) 504 229 182 136 123 24.4%
Texture VRAM (MB) 199.0 110.0 5.5 5.5 5.5 2.8%
Mesh VRAM (KB) 10,600 557 557 168 168 1.6%
Primitive (Triangles x 1000) 160 42 42 12 12 7.6%

I hope you found this article useful. I know it’s been a bit longer than usual, but there’s been a lot to cover. Remember to always check the resulting Avatar to make sure you’re happy with it. Ultimately, it’s whatever you are happy with.

See you in the Metaverse!

VR Me Up!

Let's Get In Touch!


Join us on the journey creating an Open Metaverse