Mohoから出力したSVGを制御したい妄想の話

■2020/12/31追記
「続・Mohoから出力したSVGを制御したい妄想の話」ということで、続きを書きました。
７記事あるけど。ワロス。

【SVG制御妄想１】SVG解析しないと始まらない
https://qiita.com/flying_echidna/items/5a628db0d652d1558208

【SVG制御妄想２】Mohoから出力したSVGのマスクがバグる
https://qiita.com/flying_echidna/items/3930caf04626deec7bfb

【SVG制御妄想３】連番データをどげんかせんと
https://qiita.com/flying_echidna/items/ded3f3590c3d67fadb86

【SVG制御妄想４】変形させたいよなぁ？
https://qiita.com/flying_echidna/items/188634f35a05bbde9a51

【SVG制御妄想５】ボーンぐりぐり
https://qiita.com/flying_echidna/items/a34648da8a650fe34824

【SVG制御妄想６】助けてマルチスレッド
https://qiita.com/flying_echidna/items/80b101c1a1eedb534137

【SVG制御妄想７】SVGの限界
https://qiita.com/flying_echidna/items/2f53a461c5e6c05109df

追記ここまで。

---

現在、実際に作ってる最中のブツがこちら。
適当なタイミングで更新をしてるので、ここで書いてる内容から構成が変わってる可能性あり。

【GitHub】SourceOf0-HTML/path_control: SVGを制御したい願望
https://github.com/SourceOf0-HTML/path_control

【GitHub Pages】ベクターデータをいじり倒したい気持ち
https://sourceof0-html.github.io/path_control/


さて。
妄想話の前に、そもそもの話から。

#Mohoとは
2Dアニメーションソフトウェアのこと。
昔はAnime Studioという名前だったらしい。
自分が使用しているのはMohoPro12。

2Dアニメーションソフトウェア – Moho (Anime Studio): イーフロンティア
https://www.e-frontier.com/smithmicro/moho/


初めて使ってみたときに調べたことを解説動画として雑にまとめたこともある。

MohoPro12使ってみたので自己流解説 - YouTube
https://www.youtube.com/watch?v=hNsmKullIvo


#SVGとは
スケーラブル・ベクター・グラフィックス（Scalable Vector Graphics）の略称であり、画像形式の一種。

PNGやJPGはラスタ形式…ビットマップ画像とも言われるもので、pixel（画素）の集まりで構成されている。
ちなみにpixelはpicture cell（画像の細胞）からの造語らしいよ。
写真なんかは基本ラスタ形式。
細かい色合いを表現できるのが特徴。
拡縮すると劣化するのが弱点。


これに対してSVGはベクタ形式と呼ばれる画像…
というか図形と言った方が分かりやすいかもしれない。
複数の点（アンカーポイント）を繋いだ線（セグメント）に対して、線の太さや塗りの色を設定することで画像が構成されている。
ポスターなんかは基本ベクタ形式。
拡縮しても劣化しないのが特徴。
細かい色合いを表現しようとすると、点と線の数が膨大（≒データサイズが膨大）になるのが弱点。

最近のWeb上のアイコンはSVG形式のものが多い…
てか今見たらQiitaのロゴもSVGだね。

#MohoからSVGを出力すると…？？
Mohoで作成したアニメーションは、SVGの連番ファイルとして出力することができる。
…が、しかし。

　バ　グ　る　＆　フ　ァ　イ　ル　が　重　い　。

というところは、去年苦労した部分の話。
当時そのあたりで奮闘した話をしてたので、そこから引用をば。

【2019-03-06】「SVGでアニメーションさせたいんじゃ」の詳細報告
https://qiita.com/flying_echidna/items/ff3a061f4e348e62cca0

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

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

…とまあそんなことがありましたとさ。

#愚直にSVG連番ファイルを再生
当時、四苦八苦してRubyで

 - バグで吹っ飛んだマスクを、レイヤー名（SVG側でのgタグのID）を頼りに再設定
 - 同じデータを共通設定として整理しなおしてSVGを圧縮

をしまして。
出来上がったSVG連番を、JavaScriptを使ってHTML上でパラパラ漫画形式で再生、というのをやりましたとさ。

【GitHub】SourceOf0-HTML/walk_anime: svgアニメーションのテスト
https://github.com/SourceOf0-HTML/walk_anime

**※圧縮したとはいえ、ゲロ重注意（23.1MB）**
【GitHub Pages】walk
https://sourceof0-html.github.io/walk_anime/

