メインコンテンツまでスキップ

2022-02-02 「Animation Viewer」の振り返り

注記

このページは AI(Claude)によって翻訳されています。翻訳に誤りが含まれる可能性があります。

「Animation Viewer」の開発中にいくつかの問題に遭遇したので、ここに記録しておきます。

Animation Viewer が生まれた経緯​

Animation Viewer は、私のプロジェクトである ComboGestureExpressions 2(仮称として ComboGestureDynamics とも呼んでいました)の開発中に、偶然生まれました。

アニメーションを CGE の UI にドラッグ&ドロップしやすくしたかったのですが、ドロップする前にアニメーションの内容を確認できないという問題がありました。

その時点で、Animator 上でアニメーションのプレビューを生成する仕組みはすでにありましたが、それは CGE の UI の内部でしか使われていませんでした。

そこで、Project ビュー上で直接アニメーションのプレビューを生成する方法を探し始めました。

失敗したアプローチ:RenderStaticPreview の利用​

AnimationClip 型用のカスタム Editor を作ろうとしました。

Editor を実装して RenderStaticPreview メソッドをオーバーライドすれば、マテリアルのように、アニメーションのプレビューをベイクして Project ビューに表示できると期待していました。しかし、思い通りにはいきませんでした。

RenderStaticPreview は、Inspector に表示される小さなサムネイルは更新してくれるのですが、なぜかアセット自体のサムネイルは更新されませんでした。

新しい Texture2D を返すと、アニメーションアセットが変化しなくなります。一方、AssetPreview.GetMiniTypeThumbnail が返す Texture2D を返すと、なぜか空白のアイコンになってしまいました。

さらに、原因のわからないクラッシュが何度も発生しました。

解決策を探すうちに、EditorApplication.projectWindowItemOnGUI コールバックを使う現在のアプローチにたどり着き、これでうまくいきました。この方法では、コールバックの中で項目をキューに追加します。項目が追加されると、次のフレームで、新しく割り当てたテクスチャにキュー内の項目を実際にレンダリングするタスクがスケジュールされます。

回避策:Animator が原点に移動する​

プレビューを生成するために、Animator の階層全体をコピーし、元のものを非表示にして、コピーを使って複数のアニメーションをレンダリングし、コピーを削除してから、元のものを再び表示します。

期待される結果は、コピーがその場でアニメーションすることです。しかし、理由はわかりませんが、最初のサンプリングの後に Animator がワールドの原点に移動してしまいます。Animator に RootT や RootQ のプロパティがないにもかかわらずです。

これを修正するために、コピーの位置と回転を記録しておき、サンプリングが終わった後でその位置を手動で再適用しています。

回避策:Muscle が更新されない​

アニメーションをサンプリングすると、なぜか、同じフレーム内で続けて AnimatorMode のサンプリングを行っても、Animator の Muscle が更新されません。その結果、すべてのアニメーションのサムネイルが同じ Muscle の位置になってしまい、正しくありません。

これを修正するために、試行錯誤の末、Animator の GameObject を無効にして、同じフレーム内で再び有効にすると、この問題を回避できることがわかりました。