VRChatのアバターを軽量化したい方へ。


## はじめに

パブリックインスタンスに行くこと、楽しいですよね。

知らない人と話したり、フレンドになったり。

私も暇だったら結構パブリックに行ったりしています。

しかし、やっぱり...

**みんな、アバターが重い！重すぎる！**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/d2ed2cd5-5a0d-40ef-a9a2-80098fc34fbc.png)

そこまで低スペックでもないのに、FUJIYAMAとか行くとFPSが20になったり...

なぜみんな重いのかと考えると、やはり情報が不足しているような気がしてきたので、この記事を書きました。

それでは、軽量化してみましょう。

## まずはインポートから

### VCCからインポートできるやつ

| ツール名                            | 作者 |
|-------------------------------------|------|
| AAO: Avatar Optimizer               | anatawa12    |
| lillNDMFMeshSimplifier (NDMF)       | lilxyzw    |

### ダウンロードして入れるやつ (VCCからもインポート可能)

| ツール名                         | 作者           | ダウンロードリンク                                                                 |
|----------------------------------|----------------|------------------------------------------------------------------------------------|
| VRC Avatar Performance Tools     | Thryrallo      | [GitHub リンク](https://github.com/Thryrallo/VRC-Avatar-Performance-Tools/releases/latest) |
| TexTransTool                     | Reina_Sakiria  | [Booth リンク](https://booth.pm/ja/items/4833984)                                 |
| ActualPerformanceWindow          | anatawa12      | [Gist リンク](https://gist.github.com/anatawa12/a4bb4e2e5d75b4fa5ba42e236aae564d) |


各ツールを使う目的は以下のような感じです。

| ツール名                     | 目的                                |
|----------------------------|-----------------------------------------|
| AAO: Avatar Optimizer |  Mesh結合やPhysBoneの最適化  |
| lillNDMFMeshSimplifier (NDMF) | Polygonの軽量化 |
| VRC Avatar Performance Tools | Texture Memoryの軽減 |
| TexTransTool | Textureの結合 |
| ActualPerformanceWindow | [AvatarPerformence Rank](https://creators.vrchat.com/avatars/avatar-performance-ranking-system/)の確認のため |



インポートし終わったら準備完了です！

## 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/41a51453-8b5d-4bec-be48-76e6b5786bae.png)


今回の軽量化は、しなのちゃんが手伝ってくれました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/0f5a2b07-d42a-4914-8811-359c67144796.png)

何も施していないしなのちゃんの**Performence Rank**はこのような感じです。

Polygonsは14万、Texture Memoryが63MBといった具合ですね。軽くも、重くもないです。

このしなのちゃんを**Medium**にしていきたいと思います！

まずは軽量化の順番について。正直順番は関係ないので、好きな順番で行っても大丈夫です。

1. VRC Avatar Performance ToolsでTexture Memoryを減らす

2. TexTransToolでMaterialを結合させる

3. NDMFでPolygonの軽量化をする

4. AAOでMeshの結合、PhysBoneの軽量化などをしていく

という感じです。

それでは、このしなのちゃんを軽量化していきましょう！


## 1. VRC Avatar Performance ToolsでTexture Memoryを減らす

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/52b548ef-8e0d-4c6d-aee3-51675db691d1.png)

Texture Memoryはこのアバターが使うと予想されるRAM/VRAMのサイズです。

最近、アバターのダウンロードサイズを100MB以下にすればいいという話が出回っていますが、これは事実ではありません。容量だけの話であれば、

**実際のパフォーマンスに影響するのはダウンロードサイズではなく、このTexture Memoryが大きく影響を与えます**。

減らしましょう。[AvatarPerformence Rank](https://creators.vrchat.com/avatars/avatar-performance-ranking-system/)では、Texture Memoryが150MB以下であればPoor判定になりますが、私は75MB以下になるようにするのが理想的だと思っています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/70893786-0b54-4458-b2c1-a8a2ebe687e5.png)

VRC Avatar Performance Toolsの画面です。

ここで、Texture Memoryの軽減ができます。
まず、以下の内容を覚えておいてください。

- 4096(4k)の画質を使うのは避けましょう。
- CrunchedはTexture Memoryが減っているように見えても、実際にプレイする時はメモリ上で展開されるので、意味がありません。

画質は1024か2048になるようにしていきましょう。

MatcapやMaskなどは512か256にしてもそれほど目立ちません。

可逆的な作業なので、色々な画質を試しながら減らしていきましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/e5d16842-e32c-443f-a314-216a5ad603ce.png)

Texture Memoryの軽減が終わった後のしなのちゃんです。

**63.60MB**から**9.10MB**、かなり軽くなりました。

次に進みましょう。

## 2. TexTransToolでMaterialを結合させる。

TexTransToolは、Materialの結合以外にも様々な機能を提供しています。ただ今回は、Materialを結合する機能だけに集中します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/c68385b8-d1b4-4147-a943-a61b8d1be792.png)

まず、`Hierarchy`から`Empty Object`を一つ生成します。名前は自由に設定してください。（ただし、この作業はEmpty Objectでなくても問題ありません。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/1e581ba2-098c-460b-8365-25057fc3629c.png)

