そもそも何故VRChat Avatars3.0で表情が戻らない現象が起こるのか(およびWrite Defaultsへの呪詛)
はじめに
Write Defaultsを許すな
この記事はVRChat SDK3(Avatars3.0)製VRCアバターの表情が変えたら戻らない/表情が混ざるバグ、および物を出したら戻らない現象
はたまた左右の表情が変に混ざる現象について
UnityのAnimator Controllerの仕様から説明する記事です。
質問・指摘はhttps://twitter.com/InPlanariaまで
手っ取り早く表情バグを直したい人は以下の記事を見てください。
参考文献
Write Defaultsとは何か、何が問題なのか
まずWrite Defaultsってオフとオンどっちがいいの?
よっぽど特別な理由がない限りオフ推奨
VRChat運営もオフにしろって言ってる
でもWrite Defaultsオフを条件に発生するバグもあったりする
- GestureレイヤーのHumanoid以外のTransformアニメーションがVRC上で反映されない
→Humanoid外TransformはFXレイヤーにアニメーションを移せば一応動く - Write Defaultsがオフだとアニメーション付き椅子に座った時うまく動かない
じゃあWrite Defaultsってなんだよ
例えると「壊れた補助輪」
Unityの用意した便利機能のはずだったがVRChat環境との相性が最悪
WriteDefaultsとは本来どういう機能なのか
「デフォルトの状態」に戻すのを勝手にやってくれる存在。
上記はブレンドシェイプEye_Closeを動かすアニメーションを使い、目を閉じる表情を表示した例。
アニメーションの再生をやめ、Eye_Closeを動かすアニメーションをひとつも再生していない状態になった場合、「オブジェクトをデフォルトの状態に戻す」。これがWriteDefaults機能である。
WriteDefaultsは何が狂っているのか
一見便利そうなこの機能をなぜ使ってはいけないのか。
何かの拍子に「デフォルトの状態」を勝手に忘れやがるからである。(詳しい条件は参考文献参照)
クソWriteDefaultsに頼っているとこんなことになるので、VRC公式はWriteDefaultsを使うなとお触れを出したのである。
なぜWriteDefaultsオフだと表情が混ざるのか
しかし、今までWriteDefaultsに頼りっきりであったアバターが何も対策せずWriteDefaultsオフにした場合、あの現象が起こる。
WriteDefaultsがオフの場合、Eye_Closeを動かすアニメーションがない状態になってもオブジェクトがデフォルトに戻ることはない。
このまま、ブレンドシェイプEye_Smileを動かして笑顔の表情を表示しようとすると…
こんな風に表情が混ざり破綻するのである。
WriteDefaultsオフでも正しく動かすにはどうすればいいのか
簡単な話、「アニメーションが何も再生されていない状態」を避けるだけでいい。
Eye_Closeを100にするアニメーションを表示したあとは、Eye_Closeを0にするアニメーションを表示する。
そうするだけで、アバターの顔は元の状態に戻ることができる。
これがWriteDefaults対策でデフォルト顔のアニメーションをわざわざ作る理由である。
表情が戻らない現象だけでなく、物を出したら消えない現象にも同じことが言える。
物を出したら消えないのは、「物を出す」アニメーションだけ作って「物を消す」アニメーションがどこにもないからである。
とにかく「アニメーションで何かを動かしたら、元に戻すアニメーションもあとで再生する」それだけを意識すればいい。
「表情が戻らない現象の直し方」では何をしているのか
Animator Controllerのレイヤー処理順の仕様
冒頭で紹介した「表情が戻らない現象の直し方」。
作ったデフォルト顔のアニメーションは、一番上のレイヤーに入れることになっている。
なぜならレイヤーの処理順は上から下だからだ。
Defaultsレイヤーがデフォルトに戻すアニメーション、Left Hand レイヤーが目を閉じるアニメーションを表示している場合の動作はこんな感じである。
Left Handレイヤーがアニメーションの再生をやめた場合、Defaultsレイヤーがデフォルト顔アニメーションを再生してデフォルト状態に戻してくれる。
もしデフォルト顔を入れた一番上のレイヤーが存在しなかった場合、「何も再生しない状態」になってしまい、顔を元に戻すことはできない。
余談:左右の表情が変に混ざる原因
Left HandレイヤーでEye_Smileを100、Right HandでEye_Closeを100にしていた場合。
何も考えずに作ると、このように表情が混ざって破綻する。
左右の表情が干渉する問題の対策は様々である。
例えば上図のようにRight HandレイヤーがEye_Smileを0に上書きしてしまえば、最終結果はEye_Close=100,Eye_Smile=0となり破綻しない。
「左手は口だけ、右手は目だけを動かすと決めて干渉し合わないようにする」
「Right Handsレイヤーの一つ上に、右手表情表示中だけデフォルト顔アニメーションを出すレイヤーを置いておく」
「左右のハンドサインによる表情をひとつのレイヤーにまとめておく」
といった対策も考えられる。
表情が戻らない現象の直し方には別解もあるという話
ここまで読んだ人にはもうお分かりであろうが、デフォルトレイヤーを増やす以外にも現象への対処法はある。
「どの表情アニメーションでも、すべてのブレンドシェイプを使うようにする」ならば、どの表情を表示しても全ブレンドシェイプが動くので「戻らない現象」は回避できる。
ただし全表情アニメーションを編集しなおすのは面倒なので、デフォルト顔アニメーションを一個作るだけで済む手法がおすすめされるわけである。
少量の物の出し入れギミック程度なら、全アニメーションを修正したほうがわざわざレイヤー新設するよりスマートかもしれない。