「SVGでアニメーションさせたいんじゃ」の詳細報告

<font color="Blue">※ニコニコのユーザーブロマガサービス終了に合わせて、移動＆編集した記事です。
元記事(2019-03-06)
https://ch.nicovideo.jp/FlyingEchidna/blomaga/ar1708679
</font>

放送でも取り上げてたけども…

【過去放送】2019/03/02 雑談「SVGでアニメーションさせたいんじゃ」
https://www.nicovideo.jp/watch/sm34717013

放送内では語り切れないことについてクッソだらだら書いていくぅ～↑


安売りしてたとかでおとんが買ってくれた
Moho Pro12 と Poser Pro 11
のうち、今回使ったのはMohoだけ。

Poserの方は自作で3Dモデルを作る技術もツールもないので、いまいち使い道が思いつかないnow。
デッサン人形代わりにはなるかもね？ぐらい。
大量にプリセットがあるけども、リアルテイストすぎて上手く使いこなせる気がしない（白目）


##Mohoに対するマニアックな感想

Mohoの方は2Dだから無茶ができる感。
ラスタ形式でもベクタ形式でも読み込めるし、ボーンを入れられるし、アニメーションを付けられるので、大体でOKができてありがたい。
フォトショ（psd）もイラレ（ai）もそのまま読み込める。
が、イラレはバージョン8までの形式しか対応してないらしく、CC2019を使っていようが、保存時にわざわざバージョンを落とさないといけない。
まあaiを読み込めるだけマシ？

Moho側で完結して作る場合はベクタ形式だから、パスの扱いに慣れてない人はキツいだろうけど、逆に言えばベクタ形式系の編集機能は付いてるわけで。
読み込んだデータも含め、パスの線の太さ・角度・塗りあたりもその場で編集＆アニメーションできるし、フレーム間で勝手にモーフィングしてくれる。
ただ、アンカーポイントの数の変更には弱く、途中で変形させるために無駄にアンカーポイントを増やす羽目になったり…
その辺も含め、AEのシェイプ機能みたいなもんなわけで。
シェイプ乱用に定評があるオレ歓喜。


Moho上でのアニメーションの概念についてだけども。
描画ツール系でよくあるレイヤーと、AEのコンポジション・キーフレームの概念にプラスして、ボーンを使って制御する感じ。
理解できるまでクソややこしかったけども、分かってしまえばクソ便利だなぁという印象。

表示時の重なり順はレイヤーパネル上の順になる…まあ描画ツールではよくある話で。
途中でレイヤーの表示順序を変更するようなアニメーションは、上位のグループ（フォルダ）のオプションで設定すればできるようになる。
AEだったら同じコンポのレイヤーを重ねて、切り替えたいタイミングでインポイントとアウトポイントを…
ってやるところを、アニメーションの再生途中でマジでレイヤー入れ替えちゃうあたり、かなり強引。
意図せず編集途中でレイヤーを増やしたり移動させたりすると、既存のレイヤー順序アニメーション設定がご乱心なさるのでマジ注意。

で、このレイヤーはAEで言うところのフッテージ…かと思いきや、コンポ的な扱いらしい。
つまり、レイヤーを増やせば増やすほどコンポが増えるようなもので、グループレイヤーは中に入れてるレイヤーのプリコンポみたいな感じ。
レイヤーの各々にタイムラインが存在し、各々にアニメーションの設定を入れる。
グループに移動・回転アニメーションを設定すると、中のレイヤーのアニメーションも再生しつつ、一括で移動・回転する。

単なるグループもあれば、機能を持ったグループっぽいものがあって…
特にMoho的に一番重要であろう『ボーンレイヤー』は、中のレイヤーに対してボーンを入れてグリグリ動かせる。
単純にボーンに追従させて動かすこともできるし、メッシュワープみたいな感じでグニグニ変形させながら動かすこともできる。
今回は使ってないけど『フレームバイフレームレイヤー』なら中のレイヤーをパラパラ漫画形式で再生、『スイッチレイヤー』なら口パクや目パチのような差分レイヤーとして管理＆切り替えられるようになる。
ラスタ形式だったらクソお世話になりそう。
ボーンの中にフレームバイフレームやスイッチを入れ子にすることも可能。
マスクの設定を入れることも可能。今回は目を顔でマスクしてるけど…作業画面では分からないね。動画出力時には反映される。
あとは使ってないけど、乗算やスクリーンのようなブレンドモードもある。
大体のことできるやん…


