DeepFrostIce アニメーション設定

DeepFrostIce / VRChat Avatar

パラメータをアニメーションで動かす

DeepFrostIce の凍結・融解・厚み吸収・ディゾルブ・トップスノー・スパークル・表示切替を、VRChat の Expression Menu から動かすためのガイドです。同梱サンプルをドラッグするだけの最短ルート(STEP A)と、仕組みを理解して自分のメッシュに組む/改変するルート(STEP B)の二段構えでまとめています。

仕組みの全体像

やることは一本道です。メニュー操作同期パラメータを変え、それが FXレイヤーを通じて AnimationClip を再生し、クリップが Renderer 上の material.<プロパティ> を書き換えます。

MENUExpression Menu
「DeepFrostIce」
PARAMDFI_Freeze など
Float / Bool
FX LAYERAnimator
レイヤー
CLIPAnimationClip
RESULTmaterial.
_FreezeAmount
メニュー操作から見た目の変化まで。左から右へ値が伝わる。

この鎖は同梱サンプルに全部入っています

クリップ・AnimatorController・Expression パラメータ・メニュー・Modular Avatar の設定はすべて Sample/ に生成済みです。まず動かしたいだけなら STEP A だけで完了します。自分のメッシュに適用したい・値を変えたい場合に STEP B へ進んでください。

Step A

同梱サンプルをそのまま使う

プレハブをアバターの配下にドラッグしてアップロードするだけで、Expression Menu に「DeepFrostIce」サブメニューが追加され、Radial スライダーとトグルで氷を動かせます。Animator もパラメータもメニューも、手で触る必要はありません。

用意するもの

  • VRChat SDK3(Avatars)を導入した Unity プロジェクト
  • Modular Avatar(サンプルのマージに使用)
  • DeepFrostIce 本体(Sample/ フォルダを含む)
  1. アバターのシーンを開く

    いつもアップロードしているアバターのシーンを開き、Hierarchy にアバターが置かれている状態にします。

  2. サンプルをアバター配下にドラッグ

    Sample/DeepFrostIceSample.prefab を、Hierarchy 上でアバターの子になるようにドラッグ&ドロップします。これだけで、FX レイヤー・同期パラメータ・メニューがビルド時にマージされる状態になります。

    ドラッグ後の Hierarchy
    YourAvatar
    ├─ Armature ...
    ├─ Body ...
    └─ DeepFrostIceSample              ← ドラッグしたプレハブ
       └─ DeepFrostIce Sphere          (Renderer + DeepFrostIceSample.mat)
  3. 位置とスケールを調整(任意)

    既定は 0.15 スケールの氷球プロップです。手や腰のボーンの下に入れる、大きさを変えるなど、好きな見せ方に調整してかまいません。

  4. いつも通りアップロード

    VRChat SDK からいつも通りビルド&アップロードします。ビルド時に Modular Avatar が、FX Controller・Expression Parameters・Expression Menu へ自動でマージします。アバター側の既存メニューやパラメータは壊れません。

  5. VRChatで動かす

    Expression Menu を開き、「DeepFrostIce」サブメニューへ入ります。Freeze / Melt / Absorption / Dissolve は Radial Puppet(リングを回して 0 から増やす)、Top Snow / Sparkle / Visible はトグルです。

初期値について

Radial の4つ(Freeze / Melt / Absorption / Dissolve)は既定 0=未適用の状態から始まります。トグルの3つ(Top Snow / Sparkle / Visible)は既定 ON なので、アップロード直後から見た目で効果を確認できます。いずれも saved 指定なので、ワールドをまたいでも最後の状態が維持されます。

サンプルの操作一覧

「DeepFrostIce」サブメニューの7項目が、それぞれどのパラメータ・どのプロパティに繋がっているかの対応表です。STEP B で自作・改変するときの設計図にもなります。

DeepFrostIceSample のメニュー項目とパラメータの対応
メニュー項目種類同期パラメータ動かす対象レンジ / 値
FreezeRadial PuppetDFI_Freeze
Float・saved・既定0
material._FreezeAmount0 → 1
MeltRadial PuppetDFI_Melt
Float・saved・既定0
material._MeltAmount0 → 1
AbsorptionRadial PuppetDFI_Absorption
Float・saved・既定0
material._AbsorptionDensity0 → 5
DissolveRadial PuppetDFI_Dissolve
Float・saved・既定0
material._DissolveAmount0 → 1
Top SnowToggleDFI_TopSnow
Bool・saved・既定ON
material._TopSnowAmount0 / 0.6
SparkleToggleDFI_Sparkle
Bool・saved・既定ON
material._SparkleIntensity0 / 3
VisibleToggleDFI_Visible
Bool・saved・既定ON
子GameObject の m_IsActiveOff / On

Absorption だけレンジが 0→5 ですが、パラメータ自体は他と同じ 0〜1 です。これはクリップ側の値レンジを 0→5 にしているだけ、という点が後の STEP B-1 の要点になります。

Step B-1

クリップを作る