ただ、このとき書いたRubyのコードは、あまりに四苦八苦したせいか、GitHubには上げてなかったようで。
またSVGをいじるにあたり、今回のGitHubのリポジトリには入ってます。えぇ。

【GitHub】path_control/addMaskTag.rb at master · SourceOf0-HTML/path_control
https://github.com/SourceOf0-HTML/path_control/blob/master/convert/addMaskTag.rb

ものとしては
同階層にsourceフォルダを作成＆Mohoから出力したSVG連番ファイルを入れて実行すると、
同階層のdestinationフォルダに同名のSVGファイルを出力する、
というもの。
ただ、さすがに変換前後のSVGまでは重いので、フォルダも含め一緒には上げてないです。

#再生だけじゃなく制御したくなってきた
ここからが今年の話。

久々に衝動のままMohoでアニメーションを作っていたところ、どうにも思った動きをしない部分が出てきて、気が付いた。

「あぁ、Mohoがやってるのはボーン（動きを制御するための骨のようなもの）を
基準としたアンカーポイント周りのアフィン変換（移動拡縮回転）でしかないのか」

「…ということは、
インバースキネマティクス（雑に言うと、目標点に向かって腕を伸ばすときの関節の角度の制御方法）で、
ボーンを再現した上で、SVGの制御したら…
Moho上での作業画面みたいな感じで、リアルタイムでアニメーション生成できるんじゃね？」

「Moho上のアクションの合成でやるモーフィング（ある形からある形へ徐々に変形するアニメーション）も実装できたら、夢がひろがりんぐじゃね？」

「やったろ」

尚、この思い付きから、現在すでに１ヶ月経っております。えぇ。
そして、今からするのはあくまで経過報告です。
まだできてない。うん。

ちなみにインバースキネマティクス自体は、p5.jsでシンプルなものを作ったことがあって、実物で言うとこんな感じ。

sketch_190830b - OpenProcessing
https://www.openprocessing.org/sketch/748924

ちなみにフォーワードキネマティクス（指定した角度に関節を曲げる＆次の関節にも角度が影響する）というものも存在する。

sketch_190830a - OpenProcessing
https://www.openprocessing.org/sketch/748921

フォーワードキネマティクスの方がシンプルだし、処理的にもよく見かけるかも。
多分ボーンを実装するときはこっちもお世話になる。

#もう脱SVGしてバイナリ化しようぜ
今回やりたいことをやろうとすると、SVGの中身を参考にしつつ、どのパーツをどういう形で描画するのか制御しなきゃいけない。
つまり、SVGをそのままHTML上に表示するのではなく、JavaScriptで編集した後のものを表示しなきゃいけない。

そこまでするなら、SVGを解析＆座標や色・差分の情報を自分で設計したクラスにぶちこんで、canvasに描画した方がよくない？？

というかそこまで解析してしまうなら、それをベースにバイナリ出力＆バイナリ読み込みした方が、ファイルサイズも減るやん？？

…と、いうことで。
現状、ここまでができており、冒頭に置いてるものは（2020-02-12現在）バイナリ化したものを読み込んで表示しております。
一応改めてリンク張っとこう。

通信量は4.1M。
前述のが23.1MBだったことを思えば、軽い軽い。

【GitHub Pages】ベクターデータをいじり倒したい気持ち
https://sourceof0-html.github.io/path_control/


#解説とかこれからの方針とか
作ったブツの構成は現状こんな感じ。

【GitHub】SourceOf0-HTML/path_control: SVGを制御したい願望
https://github.com/SourceOf0-HTML/path_control

**ファイル構成（2020-02-12現在）**

| ファイル・フォルダ | 説明 |
|:-:|:-:|
| convert/ | 前述のSVG変換用のRubyとか入ってる |
| img/ | convertのヤツで変換した後のSVG連番ファイルが入ってる |
| js/ | JavaScriptファイルあれこれ（後述） |
| src/  | 独自形式バイナリファイルが入ってる |
| BinaryStructuresNote.txt  | バイナリファイルの構成メモ |
| ClassStructuresNote.txt | クラスの構成メモ |
| index.html | GitHub Pagesで表示してるページ |
| output_data.html | SVG->バイナリ変換処理用HTML |
| svg.html | SVGそのまま再生用HTML |


jsフォルダの中身はこんな感じ

| ファイル | 説明 |
|:-:|:-:|
| index.js | index.html用 |
| output_data.js | output_data.html用 |
| path_control.js | メイン処理用 |
| path_control.min.js  | メイン処理用（Minify済み） |
| svg.js  | svg.html用 |