その後、`Inspector`の`Add Component`から`TTT AtltasTexture`を追加してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/c5933d84-7be5-4663-a220-c3cc23c15534.png)

Inspectorでは上記のような画面になります。

- 結合対象のMaterial : チェックを入れたMaterialが結合されます。
- 基準Material : 基準となるMaterialです。結合後のShaderの設定(影、Rimlight、Outlineなど)は、このマテリアルを基準として設定されます。必ずプレビューで確認しながら作業してください。
- 結合テクスチャの画質 : 結合されたMaterialのテクスチャの画質です。

ここで、結合させたいMaterialを選択し、結合することができます。
結合においては、いくつか注意すべきポイントがあります。必ずお読みください。

**注意！**

- AlphaTransparencyが消失します。半透明の設定がある場合、結合対象から除外してください。
- 同様の理由で、顔の表情などのテクスチャの結合は避けてください。
- 服と体の影の設定が異なる場合があります。注意してください。
- 結合たいしょうが違うShaderである場合、`結合対象のMaterial`のShaderに上書きされます。注意してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/476e03c1-891d-4cea-b7e4-ed2f22821d34.png)

今回は、服/髪と顔/体を分けて設定しました。
これで、Material(Texture)の結合が終わりました。


## 3. NDMFでPolygonの軽量化をする。

Polygonの軽量化にはVCCからインポートできる**NDMF**を使います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/090c4184-b8fa-4925-8df3-4d31c94ff594.png)

軽量化させたいObjectを選択し、`Add Component`から`NDMF Mesh Simplifier`を追加してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/6813b582-4626-4c36-85c8-9f5e72ac4b01.png)

その後の使い方は非常に簡単で、`quality`の数値を変更することで軽減ができます。`Scene`にリアルタイム反映されるので、確認しながら数値を変更してください。

ただし、**NDMFもTTTと同様に、顔に使用するのは避けてください**。表情のComponentsである、シイタケなどは非常に単純なPolygonとなっていますので、軽量化させると壊れてしまいます。

---

**3**までの作業を終えた後のしなのちゃんです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/815cafbd-880e-430a-88d9-6e5f7927f2d2.png)

Polygonsが**140034**から**66579**になりました。かなり軽くなりましたね。

