VRChatにおけるConstraint制御

# はじめに

アイテムの持ち替えに使うコンポーネントであるConstraint各種について自分用にまとめました。

## Constraint

指定オブジェクトに依存してオブジェクトを動かせます。
ホルスターから銃を抜くなど、主にアイテムの付け替えに使います。

### Constraintの基本

#### Parent Constraint

設定したオブジェクトに追従し、そのオブジェクトの子であるかのように移動したり回転したりします。
handに追従させたいけど階層深すぎて見に行くのがだるいよ～って時に便利です。
Position Constraint と Rotation Constraint の機能を併せ持つ......。

##### Activate

Sourcesが全て0のときに"これを押した時点の位置"に移動します。
具体的にはConstraint Settingsの座標情報に現在の座標が設定されます。

##### Zero

Sourcesが全て0のときにx,y,x=0,0,0(つまりアバターの原点)に移動します。
具体的にはConstraint Settingsの座標情報が0でリセットされます。

| プロパティ | 機能 |
| ---- | ---- |
|  Is ACtive  |  オンで有効になる。Parent Constraintのチェックオフとの違いは不明  |
|  Weight  |  どれだけ追従するか。1で完全追従。変なことしない限り1で良い  |
| Constraint Settings | 色々あるがこっちが使うのは以下2つ |
| Freeze Position Axes | xyzが選べる。チェックオンの軸で位置の追従が有効 |
| Freeze Rotation Axes | xyzが選べる。チェックオンの軸で回転の追従が有効 |
| Sources | 追従するオブジェクト群。0が追従なしで1にすると完全に追従する。詳細は次項目 |

#### Position Constraint

Parent Constraint から回転追従を引っこ抜いたものです。プロパティは同じ。
角度は変えたくないが追従はしてほしい場合に使う。

#### Rotation Constraint

Parent Constraint から位置追従を引っこ抜いたものです。プロパティは同じ。
メカの関節など曲がる角度が決まっているものに使われがち。

#### Look At Constraint

指定したオブジェクトにZ軸を向ける変なコンポーネント。親戚に Aim Constraint がいます。
親に合わせて移動しないし親の回転に追従もしない。プロパティが増えてます。
ロックオンミサイルとか発煙筒炊いて近接航空支援させるとかよっぽど変なことしたい時に。

| プロパティ | 機能 |
| ---- | ---- |
| Use Up Object | Roll を無効にして World Up Object を有効にする |
| Roll  | Z軸を中心に右へ左へ回転させる。Z軸を進行方向とした飛行機のロール機動っぽい |
| World Up Object  | RollのZ軸じゃなくてY軸を参照する版 |

### Sources

全コンポーネントで使えるプロパティ。追従するオブジェクトを何個でも設定できます。

* 数値は追従の重さ。0で追従せず、1が完全に追従。
* 複数が1になっていると、その中間あたりに移動する。
* アニメーションで0と1を制御することでアイテムが指定地点の間をぬるっと移動する。

アイテムを動かしたい程度ならArmatureの子に空のGameObjectを作り、それを動かしたいオブジェクトのSourcesに設定します。
以下はホルスターから銃を抜く例です。

ホルスター収納状態
| Sources | 値 |
| ---- | ---- |
| ホルスター | 1 |
| 手 | 0 |

手で銃を持つ

| Sources | 値 |
| ---- | ---- |
| ホルスター | 0 |
| 手 | 1 |

## Constraintを利用したワールド固定

手への移動ができたら、次はワールドに固定してみましょう。

### ワールド固定用prefab作成

ヒエラルキーで適当に空のオブジェクトを作ります。position, rotationを全部0にしておきましょう。  
次にproject(フォルダの方)にドラッグドロップします。するとprefabになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116924/5f9f46b3-647b-81c6-7dca-935b26aca86b.png)
ヒエラルキーにあったものが青くなったと思います。この状態になったらヒエラルキーにある方は消しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116924/399fe5c7-1656-f660-bf10-327adac0be3f.png)
↑コレは不要。  

### 固定用Constraint設定

次にアバターの直下に空のオブジェクトを作ります。さらにその下に空のオブジェクトを作ります。上がワールドの原点に留まり続ける役目、その下がアイテムを固定する役目を担います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116924/9888067f-770e-5906-445d-76e951930842.png)
上の空オブジェクトにparent constraintを追加し、Zeroで初期化、Sourcesに先程作ったprefabを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116924/a3a1d8ed-88eb-794b-6f6c-618d1b68fe09.png)

### 固定切り替えConstraint設定

次は下の空オブジェクトにparent constraintを追加します。Zeroで初期化し、今度はSourcesにArmature以下にあるオブジェクトをなんでもいいので設定します。  
私はHips下に原点に置いたからオブジェクトを作り、これを設定しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116924/a65dd9ec-f42a-3e0c-b7cc-1774b9caa21c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116924/f32c80d5-bc30-a264-2adc-b690f09cc710.png)

### アイテム側のConstraint設定

固定したいアイテムにもConstraintします。  
今回私は前項目で手持ちと装着を実装したアイテムがあるので、それを使います。  
手持ち、装着に続いて3つ目のSourcesに下の空オブジェクトを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116924/8d2ad272-d480-cf6e-260f-37dfc1b17057.png)
この状態で下の空オブジェクトのparent constraintのチェックを外すと...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116924/720bd6b4-f12a-0a64-e2f3-d74b0a2452d1.png)
このようにワールドに固定されます。チェックを入れると位置がリセットされ、また外すと場所が更新されます。  
こんな感じで簡単に実装できます。

### ワールド固定の位置調整

先ほどの設定では固定する位置が変なので、もう少し改良します。  
もう一段下に3つ目の空のオブジェクトを作ります。これを固定したいアイテムに指定してください。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116924/e5be117d-1a00-72a1-494e-db7220190427.png)
このオブジェクトの位置を調整することで固定する角度や場所を調整します。アニメーションで動かすことでアバターに追従しないギミックを仕込んだりできます。