ちなみにMinifyってのは、ブラウザに読み込ませるJavaScriptのコードが長すぎるとデータが重くなるから、その分通信量かかるでしょ？ってことで、コードを圧縮すること。
人によってはよく「○○.min.js」ってのを見かけると思うけど、あれはそういうもの。

Minify化するツールは検索したらいろいろ出てくるよ。
自分が今お世話になってるのはココ。

JavaScript Minifier
https://javascript-minifier.com/

##htmlに対応したjs共
index.js、output_data.js、svg.js、のことね。
主にHTMLで表示しているcanvasの制御と、
path_control.jsで実装してある処理の呼び出しをしてる。
フレームレートやフレーム数を管理しつつ、描画処理命令を呼び出して…みたいな。
この辺りはまだまだ構成をいじるだろうなと思ってる。

というのも、
表示したいものをループ再生させるだの、
ボーンをどう動かすかだの、
どれぐらいモーフィングさせるかだの、
再生周りの制御を最終的にすることになるので…
初期化処理のつもりで作ってるところで、そこまで面倒見てたらえらいことになるやん？

なので、フレーム数処理あたりは特に、メイン処理にあたるpath_control.jsに引っ越しなりなんなりすると思う。
最終的には初期化と、マウスやスマホでの操作の入力を受け取るだけにしたい。

##path_control.js
メイン。本題。本体。うん。
久々にガチめのクラス設計をしてるので、クラスの説明をば。

| クラス名 | 説明 |
|:-:|:--|
| PathCtr | ファクトリー＆シングルトンなクラス |
| PathContainer | １キャラ分のデータに相当。<br>画像サイズや各アクションの総フレーム数、GroupObjのインスタンスをリストで持ってる。 |
| GroupObj | Mohoのグループレイヤー、SVGのgタグに相当。<br>PathObjのインスタンスのリストや、入れ子になってるGroupObjのインスタンスのリストを持ってる。 |
| PathObj | Mohoのベクターレイヤー、SVGのpathタグに相当。<br>実際に描画するアンカーポイントやセグメントの塗りの色情報なんかを持ってる。 |

『ファクトリー＆シングルトン』てなんやねん。
いや、あれですわ。
デザインパターンってヤツです。えぇ。

ファクトリーパターンは、生成するときにしか用事がない処理をまとめて実装してある設計のこと。
生成し終わったインスタンスでやる処理と言えば、
描画前の座標更新だったり、
実際の描画処理だったりするんだけど、
生成するときの…
今回だとSVGを解析して～とかバイナリを解析して～なんて処理は、
各々のインスタンスに持たせる必要がない処理なので、
PathCtrにまとめてある。

シングルトンパターンは、実行中のプログラムの中で１つしか実体（インスタンス）を用意しない設計のこと。
C++とかでガチでやるなら、外部からのコンストラクタやコピーコンストラクタの呼び出しを禁止して、別途インスタンスを生成して返すstaticの関数を作って…とかガッツリやることがあったりするけども…

今回JavaScriptでやってるのは、varで用意した変数にオブジェクトを突っ込んでるだけの雑な作りです。
なので、最早クラスと呼んでいいのか怪しい。
単なるオブジェクト。うん。

##今後ボーンを実装するにあたり…
ボーン周りは現状まったく未着手。
その前にアフィン変換部分を実装しようかと思ってる。
ようは行列変換。そう。数学で出てくるあの行列。

```math
\begin{pmatrix}
y_1 \\
y_2 \\
1
\end{pmatrix}
=
\begin{pmatrix}
p & q & b_1 \\
r & s & b_2 \\
0 & 0 & 1
\end{pmatrix}
\begin{pmatrix}
x_1 \\
x_2 \\
1
\end{pmatrix}
```

↑ こういうやつ。
数学赤点偏差値28の自分がそんな高等なことできるの？
って言われたら…
まあ…自力で全部理屈から追って実装するのはキツいかな。

ただ、世の中便利なもので、そういう行列変換周りの処理をまとめて実装してあるコードは存在して、自分も実際お世話になりまくってるのよね。
描画系のプログラムを書いたことがある人なら見たことがあるかもしれない。

```
xxx.translate();
xxx.rotate();
xxx.scale();
```

こういう関数。ようはこれの実装だったりする。
それでいて、これの実装をしてる人は世の中に結構いるわけで。

今回は ↓ を参考にさせていただいて実装して、描画前の更新処理として走らせようかなと思ふ。

【GitHub】transformation-matrix-js/matrix.js at master · leeoniya/transformation-matrix-js
https://github.com/leeoniya/transformation-matrix-js/blob/master/src/matrix.js


と、いったところで。
現状報告終了！