[AvatarPerformence Rank](https://creators.vrchat.com/avatars/avatar-performance-ranking-system/)では、Polygonsが**70000**以下であれば**Good**判定をもらえます(32000以下であれば Very Good)。70000以上からはVery Poorになりますので、参考にしてください。


## 4. AAOでMeshの結合、PhysBoneの軽量化などをしていく。

いよいよAAOの出番です。馴染みのある方も多いでしょう。

まずはMeshの結合から始めましょう。

### 4.1 AAO Mergy SkinnedMesh

**AAO Mergy SkinnedMesh**では、`Skinned Mesh Renderer`と`Mesh Filter`の結合ができます。

まず、`Hierarchy`から`Empty Obeject`を生成し、好きな名前にしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/62165f61-5899-495e-8733-9a7bebcec003.png)

その後、`Add Component`から`AAO Mergy SkinnedMesh`を追加してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/a6c4974e-51bb-4c36-a4a7-958068396c26.png)

すると、以下のような画面が追加されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/abb33984-8a39-497b-9c23-aa6391077839.png)

`スキンメッシュレンダラー`に`Skinned Mesh Render`を、静的レンダラーには`Mesh Filter`を入れてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/bf565623-2d4d-4f7e-8d3a-1140fe8ce520.png)

今回はMesh Filterが対象のObjectではないので、Skinned Mesh Renderのみとなります。

ただ、結合において、いくつか注意すべきポイントがあります。必ずお読みください。

- ON/OFFしたいObjectやギミックは結合から除外してください。Meshが一つになってしまうので、ON/OFF機能が正常に作動しない場合があります。(今回はAFKの時に出てくるソファは除外しました。)
- `BlendShapes`が壊れたり、正常に作動しない場合があります。固定させたい`BlendShapes`がある場合、AAO FreezeShapesで固定しておいてください。

また、`AAO Remove Mesh by Box`という機能があります。

![スクリーンショット 2025-05-21 175559.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/96648ae4-95fd-49b1-9ea7-624cd40b7f82.png)

この機能は赤いBoxを設定して、そのBox内にあるMeshを削除してくれます。
目に見えない部分を消しておきたい方はぜひ試してみてください。

---

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/cdf9f02c-95b1-4dfb-8a05-ecbc32ef69e2.png)


**4.1**まで終えた後のしなのちゃんです。Physbone以外は全てGoodになりました。

`Skinned Meshes`も一つになり、`Excellent`になっています。

Polygonsは`AAO Remove Mesh By Box`の導入により、さらに軽減されました。

---

### 4.2 AAOによるPhysbone軽量化

**4.2**では、経験的にBoneやPhysboneを削減していく必要があります。目立たないBone、使用しないBoneなどを思い切って削除する必要があります。

しなのちゃんの場合は、お尻(Butt.L / Butt.R)のPhysBoneの削除、服の盆の削減などがその対象です。

これまで色々なアバターを軽量化し、Goodにしてきましたが、最も削減が難しいのはPhysboneでした。

言い訳に聞こえるかもしれませんが、アバターによって異なる部分も多く、「こうしてください」というような汎用性のある説明をするのが非常に難しいです。

したがって、ここではAAOの機能の説明のみを記述します。

#### 4.2.1 AAO Merge PhysBone

Physboneの結合/軽量化には`AAO Merge PhysBone`を使用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/00d6d710-9079-480f-8e1d-03a38ae57376.png)

使い方は非常に簡単で、`コンポーネント`にPhysBoneを入れていけば終わりです。

入れられるBoneの条件としては、

- `VRC PhysBone`のComponentsの内容が同じであること。
- `Root Transform`がある場合、同じ`Root Transform`を参照していること。
- 同じBoneに位置していること。

です。別のBoneに位置しているPhysBoneは結合できません。
注意点としては、以下のように髪の毛の全てのBoneをその対象とした場合、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/87ec0a7c-cd95-42cc-80dd-58c107504f7a.png)


Physboneが一体化されますので、同時に一つのBoneにしか触ったり(Grab)、固定したり(Posing)することができなくなります。

#### 4.2.2 AAO Merge Bone

`AAO Merge Bone`は使用していないBoneを削る時に使用できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/df9e8dad-05e1-42ff-b16f-23665073b08e.png)