あと、めっちゃAE用語で喋っちゃうけど…
全コンポ（レイヤー）のタイムラインのインポイントは一律同時。つまり全部同時再生状態。
だからこのままだと再生開始タイミングの調整ができない。
特定アニメーションを含んだコンポを、インポイントをずらして設置して、再生速度はタイムリマップ入れて微調整！
…ってことは、できないofできない。

その代わりに使うのが『アクション』＆『スマートボーン』。
個人的にはこの機能が一番ヤベェと思っている。
アクションごとのタイムラインは孤立していて、アクション各々にコンポのアニメーション設定ができる感じ。
作ったアクションを別のアクションにそのまま読み込ませて再生させることも可能。
さらに、このアクションにスマートボーンを紐づける、ということも可能。
スマートボーンは、回転角度＝紐づけたアクションのタイムラインの再生位置、で…
別のアクションの中のスマートボーンを回転させると、紐づけたアクションを再生してくれる。
タイムリマップよりも断然直感的。つおい。

じゃあ、同じレイヤーに対してアニメーションを入れたアクション2つを、スマートボーンを使って再生したらどうなるのか。
なんとまあ、イイ感じにアニメーションをマージしてくれる。
今回だと、歩きのアクション中に、瞳の動き、瞬き、首振りのアクションのスマートボーンを操作してみてる。
歩きには体の揺れとかも入ってるけど、その辺も含めて全部マージされる。
立体っぽい動きもこれで表現できる。
なんやこれ…動作差分作り放題やないか…


あとはキーフレームだけども、ここについてはAEほどの自由度はない印象。
補間方法として、スムーズ、リニア、イーズイン、イーズアウトとかは設定できるけど、AEみたいにグラフエディターで速度を調整、みたいなことはできなさげ。
数値直打ちでの微調整もできないし、エクスプレッションも当然ない。
とはいえ、ループの設定は一応キーフレームに対してできて、次のキーフレームがくるまで指定した範囲のキーフレームをループ再生してくれる。
ただ、ループした瞬間の補間が効かない（そもそも補間とループの設定が同列扱い）ので、カクつくのがすっげー気になる。
今回は、足を下した瞬間の体の揺れでごまかしたけど、こんな苦労をするぐらいならループ設定を使わず、キーフレームコピペ乱打してやろうかと思ってしまうレベル。

その他、一応スクリプトも対応はしてるみたい。言語はLua。
Luaのコードはお遊びで買ったCodeaで見たことあるけども、組んだことはないなぁ…
まあJavaScriptと比べれば…いや、どっこいどっこいかな…ｗｗ


##Mohoから吐き出したsvgを魔改造したった

mp4とかaviとかgifで出力できるのは、わかる。
しっかしsvg（サイトで表示できるベクタ形式画像）で出力できるとか…マジかよ…
やろうと思ったらサイト上で好きに配置＆配色＆変形できるし、JavaScriptで再生フレームいじれるんちゃうん…？
ってことで、実際にやってみた。

何パターンか試したけど…
つい昨日モンストにハブられかけた（強制終了バグ出ましたが何か？今日は無事）
Android4.4のブラウザでもそれなりに動作するのはこれっぽい。
20MBぐらいあるから気をつけろ！
<a href="http://dmrb.nobody.jp/walk/walk.html" target="_blank">http://dmrb.nobody.jp/walk/walk.html</a>


で。
今回は260フレームってことで260個のsvgが出力された。
全部合わせて24MBでーす！ってゲロ重いわやめてくれｗｗ
いや、初回はもっと重かったんだけど、レイヤー名がそのまま出力されるから日本語から英語にしたり、今回は塗り設定だけで十分だから線を非表示にしたりしてケチった。

svgの中身を見てみる。
律儀に全ファイルにxml宣言とDOCTYPE宣言、svgのバージョンと名前空間宣言が入ってるのは、まあ分かる。
が。
いくらクラス名の衝突のリスクがあるとはいえ、各パスにデザインの属性を片っ端から付与するのはさすがにやめてくれ…
fill="none" stroke="#a60d3f" stroke-width="1" stroke-linecap="butt" stroke-linejoin="round"
ってだけで文字数どんだけあると思っとんねん…
ということで、さすがにクラス＆CSSでの指定に移行させたい。
あと、パスそのものの情報も一部空白を取っ払えそう。