Animation ウィンドウで、対象は必ず Renderer が乗っている GameObject(サンプルでは DeepFrostIce Sphere)を選びます。バインドのキーは material.<プロパティ名> です(Unity では「Mesh Renderer → Material._プロパティ」として一覧に出ます)。

連続値のクリップ(線形カーブ1本)

先頭に from、末尾に to のキーを打った線形カーブを1本だけ入れます。クリップの長さ自体は Motion Time で正規化されるため意味を持ちません(1秒で十分)。0→1 以外のレンジは、パラメータではなくクリップの値レンジ側で表現します。

DeepFrostIceSample_Freeze.anim の中身
対象 GameObject : DeepFrostIce Sphere   (Rendererが乗る子)
プロパティ      : Mesh Renderer → Material._FreezeAmount
キー            : 0.00s = 0   /   1.00s = 1    (線形 / Linear)

Melt / Dissolve も同じ形(0→1):
  DeepFrostIceSample_Melt      : Material._MeltAmount       0 → 1
  DeepFrostIceSample_Dissolve  : Material._DissolveAmount   0 → 1

Absorption だけ末尾キーが 5:
  DeepFrostIceSample_Absorption: Material._AbsorptionDensity  0 → 5

オン/オフのクリップ(定数2本)

Off と On で1本ずつ、それぞれ1フレームの定数クリップを作ります。Write Defaults を off で運用するため、Off クリップでも必ずそのプロパティを off 値で打つのが要点です(打たないと値が戻りません)。

トグル用の定数クリップ(4本)
DeepFrostIceSample_TopSnowOff  : Material._TopSnowAmount   = 0
DeepFrostIceSample_TopSnowOn   : Material._TopSnowAmount   = 0.6

DeepFrostIceSample_SparkleOff  : Material._SparkleIntensity = 0
DeepFrostIceSample_SparkleOn   : Material._SparkleIntensity = 3

いずれも1フレームの定数カーブ

表示/非表示のクリップ(m_IsActive)

オブジェクトごと消す場合は、マテリアルではなく 子 GameObject の有効状態m_IsActive)を動かします。ポイントは、Animator が乗るルート(DeepFrostIceSample)ではなくその子(DeepFrostIce Sphereを対象にすること。子を対象にすれば、非表示にしても Animator まで止まりません。

DeepFrostIceSample_Visible*.anim の中身
対象 GameObject : DeepFrostIce Sphere   (子。ルートではない)
プロパティ      : Is Active  (m_IsActive / type = GameObject)

DeepFrostIceSample_VisibleOff : 0   (1フレーム定数)
DeepFrostIceSample_VisibleOn  : 1   (1フレーム定数)

自分のメッシュに適用したいとき

サンプルの氷球ではなく自分のアクセサリや衣装に使いたい場合は、DeepFrostIce のマテリアルを自分の Renderer に割り当て、上記クリップの対象 GameObject を自分の Renderer に差し替えるだけです。プロパティ名とレンジはそのまま使えます。

Step B-2

Animatorレイヤーを組む

FX 用の AnimatorController に、パラメータごとに1レイヤーを足します。サンプルの DeepFrostIceSample.controller7レイヤー(Motion Time 4本+トグル3本)構成で、マージ先に無駄が残らないよう自動生成される空の Base Layer は削除してあります。各レイヤーは Weight = 1Write Defaults = off で統一しています。

パラメータを宣言する

Animator の Parameters に、連続値は FloatDFI_Freeze / DFI_Melt / DFI_Absorption / DFI_Dissolve)、オン/オフは BoolDFI_TopSnow / DFI_Sparkle / DFI_Visible)を追加します。名前は Expression パラメータ名と完全一致させます。

Motion Time レイヤー(Radial Puppet 用・4本)

1ステートだけのレイヤーを作り、その State に 0→1 のクリップを置きます。State のインスペクタで Motion Time を有効化し、対応する Float パラメータを割り当てます。すると 0〜1 のパラメータがクリップの正規化時間へ写像され、結果としてクリップの from→to(Absorption なら 0→5)へ写ります。

Layer:Freeze weight 1 ・ Write Defaults off
Freeze Motion = DeepFrostIceSample_Freeze Motion Time = DFI_Freeze
Layer:Absorption weight 1 ・ Write Defaults off
Absorption Motion = DeepFrostIceSample_Absorption(0→5) Motion Time = DFI_Absorption
Motion Time レイヤー:1ステートで 0–1 をクリップの時間に写す。Melt / Dissolve も同型。

Off/On トグルレイヤー(3本)

Off / On の2ステートを作り、既定ステートは Off。Bool パラメータで相互遷移させます。Off→On は「If」、On→Off は「IfNot」。どちらも Has Exit Time = off、遷移時間は 0.1 秒です。

Layer:TopSnow weight 1 ・ Write Defaults off ・ default = Off
Off _TopSnowAmount = 0
If  DFI_TopSnow IfNot  DFI_TopSnow
On _TopSnowAmount = 0.6
トグルレイヤー:Bool で Off/On を往復。Sparkle(0 / 3)と Visible(m_IsActive)も同型。

Write Defaults の統一

