Modular Avatarにワールド固定ギミックを含める
最近bd_さんによってリリースされたModular Avatarは、アバター改変において非破壊的なワークフローを導入でき非常に便利なツールとなっています。 自身でも仮想年賀状や鳴子の配布パッケージに利用させていただいているのですが、今回はこれらのパッケージに実装したワールド固定の仕組みについて解説します。
Modular Avatarの仕組み
Modular Avatarはアバターのデータがビルドされる手前でオブジェクトのパス修正やアニメーションの統合、パラメーター名の変更などを行い、統合・変更後のデータに自動的に差し替えを行うことで、既存のファイルを変更することなく改変内容を適用するような仕組みとなっています。 これによりアバター本体と小物ギミックのリソースファイルを綺麗に分離しやすくなるため、メンテナンス性の向上や、配布用パッケージの作成の省力化ができ、非常に便利です。
今回の解説ではModular Avatarが提供するBone Proxy、Menu Installer、Merge Animator、 Parametersの4種類のコンポーネントを利用してワールド固定を含んだパッケージの作成を行っていきます。 この解説では各コンポーネントの詳細については扱わないので、必要に応じてマニュアルページをご参照ください。
0. Modular Avatarの導入
リリース一覧ページから最新のModular AvatarのUnit Packageをダウンロードし、プロジェクトにインポートしてください。
執筆時の最新版は 1.2.0 です。
1. ワールド固定用Prefabの作成
ワールド固定は何通りかやり方があるのですが、Modular Avatarで設定を行って配布すると考えた場合、空のGameObjectのみを含むPrefabを作成し、シーンには配置せずParent Constraintのソースに指定する手法が適しています。
- まずはヒエラルキーウィンドウを右クリックし、 Create Empty を選択して空オブジェクトを作成します。
- 作成後にTransformをリセットし、位置や角度を0に揃えます。また、オブジェクトの使用用途から
WorldAnchorという名前に変更しています。
作成したオブジェクトをプロジェクトウィンドウにドラッグ&ドロップし、Prefab化します。ここでは Assets/XiPHiA/Common/Prefabs 以下に作成しています。
Prefab化ができたらシーン上では必要が無いので、ヒエラルキーウィンドウから WorldAnchor オブジェクトを削除しておきます。
2. ギミック用のオブジェクトの配置
ここからはアバターを使いながら作業を進めていきます。この解説ではSDKに付属するサンプルアバター( Packages/VRChat SDK - Avatars/Samples/Dynamics/Robot Avatar/Tutorial_Robot_Avatar_Dynamics_Demo_v1.prefab )を使用して説明を行います。
アバターオブジェクトの直下にギミック用のオブジェクトを作成します。ここでは GimmickRoot としています。
作成したギミック用のオブジェクトにParent Constraintを追加し、先ほど作成したワールド固定用Prefabをソースに設定します。
Parent Constraintは以下の表のとおりの設定となります。
| 設定項目 | 設定内容 |
|---|---|
| Is Active | オン |
| Weight | 1 |
| Constraint Settings / Lock | オン |
| Constraint Settings / Position At Rest | 0, 0, 0 |
| Constraint Settings / Rotation At Rest | 0, 0, 0 |
| Constraint Settings / Position Offset (WorldAnchor) | 0, 0, 0 |
| Constraint Settings / Rotation Offset (WorldAnchor) | 0, 0, 0 |
| Constraint Settings / Freeze Position Axes | 全てオン |
| Constraint Settings / Freeze Rotation Axes | 全てオン |
| Sources | WorldAnchor, ウェイト1 |
2-1. ハンドボーン追従オブジェクトの作成
作成したギミック用のオブジェクト直下に手の位置や姿勢に追随させるためのオブジェクトを作成します。ここでは HandRef としています。
作成したオブジェクトにMA Bone Proxyを追加し、追従させたい手のボーンを Target(ターゲット) にドラッグ&ドロップします。
そのあと、 Attachment Mode(配置モード) を As child; at root(子として・ルートに配置) に設定します。
2-2. 小物配置用オブジェクトの作成
作成したギミック用のオブジェクト直下に小物を配置するためのオブジェクトを作成します。ここでは Pivot としています。
作成したギミック用のオブジェクトにParent Constraintを追加し、先ほど作成したハンドボーン追従オブジェクトをソースに設定します。
Parent Constraintは以下の表のとおりの設定となります。
| 設定項目 | 設定内容 |
|---|---|
| Is Active | オン |
| Weight | 1 |
| Constraint Settings / Lock | オン |
| Constraint Settings / Position At Rest | 0, 0, 0 |
| Constraint Settings / Rotation At Rest | 0, 0, 0 |
| Constraint Settings / Position Offset (WorldAnchor) | 0, 0, 0 |
| Constraint Settings / Rotation Offset (WorldAnchor) | 0, 0, 0 |
| Constraint Settings / Freeze Position Axes | 全てオン |
| Constraint Settings / Freeze Rotation Axes | 全てオン |
| Sources | HandRef, ウェイト1 |
2-3. 小物の配置と位置調整
先ほど作成した小物配置用オブジェクト直下にワールド固定したい小物を配置します。ここでは縮小したCubeを配置し、手のひらの上に来るように位置を調節しています。また、Box Colliderを削除しています。
3. ワールド固定ギミックの実装
オブジェクト配置と基本的な設定は完了したので、ここからギミックの実装に入ります。
3-1. アニメーションコントローラーの作成
ギミックの状態管理に使用するアニメーションコントローラーを作成します。プロジェクトウィンドウの右ペインを右クリックし、 Create -> Animation Controller を選択します。
ここでは Assets/XiPHiA/Gimmick/Animations/Contorllers 以下に GimmickController として作成しています。
3-2. アニメーターの設定
ギミック用オブジェクト( GimmickRoot ) にAnimatorを追加し、先ほど作成したアニメーションコントローラーを Controller に設定します。
3-3. アニメーションコントローラーの設定
3-3-1. 制御用パラメーターの追加
3-1. で作成したアニメーションコントローラーを設定します。まずはAnimatorウィンドウのParameterタブを開き、 Bool 型のパラメーターとして、 Active と Drop の2つを追加します。
Active はオブジェクトの表示・非表示の切り替え、 Drop はワールド固定と手持ちの切り替えに使用します。
3-3-2. 表示・非表示用アニメーションの作成
表示・非表示を切り替えるために使用するアニメーションを作成します。プロジェクトウィンドウの右ペインを右クリックし、 Create -> Animation を選択します。
ここでは Assets/XiPHiA/Gimmick/Animations/Clips 以下に Active と Inactive として2つ作成しています。
3-3-3. 表示・非表示切り替えレイヤーの設定
- AnimatorウィンドウのLayerタブを開き、初期レイヤーである
Base LayerをActiveに名前を変更し、Inactiveステート とActiveステートの2つを追加します。 - 作成したステートの Motion に 3-3-2. で作成した対応する名前のアニメーションを設定します。
Inactiveステートをデフォルトステートに設定し、EntryステートからActiveステートへのトランジションと、InactiveステートとActiveステート間の両方向にトランジションを追加します。EntryステートからActiveステートへのトランジション遷移条件にActiveパラメーターを追加し、条件値をfalseに設定します。InactiveステートからActiveステートへのトランジション遷移条件にActiveパラメーターを追加し、条件値をfalseに設定します。ActiveステートからInactiveステートへのトランジション遷移条件にActiveパラメーターを追加し、条件値をtrueに設定します。
各ステートとトランジションの設定は以下のようになります。
Inactiveステート
| 設定項目 | 設定内容 |
|---|---|
| Motion | Inactive |
| Speed | 1 |
| Multiplier | オフ |
| Motion Time | オフ |
| Mirror | 全てオフ |
| Cycle Offset | 0, オフ |
| Foot IK | オフ |
| Write Defaults | オフ |
Activeステート
| 設定項目 | 設定内容 |
|---|---|
| Motion | Active |
| Speed | 1 |
| Multiplier | オフ |
| Motion Time | オフ |
| Mirror | 全てオフ |
| Cycle Offset | 0, オフ |
| Foot IK | オフ |
| Write Defaults | オフ |
Entry -> Activeへのトランジション
| 設定項目 | 設定内容 |
|---|---|
| Conditions / Active | true |
Inactive -> Activeへのトランジション
| 設定項目 | 設定内容 |
|---|---|
| Has Exit Time | オフ |
| Settings / Exit Time | 0 |
| Settings / Fixed Duration | オン |
| Settings / Transition Durasion (s) | 0 |
| Settings / Transition Offset | 0 |
| Settings / Interruption Source | None |
| Settings / Ordered Interruption | オン |
| Conditions / Active | true |
Inactive -> Activeへのトランジション
| 設定項目 | 設定内容 |
|---|---|
| Has Exit Time | オフ |
| Settings / Exit Time | 0 |
| Settings / Fixed Duration | オン |
| Settings / Transition Durasion (s) | 0 |
| Settings / Transition Offset | 0 |
| Settings / Interruption Source | None |
| Settings / Ordered Interruption | オン |
| Conditions / Active | false |
3-3-4. 表示・非表示切り替えアニメーションの設定
3-3-2. で作成したアニメーションを設定します。 2. で作成したギミック用のオブジェクトを選択した状態で、Animationウィンドウを開きます。
Inactiveアニメーションを選択した状態で、Add Propertyボタンを押してPivot -> 2-3で配置した小物(ここではCube) -> Is Activeを追加します。- プロパティ―名横のチェックボックスをオフにし、1:00地点に追加されたキーフレームを削除します。
Activeアニメーションを選択した状態で、1. と同じようにAdd Propertyボタンを押してPivot -> 2-3で配置した小物(ここではCube) -> Is Activeを追加します。- プロパティ―名横のチェックボックスをオンのままにし、1:00地点に追加されたキーフレームを削除します。
3-3-5. ワールド固定用アニメーションの作成
ワールド固定・手持ちを切り替えるために使用するアニメーションを作成します。 3-3-2. と同じようにプロジェクトウィンドウの右ペインを右クリックし、 Create -> Animation を選択します。
ここでは Assets/XiPHiA/Gimmick/Animations/Clips 以下に Drop と Hold として2つ作成しています。
3-3-6. ワールド固定・手持ち切り替えレイヤーの設定
- AnimatorウィンドウのLayerタブを開き、新規に
Dropレイヤーを作成し、レイヤーのウェイトを1に設定します。 Holdステート とDropステートの2つを追加します。- 作成したステートの Motion に 3-3-5. で作成した対応する名前のアニメーションを設定します。
Holdステートをデフォルトステートに設定し、EntryステートからDropステートへのトランジションと、HoldステートとDropステート間の両方向にトランジションを追加します。EntryステートからDropステートへのトランジション遷移条件にDropパラメーターを追加し、条件値をfalseに設定します。HoldステートからDropステートへのトランジション遷移条件にDropパラメーターを追加し、条件値をfalseに設定します。DropステートからHoldステートへのトランジション遷移条件にDropパラメーターを追加し、条件値をtrueに設定します。
各ステートとトランジションの設定は以下のようになります。
Holdステート
| 設定項目 | 設定内容 |
|---|---|
| Motion | Hold |
| Speed | 1 |
| Multiplier | オフ |
| Motion Time | オフ |
| Mirror | 全てオフ |
| Cycle Offset | 0, オフ |
| Foot IK | オフ |
| Write Defaults | オフ |
Dropステート
| 設定項目 | 設定内容 |
|---|---|
| Motion | Drop |
| Speed | 1 |
| Multiplier | オフ |
| Motion Time | オフ |
| Mirror | 全てオフ |
| Cycle Offset | 0, オフ |
| Foot IK | オフ |
| Write Defaults | オフ |
Entry -> Dropへのトランジション
| 設定項目 | 設定内容 |
|---|---|
| Conditions / Drop | true |
Hold -> Dropへのトランジション
| 設定項目 | 設定内容 |
|---|---|
| Has Exit Time | オフ |
| Settings / Exit Time | 0 |
| Settings / Fixed Duration | オン |
| Settings / Transition Durasion (s) | 0 |
| Settings / Transition Offset | 0 |
| Settings / Interruption Source | None |
| Settings / Ordered Interruption | オン |
| Conditions / Drop | true |
Drop -> Holdへのトランジション
| 設定項目 | 設定内容 |
|---|---|
| Has Exit Time | オフ |
| Settings / Exit Time | 0 |
| Settings / Fixed Duration | オン |
| Settings / Transition Durasion (s) | 0 |
| Settings / Transition Offset | 0 |
| Settings / Interruption Source | None |
| Settings / Ordered Interruption | オン |
| Conditions / Drop | false |
3-3-7. 表示・非表示切り替えアニメーションの設定
3-3-5. で作成したアニメーションを設定します。2. で作成したギミック用のオブジェクトを選択した状態で、Animationウィンドウを開きます。
Holdアニメーションを選択した状態で、Add Propertyボタンを押してPivot -> Parent Constraint -> Activeを追加します。- プロパティ―名横のチェックボックスをオンのままにし、1:00地点に追加されたキーフレームを削除します。
Dropアニメーションを選択した状態で、1. と同じようにAdd Propertyボタンを押してPivot -> Parent Constraint -> Activeを追加します。- プロパティ―名横のチェックボックスをオフにし、1:00地点に追加されたキーフレームを削除します。
4. Modular Avatarの設定
ギミックの実装が完了したので、Modular Avatarによる設定を行っていきます。
4-1. Merge Animatorの設定
- 2. で作成したギミック用のオブジェクト(ここでは
GimmickRoot)にMA Merge Animatorを追加し、 3-1. で作成したアニメーションコントローラー(ここではGimmickController)を Animator to merge(統合されるアニメーター) にドラッグ&ドロップします。 - Delete attached animator(付属アニメーターを削除) と Match Avatar Write Defaults(アバターのWrite Defaults設定に合わせる) にチェックを入れます。
4-2. Parametersの設定
- 2. で作成したギミック用のオブジェクト(ここでは
GimmickRoot)にMA Parameterを追加し、 Show Prefab Developer Options(プレハブ開発者向け設定を表示) にチェックを入れます。 - 3-3-1. で設定したパラメーターがリストに表示されるので、それぞれ Internal(内部値) にチェックを入れ、 Sync Mode(同期モード) を
Boolに設定します。
4-3. Menu Installerの設定
4-3-1. メニュー追加用Expression Menuの作成
ワールド固定などの操作を行うメニューを作成します。
- プロジェクトウィンドウの右ペインを右クリックし、 Create -> VRChat -> Avatars -> Expressions Menu を選択します。
- ここでは
Assets/XiPHiA/Gimmick/ExpressionMenu以下にGimmickMenuとして作成しています。
- ここでは
- インスペクターのAdd Controlボタンからメニューを追加し、 Name を
Activeに設定します。- Type を
Toggleに設定し、 Parameter の右側のテキストボックスにActiveと入力します。Parameter not found on the active avatar descriptor.と表示されますが問題ありません。
- Type を
- 再度インスペクターのAdd Controlボタンからメニューを追加し、 Name を
Dropに設定します。- Type を
Toggleに設定し、 Parameter の右側のテキストボックスにDropと入力します。- こちらも
Parameter not found on the active avatar descriptor.と表示されますが問題ありません。
- こちらも
- Type を
続いて上位階層用のメニューを作成します。
- プロジェクトウィンドウの右ペインを右クリックし、 Create -> VRChat -> Avatars -> Expressions Menu を選択します。
- ここでは
Assets/XiPHiA/Gimmick/ExpressionMenu以下にRootMenuとして作成しています。
- ここでは
- インスペクターのAdd Controlボタンからメニューを追加し、 Name を
Gimmickに設定します。- Type を
Sub Menuに設定し、 Sub Menu に先ほど作成したGimmickMenuをドラッグ&ドロップします。
- Type を
4-3-2. Menu Installerコンポーネントの追加
- 2. で作成したギミック用のオブジェクト(ここでは
GimmickRoot)にMA Menu Installerを追加します。 - Prefab Developer Options(プレハブ開発者向け設定) を展開し、 Menu to Install(インストールされるメニュー) に 4-3-1. で作成した上位階層用のメニュー(ここでは
RootMenu)をドラッグ&ドロップします。
5. 仕上げ
以上でワールド固定が可能な小物出し入れギミックの実装が完了しました。最後にModular Avatarのチュートリアルで推奨されているように、コンポーネントの並び替えを行います。 Menu Installer、Parameters、Merge Animatorの順で先頭から並ぶよう調整します。
最後にギミック用のオブジェクト(ここでは GimmickRoot )をPrefab化します。ここでは Assets/XiPHiA/Gimmick/Prefabs 以下に作成しています。
あとは GimmickRoot Prefabを選択してExport Packageを行うことで、Modular Avatarに対応したワールド固定ができる、出し入れ可能な小物として配布することが可能になります。