【VRChat】頭に追従しているときだけ自分目線から見えなくする【VRC Head Chop】

# 【経緯】
眼鏡をアバターに着せるとき詰まったのでメモ。

# 【環境】
VCC：Unity 2022 Avatar Project
Unity：2022.3.22f1

# 【本文】
* Head Chopについて
* VRC Head Chop
* 使用例
* おまけ
* 最後に

初めてこういった記事を書かせて頂いたため、至らぬ点等多々あるかと存じます。
ご意見・ご指摘等ありましたら気軽にお願いいたします。

## 【Head Chopについて】
VRChatには、Head Bone配下のオブジェクトが自分目線でのみ見えなくなるという仕様があります。VRChatはこの仕様をHeadChopと呼んでいます。~~（くびちょんぱって、コト……！？）~~

>When wearing an avatar, VRChat automatically "chops off" the avatar's head bone by setting its transform scale to almost 0.
>>アバターを着用したとき、VRChatは自動的にアバターのHead Boneを（Scaleのtransformをほぼ0にして）"切り落とし"ます。

<a href="https://creators.vrchat.com/avatars/avatar-dynamics/vrc-headchop/">Head Chop | VRChat creation</a>

内部ではScaleが変動しているだけなので、Scale ConstraintコンポーネントでHead BoneをSourceに設定すれば、Head Bone配下にオブジェクトをぶち込まずとも、Head Chopのおこぼれに与ることができます。（VRC Head Chopが実装されるまではこの方法しかなかった。）

ところが、「そんなことしなくても、コンポーネントを設定するだけでHead Chopの挙動を指定のオブジェクトにも適用するよ」と言ってくれる気の利いた奴がいます。

……そう、それが **VRC Head Chop** コンポーネントです。

## 【VRC Head Chop】
コンポーネントの解説です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989021/31be7fd1-e2f4-800b-4bb1-8a368165ef43.png)

**Target Bones**：Head Chopを適用するオブジェクトのリスト
　**Transform**：対象オブジェクト
　**Scale Factor**：Scaleをどの程度絞るか。0で非表示、1で表示
　**Apply Condition**：どのプラットフォームのときHead Chopを適用するか
　―Always Apply：すべてのプラットフォームで適用
　―Vr Only：VRのときだけ適用
　―Non Vr Only：VRでないときに適用

**Global Scale Factor**：Target BonesにScale Factorを纏めて適用（Global Scale Factor分先に絞っておくような挙動だと思います。要検証。）

<a href="https://creators.vrchat.com/avatars/avatar-dynamics/vrc-headchop/">Head Chop | VRChat creation</a>

:::note warn
Scale Factorの初期値は１（表示される状態）になっています。
:::

## 【使用例】

今回は眼鏡の改変を元にVRC Head Chopを使用例をご紹介します。
要件は以下の通りです。
* 眼鏡の追従位置を複数パターン用意したい　（普通・頭の上・手に持つなど）
* 眼鏡を掛けてるときは眼鏡を非表示し、持っているときは表示させたい
* 追従パターンごとに自動で眼鏡の表示を切り替えたい

***

### 前準備（参考）

このような眼鏡を用意して、普通・緩く掛ける・頭の上・右手に持つの差分を作成しました。~~（かわいいですね。）~~

![スクリーンショット 2025-01-20 224108.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989021/3c9f347c-559a-4bd1-414a-4bf5c2e05dbe.png)

階層はこんな感じでアバターの直下に配置しています。

![スクリーンショット 2025-01-21 011110.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989021/23b99d27-2eaf-c55a-c0cf-c5ede014ab9a.png)

GlassesWellingtonは眼鏡本体で、
以下のようにParent Constraintを使用することで、Sourcesの参照先を切り替えています。（Zeroで有効化）

![スクリーンショット 2025-01-21 012127.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989021/6706932e-45f9-ba03-5c42-cf683bba2e98.png)

BoneHead、BoneHandについては、設定している座標が上記の普通・緩く掛ける・頭の上・右手に持つの差分の位置になっています。また、上３つはHead追従、下１つはHand_R追従です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989021/72547eaa-54d9-5194-88ab-01c2e9ab8e0c.png)

***

### 問題点

次に、VRChat（VR）で動かしてみましょう。

