FaceEmo 2.x 雑多メモ
記載内容の重複は気にしない
一番下にどんどん追加していく
この段階でタスクを立てていると、タスクが多すぎて後で整理できなくなる
Fistウェイトを0に戻すまでのバッファ
デフォルトでは表情遷移のdurationに合わせる
表情遷移のdurationに合わせず、独立に設定するオプションを後で追加する
オプション追加しやすいコードにする
最初からオプションにしちゃってもいいが
runtimeのndmfコンポーネントはndmfに依存しない
editor側でコンポーネントを参照する
CGEコンバーターで参照しているアセンブリ
"CGE.Runtime",
"ConvertComboGestureToFaceEmo.Runtime",
"jp.suzuryg.face-emo.components.Runtime",
"jp.suzuryg.face-emo.domain.Runtime",
"jp.suzuryg.face-emo.appmain.Editor",
"jp.suzuryg.face-emo.external.mathijs-bakker.extenject.Runtime",
"jp.suzuryg.face-emo.detail.Editor",
"jp.suzuryg.face-emo.external.neuecc.unirx.Runtime"
ライブラリ同梱時のパス長対策
リネームまではしなくていいか?
フォルダは単一にする(EditorとRuntimeのみ)
アセンブリ名にパッケージ名を入れなくてもいいかも
入っていないケース
AnimatorAsCode.V1.dll
CGE.Editor.dll
lilToon.Editor.dll
UniTask.dll
VRC.SDK3A.Editor.dll
アセンブリ名の重複さえ回避できていればいい
頭にSuzuryg.を付ければいいか?
そうすると現状と3文字しか変わらないか…
extのアセンブリ名長すぎなので短くする
UniRxとかUniTaskとか、Runtimeで使わないので全部Editorに入れちゃっていいかも?
RuntimeのコードをEditorに入れても問題ないはず
アセンブリ名にruntimeのsuffixを付けないケースが多い
例
Unity.XR.Oculus.dll
Unity.XR.Oculus.Editor.dll
Unity製のdllがこの命名なので、これに準拠していいはず
runtimeアセンブリのパス長がコンパイルエラーの原因になっている場合、この省略は有効に働くはず
逆にndmfはruntimeのみsuffixありだったりする
アセンブリ名が重複するときだけsuffixを付ける慣習な気がしてきた
アバターに付けるコンポーネントはIEditorOnlyを実装する必要があるため、VRCSDKのdllへの参照が必要
まばたきシェイプキーの表情エディタ上での扱い
リセットアニメーションをどうするかによる?
以前まばたきをリセットしていないときに不具合があったのでリセットすべき
表情再生レイヤーの上でまばたきを再生するかどうか
下で再生する場合、まばたきシェイプキーを表情に使っているとまばたきしなくなる
上で再生する場合、まばたきシェイプキーを表情に使っていると無効化される
まばたき無効チェック時、シェイプキー0で上書きするのではなく、アニメーションを再生しない方式であれば表情が無効化されない
どちらにせよ、まばたき有効な場合は上書きされてしまうので、それをどう扱うか?
結局、まばたきシェイプキーを使用しない or 警告表示が丸い
リップシンク用シェイプキーは適用時orビルド時に除外してしまうのがいい
エラーメッセージのローカリゼーションについての考え方
Domainの責務ではない?
元々のアバターの表情を無効化しきれないケース
Bodyメッシュ以外のキーがHandsLayerで変更されている
元々のアバターの2フレームアニメーションを編集して使用しているため、1フレーム目の表情が一瞬だけ再生される
インポート時は最終フレームをコピーしているため、これを使うなら問題ない
複数フレームのアニメーションの取り扱いはどうする?
アニメーションする表情を使いたいケースを考慮すると、適用時に最終フレームを抽出するのはよくない
値が変化するアニメーションの場合は警告する?
表情リセットのテスト
表情リセットレイヤーを再生しながら、FXに含まれるすべてのアニメーションを再生
表情が適切にリセットされていない場合は追加オブジェクトを設定する
アニメーションに含まれるオブジェクトを候補として表示
表情インポートの直後に表示するといいかも?
販売アバター対応
基本はManual Bakeとする
ユーザー改変の際、既存のFaceEmoレイヤーはビルド時に除去する
表情インポート
"FaceEmo/アバター名"のフォルダをunitypackageに同梱しておけばインポートできるようにする
Emoボタン押下時にFaceEmoフォルダを探索する
コンポーネントをアバターに付ける必要はない
FXから読み込めるようにするのは不可能ではないが、ちょっとしんどい
課題
保存アセットの互換性に気を使う必要がある
これは1.xでも気を使っていたので、今とあまり変わらないはず
ユーザーが追加する必要がないコンポーネントがあれば
1.xのコンポーネントはすべて非表示でいい
APIにはjetbrainsのPublicAPI属性を付けるといい
Prefab Variant運用の場合の分かりづらさ
ベースPrefabのEmoボタンかコンポーネントから起動するのが正解だが、派生PrefabのEmoボタンを押してしまいがち
ベースPrefabにFaceEmoのコンポーネントが付いている場合、そちらを使用して起動するか確認する?
対象アバターもベースのPrefabとすべきでは?
1.xでは親prefabを遡ってFaceEmoPrefabを探索するので、対象はベースじゃなくても問題ない?
最初に見つかったFaceEmoPrefabを置き換える
2.xの仕様次第ではある
逆に、ベースのprefabと派生prefabで表情設定を変えたいときに困るかも
現行の仕様だと、派生prefabからFaceEmoPrefabを削除してから適用する必要がある
ランダム時間でのまばたき
StareステートでEyelids_Stareアニメーションを再生(4秒間のループアニメーション)
Blinkステートへの遷移条件は下記の2つ
DisableBlinkがfalse(ExitTimeあり)
DisableBlinkがfalseかつBlink_Triggerが発火(ExitTimeなし)
StareステートでBlinkIntervalをランダム決定
範囲は0.2から1
LocalOnlyはfalse
ただし、ランダム値はリモートプレイヤーと同じ値にならない
StareのMultiplierがBlinkIntervalとなっているため、再生速度が0.2倍から1倍にランダム変化する
つまり、Stareの再生時間が 4/1 = 4秒から4/0.2 = 20秒の間で変化する
ジト目干渉対策
まばたきアニメーションでジト目のシェイプキーを0にする
デフォルト表情でジト目にしている場合の対策であり、表情変化時のジト目には対応しない(常に同一のまばたきアニメーションを使用するため)
AACのアセットコンテナはAnimatorControllerでいいか?
ScriptableObjectのインスタンスは作成できない(スクリプトが無いと言われる)
MAはアセットコンテナ用のクラスを定義している
表情インポートよりもFX解析と呼ぶ方が適切か?
サードパーティのライセンスはLICENCEではなくTHIRD-PIRTY-NOTICESに記載する方がいいかも
.NET系のライブラリの例
code: THIRD-PARTY-NOTICES
.NET Runtime uses third-party libraries or other resources that may be
distributed under licenses different than the .NET Runtime software.
In the event that we accidentally failed to list a required notice, please
bring it to our attention. Post an issue or email us:
dotnet@microsoft.com
The attached notices are provided for information only.
License notice for ASP.NET
-------------------------------
Copyright (c) .NET Foundation. All rights reserved.
Licensed under the Apache License, Version 2.0.
Available at
以下、その他のライセンスが続く
.NET系はすべて同じだと思ったけどだいぶ違った
リリーステスト用のプロジェクトに、開発プロジェクトのTestsフォルダのシンボリックリンクを作成する
Convertingアセンブリに、vrchatアセンブリやresoniteアセンブリを読み込ませる
startupアセンブリとは役割が違う
aacはvrcsdk存在時のみ有効
vrcsdkやma ndmfが存在しない環境に手軽にスイッチしたい
ダウンロードサイズの削減
Questの容量制限は10MB?
要出典
10MBとなるとExMenuのサムネイルの影響が大きいので、削減を考える
他のツールで圧縮とかしてない?
とはいえ、単体でも削減できた方がいい
Questビルドとの切り替え?
アセットのLocalOnly的な設定なかったっけ?
コピーしたアバターのEmoボタンを押して、設定が消えていると勘違いするケースがある
表情設定がどこに保存されているか認識しづらいのが原因かも
初回設定のウィザードを作る?
いろいろプレビューしながら進める
まばたき設定とか
ARKit等ではシェイプキーの名前が決まっているので完全一致でいけそう
複数のフェイストラッキング方式に対応しているアバターがあるかも
FTパッケージで追加されるシェイプキーはUnified Expressionsに準拠していそう
同様にMMD用シェイプキーも除外する?
MMD用シェイプキーを除外する場合、ダンスギミック対応で特別な操作をする必要がなくなる
ARKitやMMD用のシェイプキーは一箇所にまとめられていることが多いので、連続していることを検出条件とする?
シェイプキーの順序って保証されてたっけ?
顔トラのパラメータを使って分岐させる
各表情パターンに対して、FT/v2/hogeが0.5以上の時はこの顔になり、さらに顔トラでモーフさせる、というような感じ
ジェスチャーと併用する?
その場合、顔トラのパラメータとジェスチャーは排他にする?
ジェスチャーと異なり、組み合わせのパターンが膨大
それによって、複合条件の設定が難しくなる
MAは相対パスモードでいいかも
シェイプキーの左右分割
依存関係の解決は下記の方法でいいのでは?
packages.jsonのdepenciesにgitのurlを書く
リポジトリ上のパスやリリースタグを指定できる
入れるパッケージ
UniTask
R3 (Unity)
NugetForUnity
NugetForUnityでR3のコアを入れる
こうなるとAaCもvccの依存にする?
バージョンの競合をケアするか?
git urlで解決するにはgitがインストールされてないとダメだった…
現状、R3を更新するには手元でビルドする必要があるのがちょっと面倒
Actions使う?
本家の更新に追従してリリースタグを追加する
FaceEmo側からの参照の更新も自動化できるとベスト
ループアニメーションの設定ツールとして使われることがあるので、表情エディタで開いたときにうまく編集できるようにする?
顔部分をモジュール化する
Bodyの下にFaceEmoPrefabを入れる
アバター直下より分かりづらくなるのでは?
削除ボタンをメインウインドウに付ければ問題ない?
Body以外のメッシュを操作したい場合はどうする?
案1 メッシュごとに別モジュールとして扱う
案2 相対パスを登録する
案3 参照を登録する
ユーザビリティ的にはFaceEmoPrefabが複数ある状況は避けたいので、案2か案3がいいか
アニメーションのパスを相対にする
UnityっぽくないUIにするか?
ドッキングのためにEditorWindow派生にすべき
フェイストラッキング設定
有効にすると、UnifiedやARKitのシェイプキーをすべて除外する
検出されたシェイプキーのタイプを表示する
オプトアウトしてもいい
TrackingControlを無効化しない?
ジェスチャー表情側が破綻するのでは?
初期化時にウィザードを出す
何やってるか分からないよりはいいはず
スキップして推奨設定を適用できるようにするか?
フェイストラッキングのカテゴリを細分化して、有効・無効を切り替えられるようにする
うまく動かないとき用に、ビルド時にFXを全消しするオプションを追加する
テストモード?
finallyで元に戻すなら、アバターをコピーせずにプレビューした方が軽い?
NDMFのプレビューシステムに乗っかるなら関係ないか?
VRChat依存と他プラットフォーム対応についての考え方
コアからVRC依存を切り離そうとすると、PhysboneやContactに関連した機能の取り扱いがややこしくなる
他プラットフォームと同列に扱うのではなく、VRC用表情設定を他プラットフォームにエクスポートする形の方がやりやすい
VRCの表情設定のうち、他プラットフォームでも再現可能な部分だけをエクスポートする
それはそれとして、VRCSDKを参照するコードは1箇所にまとめておくと保守しやすそう
サムネイルや表情エディタの表示タイミングを0-1の正規化時間で指定できるようにする
Docusaurusやめたいかも
セキュリティアラートが多い
Hugoがよさそう?
AAOはHugo
既存表情レイヤーの無効化を最適化設定みたいなところに入れる
デフォルト有効か無効かは要検討
うまく動かないときは?みたいなUIで変更をサジェストする
ExpressionMenuからActionMenuに表記変更
「丸いメニュー」って言った方がいいかも?
公式名称はあるけど、公式も呼び方がフワっとしてる
ActionMenu -> ExpressionMenuの階層で、実際にメニューが追加されるのはExpressionMenuなので今のままでもいいかもしれない
それはそれとして、FaceEmoの場合は「表情メニュー」と同じ意味になってしまうので適切に呼び分けたい
Input2.0でジェスチャー以外の表情操作ができたりしないか?
ExParamの変更(ローカル含む)をコントローラにバインドできるかどうか
良さげなアクションは無さそうだった…
というかそもそも定義済みパラメータで使えそうなのがジェスチャーぐらいしかない
そろそろ表情専用のパラメータとアクション用意しませんか…?
仮にハンドトラッキングによる手の形とGestureLeft/Rightを分離できたとしたら、gesture_direct_fist_leftをどこかのボタンにバインドして表情変更に使える?
望み薄ではある
理想:バインドされたアクションによってイベントが発生し、それをアバター側で購読できる
なるべくサブアセットを作らずに保存したい
どういう条件でサブアセットになるんだっけ?
Unity2022はC#9.0なのでrecordが使える
IsExternalInitが必要?
Initアクセサを使うために必要
VRCSDKのバリデーションエラーが見づらすぎるのでなんとかしたい
スクショ見ても大抵必要な情報まで辿り着いていない
なんかフックできないか?
docusaurusの言語自動選択
MAの場合はこれでいける
なにか設定が必要?
複数フレームのアニメーションへの対応
現状、編集せずにセットすることは可能
ここから編集すると1フレームになる
複数フレームの編集に対応する場合の仕様は?
VEEを参考にする?
シンプルなのは、編集対象のフレーム番号を指定するもの
アニメーションの再生がほしいかもしれない
ドキュメントのPRを出しやすくする
環境構築の手順を書くだけでいいか?
バイパス時とオーバーライド時のTrackingControlをオプション設定に出す
需要の高いオプション設定をアクセスしやすい場所に配置し、そうでない設定をアクセスしづらい場所に配置する
日本語パス検出時のメッセージをInfoではなくErrorにする
エラーだけ見ている場合は目が行かない
どうせVRCSDKのGUIがずっとエラー出してるので、FaceEmoが常にエラー1つ出しててもそこまで気にならなそう
ビルドエラー時のメッセージも添えると分かりやすそう
ビルド時にシーンの状態とリセットアニメーションを比較
差分がなければそのままビルド
差分がある場合
再生成に時間がかかる → 確認してから再生成
再生成に時間がかからない → 確認せずに再生成
dllで配布する?
利点
コンパイルの時間をカットできる
欠点
ユーザーが手元で修正できない
外部パッケージにテストが存在する場合、それをシンボリックリンクで持ってくる
asmdefだけ自前で作る
トラブルシューティング用のウィザード
「うまく動かないときは?」ボタンを目立つ場所に設置
ありそうなトラブルを列挙
各トラブルに対応するオプションを表示する
例
アバターギミックが動かない
表情レイヤー無効化
Contact設定
Physbone設定
アバター組み込みの表情メニューが動かない
表情オーバーライド追加
フェイストラッキングで顔を作った後で固定する
撮影用
Contactでバイパスを設定していると、「頭に手を当てたときになぜかFaceEmoが無効化される」という解釈になる
FAQで吸収する?
やっぱり元々の表情レイヤーを消したい
例外クラス
基底クラス (FaceEmoException) を定義
多言語対応のための機能を追加する
具象は別のレイヤーに置く?
必要に応じて派生クラスを作る
FaceEmo_EmoteOverrideExampleのWriteDefaults設定についてのオプションがない
アバターギミックがWD ON前提だと動かなくなる
デフォルトでWD統一ONにするだけでいいかも?
メニュー編集はFuryのtoggleを参考にする
R3の依存ライブラリのうち、下記のdllはasmdefの参照に入れる必要がなさそう
Annotations
Channels
Unsafe
R3.dllからは参照されているので、これらを消すとR3.dllがロードできなくなる
上記以外のdllはR3LearningTestsでasmdefに追加している
NugetでR3がインストールされている環境にFaceEmoをインストールして、R3LearningTestsが通ることを確認した
Runtimeアセンブリが多すぎるとアバタービルドでコケる問題、managed dllは関係なさそう?
AAOを追加したらコケる状態にしてからAAOを削除し、R3関係のdll(8つ)を追加してもコケなかった
また、jp.suzuryg.face-emo.ndmf.RuntimeをRuntimeに戻したらコケる状態にして、R3関係のdll(8つ)をjp.suzuryg.face-emo.domain.Runtimeの参照に追加してもコケなかった
Unsafeを削除するとR3.dllでエラーが出たので、dllは無視されていない
devブランチを消してmain一本にする
リリース状態の管理はタグで十分
バグ修正時はhotfixを作る
未完成状態の機能をmainにマージしない
そうする場合は機能ごとのdevブランチを作る
featureよりも大きい単位のブランチが必要な場合
2.xリリース前には顔トラを一時的にやめて実運用テストをしておく
コンタクト設定デフォルト有効にしない方がいいかも
「オリジナルの表情が無効になってない」は大体これ説
「元々のアバターギミックを維持する」設定を一括ON・OFFするスイッチを目立つ場所に作る?
最初にウィザードで設定させる?
「ギミック互換設定」でウインドウを1つ作る?
fxからギミックを検出して個別ON・OFFする
ダンスもここでいいかも
MAにDBT用のコンポーネントがある?
表情パーツON・OFFはこれを使ったほうがいいかも
デフォルト表情 → 顔つき設定
「FaceEmoを使うと顔が破綻する」ケース
おそらくアバター側の口変形キャンセルをインポートできていない
fxをパースするのは無理
規格化されてなさすぎる
ウィザードで口変形キャンセルを設定する?
プレビュー付き
顔の下半分だけを表示すれば、目元などの破綻を気にしなくていい
万全を期するなら各visemeだけ100の状態と、全表情合成+viseme100の状態を比較する
口変形キャンセル用アニメーションっぽいものを複数検出し、ユーザーに選択させる?
遷移条件から絞り込めそう
表情リセットのシェイプキーをサジェストしてしまった場合、喋ると表情が動かない!となるので注意
独自リップシンク対応は口変形キャンセル対応とセットになることが多い
独自リップシンクで使われているシェイプキーがdescripterに登録されていない場合は口が全く動かなくなる
登録されている場合、口の動き自体は阻害されない
現行のvrcの仕様では、アニメーションで一度でも動かした時点で標準リップシンクが停止する
シールドでアニメーションがブロックされている場合の挙動は?
標準リップシンクが使われそう
このケースに対応するため、登録ありのアバターが多数派なのでは?
独自リップシンクの場合、tracking controlが常にmouth無効かもしれない
これは一律にコンポーネント削除で対処できる
独自リップシンクの場合、同じレイヤーで口変形キャンセルを行っている可能性が高い
破綻と言われているケースはこれが大半では?
0シェイプキーの一括追加時に警告
顔つきの変更が反映されなくなる
0シェイプキーを非表示にした場合、顔つきの変更が反映されない原因が分かりづらくなる
オプション消す?
顔つきにシーン状態を反映するかどうかをオプションにする?
「反映しない」を使うことがなさそう
使うことはあるけど、オプションの存在が混乱を招く
コンポーネントで完結させる
シーン不要にできるといい
シーンオブジェクトの参照を保持できなくなるので、パスでアクセスする
ビルド前にprefabを生成しない
fxの生成を毎回やると時間がかかる
変更があった場合のみ再生成?
変更フラグの取り扱いに注意
他のツールで参考になるものがあるか?
あんまり大規模なレイヤーを生成しているものがない?
とりあえずパフォーマンスを見てみる
importerのPR作りやすいようにしたらPR飛んできたりしないかな…
個別対応が大変なので
importerの作り方をマニュアルに書く?
特定アバター用のimporterを作ったとして、そのアバターかどうかの判定が必要になる
個別対応が多くなると、importer同士の整合性をとるのが大変になるかもしれない
個別のimporterを用意せず、setup outfitのように対応ケースを増やしていく方が妥当
デグレを防ぐためにテストを充実させる必要がある
CIのために、市販アバターをprivate領域にアップロードできたりする?
アバター購入数がそんなに多くないので、コストやリスクとリターンが見合わない
テスト時はAnimatorcontrollerをコードで生成するのが良さそう
テストケースを増やすたびにアセットを用意するのは大変
最後のテストは実運用と同じ環境でやるとして、そこで見つかった見落としを自動テストに順次反映させていけばいい
ライブラリの警告を気にしないなら、Unityのプロジェクト設定でnullableを有効にしていい
Riderで各コードに正しく警告が出てくれればいい
コンパイル後の警告は気にしないようにする
どうせnullable無効でも他のライブラリで色々出てるし
UnityEngine.Objectでnull合体演算子を使うと警告を出してくれる
Unityでは「PlayerSettings > Player」にある「Additional Compiler Arguments」で-nullable:enableを追加します。
AAOの一部のcsprojでLangVersionが7.3になっており、エラーが出る
これはAAO内にあるcsc.rspで7.3が指定されているため
経緯
Unity2022で開発していくにあたり、Unity2019で使えない機能を使ってしまわないための制限
1.8.xではUnity2019を切るので、この制限がなくなる
それだけでなく、C#10を使うらしい
structのデフォルト値使いたいな…
このPRを見ておきたい
Unityバージョン分岐をやめる
JetBrains Annotationsをやめる
開発環境でのみnullableをエラーにする
これはUnityのプロジェクト設定でもいい?
他ライブラリのコードで結構警告出るからダメ
最終的にEditor/csc.rspはやめてる
Utilsはソースコード内でnullable enableしている
なぜ?
最終的にこの方式はやめてる
すべてのアセンブリに.csc.rsp.nullsafeを適用
これを各アセンブリのcsc.rspで参照していたりする
APIInternalはソースコード内でnullable enableしている
Unity依存だから?
これ以降ソースコード単位で有効化するコミットが出てくるので、たぶんそう
HashCode structを使う
これいつから使えるやつ?
結局どうする?
一律にnullable enableしてしまって、エラーではなく警告にするのが楽ではある
Riderで見て判断できればいい、という運用
プロジェクト全体をgitで管理しない場合、このやり方だとnullableについての設定がリポジトリに残らないのが不安
厳格な運用もちょっと興味はある
それはそれとして、C#10は使いたい
csc.rspについて調べる
同一のFaceメッシュを対象とした設定ファイルが存在する場合、インポートを提案する
ioの効率化
uiからは書き込みを予約するだけで待機しない
一定間隔で最新の値を非同期で書き出す
読み込みはキャッシュを返す
Unityのシリアライズに乗っかるのでundoもできる
とりあえずプレビューウインドウは正面を映すだけの状態でモックを作る
UI要素は1.xをそのまま使い回して、後で整理していくのもアリ
ロジックを分離して描画のみ使い回す
ビルド時に顔つきが変化していたら警告
表情が破綻している可能性があるため
警告解除の条件は?
FaceEmoのウインドウを開くこと?
Fxのキャッシュ
ビルド時にキャッシュが存在すればそれを使う
Fxが変化するような操作をした場合、キャッシュを削除する
キメラ用のワークフローは今と違うものにしたい
わからん集会16回のフロー
顔のアバターでFaceEmoを適用
FaceEmoPrefabを生成
顔のアバターのAvatarDescriptorを削除
顔のアバターを体のアバターに入れる
体のアバターのAvatarDescriptorで顔メッシュの設定をする
FaceEmoPrefabを相対パスにしてルートを顔のアバターにする
顔アバターの顔メッシュが体アバターの直下にないため、AnimationClipのパスを変換する
このフローになっているのは、こうしないとパスを変換できないため
FaceEmo設定の対象アバター変更だと、元アバターの表情アニメーションで直下以外の顔メッシュを対象にできない
元アバターの表情を流用しない場合は、別にこのフローじゃなくてもいい
AvatarDescriptorから顔メッシュを参照できるので
顔パーツをモジュールにする需要
顔をどこに入れてもパスが正しく変換される
コンポーネントの場所は顔メッシュでなくてもいい?
パスの起点をどこにするか
設定アセットを使い回す場合、起点が定まらないのはしんどい
AvatarDescriptorを起点にすると決まっていれば楽
基本的に、アバターのアニメーションはアバタールートのAnimatorで再生されるので、アバタールートのをパスの起点にしている
基本的に、コンポーネントはアバタールートに付けるようにしたい
そしてアバター直下に相対パスでprefabを生成する
顔メッシュのパスはアバタールートからの相対パスで持っておいて、見つからない場合はエラーを出す
追加メッシュは別扱いにする
設定を使い回した場合、追加メッシュがないアバターもありそう
顔メッシュだけは必須とする
顔メッシュでリップシンクとまばたきが設定されている前提
顔をモジュール化する場合、AvatarDescriptorがない状態で動けるようにする必要がある
そうした場合、多くのコードをvrcsdk非依存にできる
「アバターに適用」のステップを省く場合はコンポーネントを起点にする必要がある?
ndmfに乗っかる上で一番自然なのはコンポーネントベースにすること
従来
emoボタンがAvatarDescriptorごとに表示される
emoボタン押下
descriptorが一致する設定をシーンから検索
descriptorを基準にして顔メッシュやfxを取得
リップシンク、まばたき、fxの取得のためdescriptorは欲しい
逆に言えば、それらの設定を取得できたらAvatarDescriptorは不要?
AvatarDescriptorの設定変更に対応しないならばそう
アバター内に複数のFaceEmoコンポーネントがある場合はどうする?
安全なのはエラーにすること
エラー表示からコンポーネントに飛べるようにする
中央集権的な管理なので、マージは難しい?
表情パターンを足すだけならいけるか
オプションのコンフリクト解決が厳しい
上記の顔モジュール仕様に準拠するなら、FaceEmoPrefabが複数生成されることになる
というか動的生成ならprefabじゃなくていいので名前を変える
リセットアニメーションの都合上、最後にマージされたFaceEmo設定以外は無視される
バイパス設定についてはこの限りではない
やっぱり複数は許容しない方が丸い
新しい仕様
emoボタンがAvatarDescriptorごとに表示される
emoボタン押下
アバター内のFaceEmoコンポーネントを検索
ある場合は起動
複数ある場合はエラーを出して削除を促す
無効化でもいい?
ない場合はアバタールートにアタッチ
AvatarDescriptorから設定を取得
顔メッシュ
リップシンク
まばたき
fx
fxの中身を見る
fx自体の参照は保持しない
起動
AvatarDescriptorから取得した設定が正しければ、あとはvrc非依存で編集できる?
contactとかpbを参照する場合は必要
ただ、AvatarDescriptorを参照する必要はない
起動時にAvatarDescriptorを参照して、設定が変わっていれば更新したい
顔メッシュは更新しない
顔メッシュが一致している場合のみ、他の設定を更新する
MAベースでやる場合は、デバッグ用にMAprefabを静的に生成するモードを付ける
動的生成を切る
従来、ヒエラルキー内の順序でレイヤー順を制御していた場合、それを再現できるか
FaceEmoのレイヤーが最初に再生されていれば大抵は問題ないのでは?
従来のFaceEmoPrefabを削除した場合は警告を出す
ない状態を正としたい
どこから作る?
モックの作りやすさで考える
早めに全体像を把握したい
順序
ドメイン作る
詳細実装のモックを作る
UIのモックを作る
1.xを使い回せるところは使い回す
PBやContactの値のうち、必要な部分だけを切り出してDomainに入れる
表情設定にメニュー階層の概念を入れるか?
表情パターンを階層管理したいかどうか
自分はしたい
表情パターン自体がフォルダみたいなものと捉えられる
表情パターンのフォルダ分けが存在しても、階層プリセットや階層カスタマイズの妨げにはならなさそう
どっちみち、表情固定を表情パターンでフォルダ分けするなら、表情パターンのフォルダ分けがあっても大差ない
仕様は後で詰めるとして、とりあえず表情パターンの階層はアリで進めていい
階層プリセット
プリセットA(表情パターン切り替えをよく使う)
ルート
パターン1
表情固定
パターン1
表情1
プリセットB(表情固定をよく使う)
ルート
パターン1
表情1
パターン切り替え
パターン1
プリセットC(表情のフォルダ分けも不要)
ルート
表情1
パターン切り替え
パターン1
階層カスタマイズ
現時点での階層プリセットをもとに、階層を自由にカスタマイズできる
カスタマイズを有効にするとプリセットによるメニューは作成されず、カスタマイズ後のものに置き換えられる
フォルダを自由に作成できる
既存の項目を自由に配置できる
すべての表情パターンと表情に固有のIDが振られている必要がある
フォルダはID不要(コピーすればいい)
元のフォルダ名や表情パターン名を変更したケースへの対応を考えると、そもそもフォルダ単位でのコピーは不可にすべきかも
階層カスタマイズは静的であり、階層プリセットの変更が自動的に反映されない
任意に「未整理」フォルダを追加できる
カスタマイズ後のメニューに存在しない項目がすべて詰め込まれる
「未整理」が無効であり、かつ、未追加の項目が存在する場合はビルド時に警告する
その他、階層についての機能の候補
お気に入り表情
ONにすると表情固定メニューの直下にその表情が来る
ショートカット
固定ON・OFFのショートカットをどこかに作る
Contact固定を使わない場合は欲しいかも
設定階層
FaceEmoteProfile
表情メニュー
各種Settings
各種Setting
プリセット設定はパターン追加のパネルに移動
デフォルトは右優先
選択はEditorPrefsに保存
ツリーは起動のたびに全展開する
表情パターン単位・フォルダ単位で有効・無効を設定する
項目数の上限もないので、「アーカイブ」が不要になる
Fist前後表情設定のメリデメ
メリット
表現の幅が広がる
Fist前の設定がない場合、デフォルトの顔つきからの遷移しかなくなる
デメリット
設定が煩雑
理解しづらい
自動合成の仕様が難しい
そうでもないか?
Fist前表情がない場合、もう片方の表情から徐々に合成表情に遷移していく
Fist前表情がある場合、Fist前表情との合成から、Fist後表情との合成に遷移していく
プレビューがめんどい
Fist前表情がない場合、合成前は破綻していないことが確定している
今の仕様で移植しながら仕様検討していく
Tests以下を無視していると、Rider上で緑色で表示されるのがちょっと嫌
別のやり方にするか?
今のやり方はMAの真似
AAOも同様に"Test~" になっているが、シンボリックリンクの生成や.gitignoreへの記述が見当たらないので、実行の仕方は違いそう
ライセンスファイルの整理
THIRD-PARTY-LICENSES.mdに列挙する
どれを対象にする?
リポジトリ内のものをすべて書くのが無難
リポジトリのライセンス表記も兼ねるため
公開リポジトリでなければ別
配布zipに入っていないものを記載していても、MITやCC0なら特に問題ないはず
MAはリポジトリ内にコードやバイナリを置いていないので削除してもいい
メニューの名称
日本語: リングメニュー
英語: Radial Menu
ドキュメントでは正式名称についても言及しておくといい
本ツールでは「リングメニュー」と呼びます
FaceEmo Simpleコンポーネント
表情アニメーションの差し替えだけを行う
通常設定との共有を考えると色々ややこしい
とはいえ、モード切り替え式にすると「設定が消えた!」になる
別ツール…?
どちらにせよマイグレーションからは逃れられない
FaceEmoteProfileにSimpleモードの設定を内包する?
通常モードで使わないデータをここに格納するのは違和感がある
一方、アセットが分かれていると管理が煩雑になりそう
差し替えはFX依存なので、FX非依存のprofileに内包すると複数アバターで設定を共有するときに困るのでは?
そう考えると別ツールの方が自然
別ツールにするとR3の依存アセンブリ作らないといけなくなるな…
表情エディタは共有したい
通常コンポーネントとSimpleコンポーネントが両方存在する場合、通常コンポーネントの設定が優先されることをどこかに書いておけばよさそう
リセットレイヤーがマージされると、差し替え有無にかかわらず上書きされる
両手がFistの場合のみ2d blendtreeを使うようにすれば、interruption sourceを使わなくても良くなる
1.xではステートが分かれていると表情固定ができなくなるため、同じステートに入れている
表情選択はなんとかなるが、固定ON・OFFが厳しい
表情選択もダメでは?
2dの表情に固定して片手fistにする場合
トリガーを無効にして、トリガー前後の表情に固定するのはOK
自由度を下げて安全を取るなら、両手Fistの単一セル条件以外では左右トリガーの同時enableを禁止する
ちょっと違和感がある
CGEのスムージング仕様に戻す場合、2d blendtreeのステートで片手fistの場合にウェイトが戻らなくなる
レアケースではある
表情固定がなければステートを分けて解決できる
FistのスムージングをDBTで組んでステート遷移を無くせないか?
OSCmoothはDBTだったような
VContainerSettingsのMenuItemの影響について
ユーザー(エディタ拡張の開発者等を想定)の環境とFaceEmoのVContainterのバージョンが異なり、かつ、MenuItemにFaceEmoのVContainerが登録されている場合、ユーザー環境と異なるバージョンのVContainerでCreateAsset()が実行されてしまう
しかし、CreateAsset()はアセットを初期化してPreloadAssetsに登録するだけのメソッドであり、VContainerSettingsの編集はユーザー環境のVContainerで行われるため、ほぼ問題にならないはず
足りないフィールドは追加され、余分なフィールドは削除される?
FaceEmoteProfileVariant
設定の一部だけを差し替え
顔つき変更反映の障害をなくす
シーンと同値のシェイプキー非表示オプションを削除
代わりに、シーンと同値の場合は灰色で表示する
シーン不要のワークフローにする場合、「シーン」という言葉は使わない方がよさそう
「顔つき」でよさそう
シーンと同値のシェイプキーを一括追加するボタンに (Not Recommended) と表示し、確認ダイアログを追加
シーンと同値のシェイプキーを一括削除するボタンを追加
表情ごとではなく、すべての表情に対して実行するボタンがあってもいい
FaceEmo起動時はアバターに付けたコンポーネントを起点にする?
その場合、VContainerのContainerBuilderにMonobehaviourを登録する必要があるか?
FaceEmo起動時にresolveする?
その場合、インスペクタの描画にはコンテナを使いたくない
スクリプトのロード時にresolveする?
ロード時点で依存関係をすべて解決できるなら、これが良さそう
できないとしても、それらは子スコープに回したい
resolveに時間がかかるなら、スクリプトのロード時に行うのではなくFaceEmo起動時に行ってキャッシュしておく
コンポーネントは登録するのではなく、ファクトリの引数として渡した方がいいかも
package-bundlerで階層を除外するときはPath()で囲むのを忘れないこと
配布zipに含まれないOSSのライセンスを分離する
ファイル名どうする?
メニューの追加先をコンポーネントに保存する
その他、アバター依存の設定(派生アバター毎に変わりうる設定)はコンポーネントに保存する
DefaultFaceレイヤーで表情パターン毎に分岐されるようにすれば、ビルド時にアニメーションを合成せずに済む
サムネイルの生成は必要だが…
高速化したい
Moq必要かも
テスト用のライブラリ、リポジトリに入れなくてもいい?
CIで使いたいから入れたい
cloneした人が使えるようにしたい
パッケージのリポジトリにどこまでUnityプロジェクトの中身を入れるか
普通にDLL同梱でいいか
csc.rspを新しく配置しても設定が反映されない場合、Library/Beeを削除してUnityを再起動すると反映される
ScriptAssembliesの削除では反映されない
これ、ユーザーにLibraryを削除してもらうのは若干やりたくないな…
開発者的にはLibrary爆破はポピュラーだが、非開発者には未知の存在
一応FAQには書いておく
nullableのエラーはwarn as errorを消して対処できるが、struct record等はエラーが出る
package.jsonのemailとか消す?
他のツールのpackage.jsonを見る
unityの機能を使わずにyamlを直接生成した方が速い?
すぐ互換性なくなりそう
互換性を考慮しなくてもいいアセットはunityの機能を使わなくてもいいかも
表情設定の保存アセットとか
いやundoしたいな…
表情セットの削除とか
非同期でやればUIは止まらないはず
asmdefの名前からパッケージ名を消してもいいのでは?
アセンブリ名と一致していなくてもいい
GUID参照じゃない場合ってファイル名参照だっけ?
別にasmdefのパスが最長になることはないか…
最長になったら考える
1.xの実装はデメテルの法則に反している?
一応IDで参照してるな…
表情プロファイルを集約ルートとする
表情パターンと表情はエンティティとして、IDで管理する
IDは表情パターンと表情で別個に定義する
集約ルートから下記を取得できるようにする
表情パターンのIDのリスト
IDに対応した表情パターンのメタデータ
表情のIDを含む
IDに対応した表情のメタデータ
プロファイルを1つの集約にする必要はないか?
集約の肥大化を避ける
1つのアセットを1つの集約とする必要はない
アセットのクラスはDomain層では定義しない
インポート・エクスポートはどうするか?
App層に定義する、Domain層は関与しない
技術的な関心事はビジネスロジックではない?
いや、表情設定に対しての操作でオプションを参照することがあるから、同じ集約にあるべきだな…
設定を参照するのは適用のときでは?
追加表情オブジェクトは表情エディタで参照する
集約の内部は、ルートエンティティ以外は「値オブジェクト」だけであることが望ましいとされています。IDDD本の中で紹介されているプロジェクトでは、7割の集約はルートエンティティに値オブジェクトのプロパティを数個持たせるだけに抑えることができ、残り3割も2つか3つのエンティティを使用しただけとの報告があります。どうしても、ユースケース的に大きな集約を作らなければいけない場合は、結果整合性にて遅延を許容できないか検討してみるといいでしょう。
うーん、結果整合性…
スタンドアロンでは別に苦労しない?
アバターへの適用ってビジネスロジック?
FXの詳細はInfra
「どのような挙動にするか」はDomainに書ける?
これも難しいか
他プラットフォーム適用まで見ると、詳細は持ちたくない
プロファイルはパターンの順序だけを管理し、別集約とする
パターンと表情の関係も同様
Domain.Menu
Motion
Emote
EmoteSet
EmoteSetFolder
EmoteMenu
FaceEmoteProfile
HierarchyEditor
集約が別なら、EmoteMenuではなくIEmote(Menu)Repositoryの方が自然
その場合、Getのたびにデシリアライズするのではなく内部でキャッシュしておく
Repositoryは参照をそのまま返す?コピーを返す?
コピーにすべき
Repositoryにビジネスルールを置かないために、EmoteMenuが各エンティティのrepositoryを持つ形にする?
リポジトリを持つのはエンティティではなくドメインサービス
Emoteの更新・削除通知はどの層に書く?
どうしてもViewは複数になる
1.xで親の参照が必要だった理由は?
いくつかある
親がRegistered, Unregistered, Groupのいずれかによって処理を分岐するため
親の容量が一杯である場合に追加ボタンを無効にする
今回はフォルダ単位での制限を導入しないため不要
表情セットをコピーするとき、親に空きがあるか確認する
今回はフォルダ単位での制限を導入しないため不要
表情セットをコピーするとき、親の末尾に追加する
View側で親も指定してリクエストできるようにする?
表示中の階層は分かるはず
移動とコピーが同じような実装になる
ツリー表示中、追加ボタンが押されたとき親に新しくアイテムを追加する
View側で親要素が保持するIDを取得できるようにすればいい
他のView要素で表情セットが選択されたとき、中央列でその親の中身を表示する
選択状態の管理はViewの責務
必要であれば、Viewのクラスでは親の参照を入れる
表情セットを削除したとき、削除前の親の要素リストを取得して直近の要素をViewで選択する
Viewで完結できそう
いや普通に双方向の参照でいいか
整合性さえ保証できるなら問題ないはず
GUIDは大きすぎない?
最大の要素数を考慮するとGUIDでなくてもいいはず
表情の個数制限を入れる?
UIに警告は出したい
ルート階層に必ず表情セットが必要なルールとする?
デフォルトの表情セットをどのように決定するか
クラスの公開範囲どうする?
公開する意味があるもの以外はinternal
外部ツールから参照されることにより、互換性の問題が生じることを防ぐ
DomainとPresentation (Presenter, View) で同名クラスを定義
ToDomain(), ToPresenter()で変換
ViewにEmoteSetやEmoteのIDを持たせる
package.jsonのzipSHA256プロパティについて
MAのワークフローを見ていたらzipのハッシュ計算が追加されていることに気付く
ここで追加された
vpm-repo-list-generatorと連動してる
The optional zipSHA256 property is used to verify the integrity of the zip file you provide. The checksum should be added to the manifest of the repository listing, not in the package's package.json. Currently, the zipSHA256 property is only used for cache invalidation. But we might start enforcing hash checks in the future to ensure the integrity of the packages the users download.
このプロパティがあるとキャッシュが無効化される
将来的に必須化するともとれる書き方
過去のパッケージが使えなくなるし、警告が出る程度なのでは?
一旦様子見でいいか…
liltoonは過去バージョンにハッシュを追加して対応
クラス名の短縮は最後に検討する
動作確認込み
シェイプキーの値が100より大きくならない原因がFaceEmoだと思われていることがある
VRCの仕様である旨どこかに書いておく
仕様が変わった場合はツッコミが来るはず
ユビキタス言語の変更
表情メニュー →
表情パターン → 表情セット
Expression Menu → リングメニュー
unityのアニメーション機能のうち、FaceEmoで扱う部分だけを抽出してdomainに再定義する
blendshape
transform
isenabled
フレーム
プレビュー表示
サムネイル生成にも使う
アバターを抽象化したときの要件
アニメーションできる
つまりUnity的にはAnimatorが付いているGameObject
具象をinfraで実装する場合はGameObjectを要求しなくてもいい
GameObjectを特定可能な識別子は?
アセットでない場合はguidがない
パスかな…
保存する必要がなければIAvatarにしてプレビューを受け入れ可能にすればいい
アバタービルド関係の処理はほぼ具象で実装
ただし、アセットに保存する必要があるものはdomainで持っておく
AnimationModeでプレビューしない場合、アニメーションのパスではなくblendshapeやtransformで取り扱う必要がある
どのフレームをサムネイルにするか指定する場合、メニューもアニメーションの知識を持っている必要がある?
domain内の名前空間はあとで整理する
まずはエイヤで決める
FaceEmoのコードを使い回す場合はsubmoduleにする
アセンブリは別のものにする
FaceEmoのバージョンに依存するのを避ける
profileはdomainで定義しない
リポジトリの具象クラスがprofileから各エンティティを読み込む
可能なら編集中に裏でfxの生成を回せるといい
メインスレッドのリソースを食うからやめた方がいいか
TODO
双方向参照に変更
ルートのIDどうする?
IDをuintに変更
stash popする
未使用IDの取得どうする?
EmoteSetとEmoteSetGroupのリポジトリは別でいいのか?
IDが共通なので、同じリポジトリの方がいいのでは?