FX 全体で Write Defaults の on/off を混在させないのが鉄則です。サンプルは off 前提で、各ステートのクリップに「そのステートで欲しい値」を明示的に入れています。Modular Avatar の Match Avatar Write Defaults が、マージ先アバターの流儀に自動で合わせます。

Step B-3

同期パラメータとメニュー

Animator を動かすための 同期パラメータ と、それを触るための Expression Menu を用意します。

Expression Parameters

  • 連続値:FloatSaved 有効、既定値 0DFI_Freeze ほか4つ)。
  • オン/オフ:BoolSaved 有効既定 ON を明示(DFI_TopSnow / DFI_Sparkle / DFI_Visible)。
  • 名前は Animator のパラメータ名と完全一致させます。

Expression Menu

  • Radial Puppet:コントロール自身の Parameter は空のまま、Rotation(サブパラメータ)に Float 名を割り当てます。
  • Toggle:コントロールの Parameter に Bool 名を割り当て、Value = 1。
  • 7項目はルートに直挿しせず、サブメニュー1個にまとめて、ルートにはその入口を1つだけ置きます。サンプルでは DeepFrostIceSampleMenuControls.asset に7項目、DeepFrostIceSampleMenu.asset に「DeepFrostIce」サブメニュー1件、という2枚構成です。
  • アバターのルートメニュー
    • (アバター既存の項目…)
    • DeepFrostIce SubMenu
      • Freeze Radial
      • Melt Radial
      • Absorption Radial
      • Dissolve Radial
      • Top Snow Toggle
      • Sparkle Toggle
      • Visible Toggle
ルートには SubMenu を1つだけ。中に7項目をまとめてルートを圧迫しない。
Step B-4

Modular Avatarでマージする

Controller・Parameters・Menu を、プレハブのルート(DeepFrostIceSample)に載せた4つのコンポーネントでアバターへマージします。これが「ドラッグするだけで動く」正体です。

  1. Animator(一時置き)

    ルートに Animator を付け、Controller に DeepFrostIceSample.controller を指定します。これはマージ用の受け渡しで、下の Merge Animator がマージ後に自動で外します

  2. MA Merge Animator

    • Merge Animator To = DeepFrostIceSample.controller
    • Layer Type = FX
    • Delete Attached Animator = ON(上の一時 Animator を掃除)
    • Path Mode = Relative(クリップのパスをプレハブ内の Renderer に解決)
    • Match Avatar Write Defaults = ON
  3. MA Parameters

    7つの同期パラメータをアバターの Expression Parameters へ登録します。Float 4つは Saved・既定 0Bool 3つは Saved・明示的に既定 ONを指定しています。

  4. MA Menu Installer

    Menu to AppendDeepFrostIceSampleMenu.asset(「DeepFrostIce」SubMenu を1つ持つルートメニュー)を指定します。アバターのメニューへその SubMenu が append され、ルートを埋めません。

MAでマージする利点

Controller・Parameters・Menu をアバター本体へ手作業でコピーしないので、既存設定と衝突しない複数アバターに使い回せる更新の差し替えが楽という利点があります。Renderer とマテリアルは同じプレハブ内に置き、Relative パスで解決させます。

MAを使わない手動組み込み

Modular Avatar を使わない場合は、同じ中身をアバター本体へ直接足します。手数が増え、衝突にも注意が要りますが仕組みは同じです。

  • FX Controller:STEP B-2 の7レイヤー(Motion Time 4本/トグル3本)をアバターの FX AnimatorController へ複製。クリップのバインドパスが、アバター配下での Renderer のパスと一致するようパスを合わせ直します
  • Expression ParametersDFI_* の Float 4つ(Saved・0)/Bool 3つ(Saved・既定ON)を手動登録。
  • Expression Menu:SubMenu を作って Radial/Toggle の7コントロールを入れ、アバターのメニューへその SubMenu を追加。
  • Write Defaults はアバターの FX 全体の流儀に合わせて統一します(混在させない)。

つまずきやすい注意点

動かないとき・意図せぬ挙動のとき、まずここを疑ってください。

Write Defaults の混在

FX 内で on/off が混ざると値が戻らない・効かないの温床に。全体で統一。off なら各ステートで欲しい値を必ず明示します。

Motion Time のレンジ

Radial は必ず 0〜1。Absorption の 0→5 のような幅はクリップ側の値レンジで表現します。パラメータを 0〜5 にしようとしないこと。

ルートメニューの圧迫

ルートは8枠しかありません。項目はSubMenu にまとめて、ルートにはその入口を1つだけ置きます。

同期パラメータのコスト

同期は 256bit の枠を共有(Float=8bit / Bool=1bit)。サンプルは Float 4+Bool 3 で 35bit 使います。不要な項目は削って構いません。

名前の食い違い

Animator パラメータ/Expression Parameters/メニューの名前は完全一致DFI_Freeze が1文字違うだけで無反応になります。

表示切替の対象

オブジェクト非表示は 子の DeepFrostIce Spherem_IsActive を動かします。Animator が乗るルートを消すと Animator まで止まります。