Sceneを見る限りは問題なさそうですが、実際にプレイしてみると下記の問題点が発生します。（上はHeadBone_Center、下はHeadBone_Belowに追従させています。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989021/5186ce14-f726-dded-e219-4e551fe10ceb.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989021/9c279137-e7d8-046a-5a88-622225a0f629.png)

**眼鏡が視界に入ってしまっていますね。** 

眼鏡にHead Chopが行われていないため、自分の視点からでも見えてしまいます。
今回の場合は視界の邪魔になってしまっているので、消すことにしましょう。

対処法としては
* Head Bone直下にオブジェクトを設置する
* Scale Constraintを使用してSourcesの参照先をHead Boneにする
* VRC Head Chopコンポーネントを使用して非表示にする

の３つが考えられます。

今回はBoneを間接的に参照していて、切り替えが発生しますので、VRC Head Chopコンポーネントを使用しましょう。

***

### 解決策（VRC Head Chop）

VRC Head Chopを親オブジェクトに追加して、以下のように設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989021/c6829bc7-c617-5995-d081-77405c22fb34.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989021/2572af7a-faf5-4308-e5ab-9b665774c034.png)

Global Scale Factorを0にしているため、Target Bonesはすべて非表示になります。

アップロードして確認すると……

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989021/0493d0bc-7898-e084-9dc7-acceec16b9a9.png)

**自分目線から眼鏡が消えましたね！！！**

これがVRC Head Chopの使い方になります。

***

### 違う、そうじゃない。（蛇足）

上記の挙動ですが、頭の上に眼鏡があるときは別に表示されていてもいいでしょうし、
右手に持っているときはむしろ表示されてほしいのに消えてしまっていますね。

ということで、要旨とは少しズレますが、アニメーションを使って切り替える方法も併せてご紹介します。

まず、VRC Head Boneの切り替えAnimationを用意しましょう。

![スクリーンショット 2025-01-21 024113.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989021/5654e3b8-d718-30d9-5f61-5ffc9111f4d6.png)

:::note warn
VRC Head Chopが有効になったときは眼鏡が非表示になるため、ViewOffではコンポーネントを有効にし、ViewOnでは無効にしています。
:::

ここから、IsViewというParameterを定義して、IsViewがTrueのときはViewOn、FalseのときはViewOffのアニメーションが走るようにしていきます。

説明を省いていましたが、先ほどの追従位置の切り替えはExpressionMenuを使用して行っていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989021/b94222b8-ea22-0b60-0026-cc25d355e61a.png)

IsViewをTrue（表示の状態）にしたいのは、頭の上に乗ったときと、手に持ったときなので、そのStateに到達したとき値が切り替わるようにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989021/aa2690bc-43f0-b5e0-6eff-f2dde0b50156.png)

[ Add Behaviour ]から **VRC Parameter Driver** コンポーネントを選択して、
以下の手順で設定を行います。

* Addを押下
* TypeからSet、DestinationからIsViewを設定
* Valueに☑を入れる（Trueにする）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989021/a7d264df-670c-55b9-99b3-532dd847a5d1.png)

（詳しい説明は省きますが、このコンポーネントがくっついているStateに到達したとき値をSetしてくれるコンポーネントです。）

この設定を４つのStateに同様に行います。（HeadC・HeadBはFalse、HeadA・Hand_RはTrue）

これで設定は完了なので、アップロードして確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989021/dfa72dde-7275-4f76-9da4-44e68f1584d4.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989021/c81dde6c-5673-3ccc-d7e8-f4df07f2b80e.png)

**頭に追従しているときだけ自分目線から見えなくする** ことができました！~~（タイトル回収）~~

ということで、VRC Head Chopの使い方でした。

ご清聴ありがとうございました。

## 【おまけ】

VRC Head Chopコンポーネントは、Head Boneに適用されるHead Chopも上書きできるため、自分の髪を視界に表示させるといったことも可能らしいです。なるほどなぁ。

<a href="https://zenn.dev/sarashinanoniki/articles/afbfc91277e3be">【VRChat】VRCHeadChopで自分の髪を感じよう！ - Zenn</a>

## 【最後に】

今回使用させていただいたモデルはこちらです。今回の記事の執筆にあたって快く参考画像への使用許可をいただきました。この場をお借りして感謝申し上げます。

https://kujishift.booth.pm/items/3190100