説明の通りの感じで、`AAO Merge Bone`が導入されているBoneをそのChild(下位Bone)を削除し、親に結合させます。


---

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/d1cb8509-e33f-49d3-b85c-c54b63930b3f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/39c997b6-2c69-4ad0-b445-0d3d5383e815.png)

ここまでの作業でしなのちゃんが**Medium**になりました。

正直、Goodにしたかったのですが、見た目がそこまで変わらないレベルであれば、自分ではMediumが限界でした。

比較してみるとこんな感じになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/27776285-f2b2-4e04-a177-4da5699bc4b9.png)





## 5. その他

### 5.1 **リアル影システムや、懐中電灯などを入れている場合、常時ONは避けましょう。**

光源(Light)はVRChatにおいて、最もパフォーマンスに影響を与える要素の一つです。
簡単に説明すると、**Realtime Lightは非常に重い**です。

> VRChatは`Forward Rendering`というレンダリングによりレンダーされ、このレンダリングは $n × m$の演算を行います。ここで$ n $は**光源の数**、$ m $は光源の影響を受ける物体の**Vertex数**になります。
> 
> 光源が存在していない場合、$ m $だけの演算になりますが、一つでもRealtime Lightが存在していると、その演算量が爆発的に増加します。
> 
> 13万ポリゴンのアバターがあるとし、ワールドに光源が2個、リアル影システムが1個あるとしたら、$ 3 × 130,000 $として、膨大な演算が必要になります。
> 
> また、これにより影も計算する必要が生じます。これにより、計算量は膨大に増加し、ラグの原因となります。
> 
> これはアバターだけでなく、ワールドにも影響を与えますので「重くなる」というのは言うまでもないと思います。

少し長くなりましたが、言いたいことは一つ。

**リアル影システムやリアルタイム光源の導入はなるべく避けてほしい**と思います。


### 5.2 服を複数枚入れるのも避けましょう。

服を複数入れるのは、便利ですよね。ただ、**本当に重くなります**。避けましょう。アバターを分離してアップロードしましょう。

どうしても入れたい場合は、Animationの作成の時にその服のBoneやPhysBone Componentsまでオフにしてください。

### 5.3 Particle Systemを減らしましょう。

近年、Particle Systemを活用したアバターギミックは多数存在しています。しかし、Particle Systemもかなり重いです。減らしましょう。ぴかぴかしていてきれいなギミックは素敵ですが、なるべく避けてください。パブリックで使用するのも避けてください。ラグの原因となります。


### 5.4 Bounds範囲を調整しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/536c5936-8e55-46ec-ab8d-f5fe773dfcb4.png)

VRChatには遠いアバターは見えないように設定する機能があります。ラグの軽減のために使っている方も多いでしょう。しかし、せっかくその範囲を決めていてもBounds範囲が広いと、意味がなくなります。他人のために減らしましょう。ラグの原因となります。

### 5.5 複雑なAnimatorの使用は避けましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/9c50aea9-c9ee-4644-acc6-f85c045e8c71.png)

VRChatはAnimatorの使用ができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682031/d3343cb3-92e1-46e3-a654-ffa3f0e2bc9a.png)

AnimatorのLayerは順番に実行され、Layerが多いとCPUでの演算量が増加します。LayerのWeightが0でも計算されます。LayerとLayer内のStateはなるべく複雑にならないようにしていきましょう。


## 最後に

これで、AAO/Thryrallo/TTTなどのツールを使用したVRChatのアバターの基本的な軽量化の説明が終わりました。

アバターの軽量化は、自分自身のためだけでなく、他人のためにも必ず行っておく必要があります。

Very Poorだから「重い」というわけでもありません。できる範囲内で、軽量化していきましょう。
必ずGoodかMediumにする必要もありません。できる範囲内で、軽量化していきましょう。

自分のためにも、みんなのためにも軽量化はしていきましょう。

最適なVRChatライフのために。

最後まで読んでいただきありがとうございました。