いや、それより一番の問題は…
実際にsvgを表示したときに、設定していた一部のマスクが効いてない。
詳しく差分データを用意してタグを解読していくと…
どうやら、マスク設定を有効にしたグループ内にグループを入れ子で置いた場合、マスク設定が出力されない模様。
mp4で出力したときは問題なかったし、Moho側のバグっぽい。

オマケにタグをよく見ると、表示しているパスをそのままマスクとしても流用する設定を入れていた場合、内容が全く同じパスを表示用とマスク用として出力していることが発覚。
どうにかならんかとsvgの仕様を調べたところ、useタグを使うことでパス情報の使いまわしができることが発覚。
どうにかしてuseタグに移行させたい。


とにかく。
出力したsvgの内容がめっちゃ不服。どうにかしたい。
AEだったら速攻でスクリプト書いてただろうけど、今回はMoho。
今回のケースに留まらず、ローカルファイルをいじるという意味では、もうちょっと汎用的で楽な手段が欲しいところでもある。
Ruby on Railsも勉強したことだし…
ということで、Rubyでsvgタグをいじるプログラムを組むことにした。

マスクの設定が出力できてないレイヤーの名前に識別用の名前を付けてsvgを出力しなおす。
で、svgをRubyで読み込んで、その名前を見つけたら、マスクの設定を自動で付与。
マスクのパスが使いまわせそうだったらuseタグで参照するようにした。
あと、無くても動くからxml宣言とDOCTYPE宣言をごっそり削除。
デザインの属性も一旦ハッシュに登録して、同内容の設定だったら同じクラス名を付与。
全部パス走査し終わったらハッシュの中身を確認して、styleタグにクラス名とCSSを出力した。

他に、1個のファイルにする実験もやってみたんだけど、それだと今度はファイル1個が重すぎる問題が発生。
自分が使ってるレンタルサーバーはアップロードできるファイル1個の最大サイズは3MB。1個で20MBなんて論外of論外。
試しに3MB未満になるように適当に10個ほどに分割してみたけど…
オレのAndroidじゃキャッシュがうまく動かないのか、全く表示できず。
結局、最終版は260個のままなのであった。


あとはアニメーション。
svgファイルは各々1個で完結した静止画なので、html上ではこれをJavaScriptでパラパラ漫画の如く再生（切り替え）させる。
これ自体はよくあるimgタグの切り替え処理みたいなもんで、そんなに難しいことではないんだけども…
問題はロード時間と処理速度。ということで、読み込み方法あれこれ試した。

愚直なのは、htmlに最初から全フレームのimgタグを非表示設定付きで置いとくパターン。
JavaScriptで後から必要数分のimgタグをぶち込む汎用的な方法もあるけど、速度で言えば前者の方が早い。
先に結論をいっちゃうと、試した中でこれが最強だったよ（爆）
それでもオレのAndroidだと表示までに30秒ぐらい待たされるし、なぜか未だに1フレーム目だけ表示時のリサイズ処理が走らないんだけどね。なんだろね？

次にやったのは、読み込むファイルが多いからいけないんだ！的な発想で、最早別ファイルを読み込まない、svgをhtmlに埋め込むパターン。
「svgファイルを1個にしたら20MBになった」っていってんのに、それをhtmlに埋め込むってことはだな…まあアップロードできないわな。
一応GitHubの方で無理矢理試したけど、オレのAndroidはロードが終わらないどころか、ブラウザが死んだよ（爆）

さらに、ajaxを使って後でがっつりリクエスト＆ロードするパターン。
動かなくもないけど…オレのAndroidは1分ぐらい待たされた。うん。


あと別件で、imgタグじゃなくuseタグを使った表示もやってみた。
埋め込み式（ゲロ重htmlかajax）じゃないとダメなんだけど、一応表示＆アニメーションはできた。
ファイルパスの指定を省略できるし、ファイルアクセス的には早くなるかな？と思ったけど、速度の体感差は皆無だったね…
まあそういう方法もあると知れただけでもOKとしましょう。


報告は以上。