前回お約束した、VST PlugInのキャラクターの新規作成、設定変更のやり方を解説します。

データ構造
ChordOfLifeフォルダにあるファイルの役割を説明します。データは多くのソフトウェアで使われているJSONというデータ構造で表現されています。
Characters.json
VSTで扱うキャラクターの定義。単にキャラクター名を羅列したもの。
この順序で選択肢にリストアップされます。
1つ目は”None”でなければなりません。
現バージョンでは、2つ目は”Drummer”固定、マルチチャンネルモードではch.1です。
3つ目以降は変更可能で、以降マルチチャンネルモードでch.2~に該当します。
空行はエラーとなります。
Drummerは複雑すぎて、キャラデータの組み換えに対応できていません。なので、当面Drummer.jsonは触らない方が無難です。(座標値を変更しないで画像だけ差し替えるのは可能かも・・・)
(キャラクター名).json
Characters.jsonで定義されたキャラクター名の詳細構造を記述しています。
データ構造は以下の通り。項目順は重要ではありません。
なお、データは手動で設定するわけではなく、設定ツール(後述)で書きだします。
とりあえず項目名だけ記述します。
bones–+-name Bone名
+-parent 親Bone名
+-x 位置X(後述)
+-y 位置Y(後述)
+-pivotX 関節位置X
+-pivotY 関節位置Y
+-rotation 回転量(Radian)
+-z Z Order(描画順) 小(奥)—->大(手前)
ここまでが必須項目で、以降はオプション的なデータです。
なくても一応絵は出ます。(動かないけど)
+-absPosX 絶対位置X
+-absPosY 絶対位置Y
+-L1 IKでの第1関節から第2関節までの距離
+-L2 IKでの第2関節からターゲットまでの距離
+-IKDir IK設定の向き
+-ikAbs IK計算を絶対座標で行うか相対座標で行うかのフラグ
+targetX IKでのターゲット座標X
+targetY IKでのターゲット座標Y
+-action このBoneの振る舞い
+-aMoveX actionのパラメータX
+-aMoveY actionのパラメータY
+-aRot actionのパラメータR
+-action2 このBoneの振る舞いその2
+-aMove2X action2のパラメータX
+-aMove2Y action2のパラメータY
+-aRot2 action2のパラメータR
以下boneの繰り返し
(bone名).png
上記キャラクターのbone名に該当する画像。pngのみです。
キャラクターデータ構造を理解するための基礎知識
キャラクターはBoneというパーツの集まり
2次元アニメーションの基礎である、AffineTransformという技術を用いています。

この図はAffineTransformの移動、ピボット、回転、拡大縮小を説明する図で、Geminiが書いたものなんですが、あれっ、拡大縮小の図、なんか変ですね。まぁでも、雰囲気で分かりますよね。
腰、胴、脚、足、上腕、前腕、頭、楽器などはBone(骨)またはパーツと呼ばれ、それぞれ矩形の画像で描かれ、それらを関節でつなぎ合わせて動かします。
それぞれのパーツ図形は左上が原点、Xは右方向が+、Yは下方向が+です。Yの方向は数学の教科書とは逆です。また、回転も数学の教科書とは逆で、時計回りが+です。
AffineTransformで重要なのは、パーツの親子関係です。親パーツが動くと、子パーツも引きずられて動きます。そして親子関係で重要なのが関節(Pivot)です。
パーツの親子関係は、親に対して、子パーツをつなぐということで作っていきます。このつなぎ目が関節(Pivot)なのですが、便宜上、関節は子パーツの持ち物で、パーツ毎に1つしかない、と考えます。
例を挙げると、胴体に上腕をつなぐには、親である胴体画像の肩の位置に子パーツ(上腕)の関節を重ね置くということになります。
親パーツは複数の子パーツを持ちますが、子パーツの親は1つしかありません。この例だと、胴パーツの子は頭、左上腕、右上腕と3つありますが、頭や腕パーツの親は胴のみです。
ちなみに、胴パーツの親は腰、腰パーツの親は背景(Background)、背景は特殊パーツで親なし(動かせません)ということになります。
FKとIK

BoneはFK(Forward Kinematics)というモデルで計算し、描画されます。
・ルートBoneを描く
・子のBoneをPivotを中心に(必要なら)回転させ、X,Yドット移動させて描画
・さらに子をたどり、相対値を用いて計算し、描画していく。
なので、胴が揺れれば腕も揺れます。頭も揺れます。
しかし、この方式だと、「手(前腕の先端)を50ドット上げる」にはどうしたらよいか分かりません。実際には手の位置でプログラミングしたいのに。困りましたね。
そこで、肩と手の座標から、肩関節と肘関節の角度を計算する手法が必要になります。この手法をIK(Inverse Kinematics)と言います。どうするかというと、高校数学で習う「余弦定理」というのを使うのです。
詳しい説明は省きますが、胴-上腕-前腕のコンビネーションで、前腕の先端である手の位置を指定することで、上腕パーツと前腕パーツの回転量を計算します。同じく、腰-脚-足のコンビネーションにおいて、足先の位置を指定することで、脚パーツと足パーツの回転量を計算します。
以上、必要な基礎知識でした。
MakeBoneTool
基礎知識を得たところで、Bonesデータを作るツールの使い方を説明します。
MakeBoneTool.exeは、どこでも動作しますので、好きなところに置いてください。
なお、VST PlugInを配置するVST3フォルダはWindowsによって更新制限がかかっています。なので、別の作業場所でデータを作り、完成後にコピーするようにしてください。

最初の作業は背景画像(Load Background Image)を読み込むことです。この背景は動かせない特殊Boneです。
背景画像を読み込むと、以降、通常のパーツ画像読み込みボタンに変わります。

パーツ画像を読み込み、その画像に対して、できることは・・・
・ドラッグで移動
シアンの枠が表示され、当該パーツが一番手前(z値最大)になります。
・Shift+ドラッグでPivot位置設定
・Ctrl+ドラッグで回転
・Alt+ドラッグで黄色い線が現れます。
親にしたいパーツの上でマウスアップすると親子関係が指定されます。
親子関係を解消したい場合は枠外でマウスアップします。
・右クリックでパーツ削除
親子関係が結ばれると・・・
・親パーツは黄色い枠が表示されます。また緑の矢印が現れます。
邪魔ならlinkVisibleボタンをOffにしてください。
・親パーツを操作すると、子パーツも連動します。ただし、いろいろな副作用があるので、Saveしてから行うことを推奨します。
・Saveファイルは画像のあるフォルダに.mbtファイルとして生成されます。
・Loadすると、Save時の状態が再現されます。
IK設定

・親、親の親があるパーツに対して有効な設定です。例)胴->上腕->前腕
・IK設定をするパーツと親パーツは回転していない状態で行ってください。
・IK設定をするパーツと親パーツのPivotは縦にそろった状態が望ましいです。
・前腕パーツにターゲット(手の位置)を指定します。(Ctrl+Shift+ドラッグ)
・前腕がセレクト(シアン)の状態で、Toggle IK Modeボタンを押し、IKモードにします。

・IKモードになると、マウスでターゲットをドラッグできます。
・IKの計算は、2通りの解があるので、肘の向きの正しい方向を指定してください。
(Toggle IK Dirボタン:ClockWise、CounterClockwise)
・動きが確かめられたらIK Modeを解除するとその時のターゲット座標が記憶されます。
表エリアの表示と操作


・表エリアにはパーツがZ値順に表示されます。
・各パーツのLock欄クリックで、位置が固定されます。
・Visible欄クリックで表示On/Offできます。
・パーツ名欄クリックでパーツのZ値を変更することなく、パーツを選択できます。
上下左右キーでパーツの位置を微調可能。なお、動かない場合は欄外を改めてクリックするとたぶん動きます。
・ikAbs欄をクリックすると、IKの計算における座標系を絶対値か相対値か指定することができます。どういうことかというと、手のようにターゲット位置が胴に連動する場合は相対座標でよいのですが、ターゲットが足先やキーボーディストの手の場合、絶対位置となるので、Abs指定をしておく必要があるのです。
action指定

※これがキャラの振る舞いの要です。当該Boneがどのように動くのか指定します。
しかし、上で書いてますが、この指定、Drummer.jsonには無効です。
[移動系]X値、Y値を併せて指定します
・Shake
4拍で往復する動き。
例)腰がリズムに従って横に振れる
・SimpleHit
NoteOnで振れ、2/3秒で元の位置に戻る。
例)ギタリスト、ベーシストの右手
・MoveByNote
NoteC4(60)を中心に移動。次の音が鳴るまでそのまま。
例)ギタリストの左手
・MoveByBassNote
NoteC3(48)を中心に移動。次の音が鳴るまでそのまま。
例)ベーシストの左手
・MoveByTrombone
Note(52~82)によりトロンボーンのスライダーポジション0~6へ移動
・KeyboardHighHit
NoteC3(48)以上の音による位置移動と、NoteOnでの縦Hitを合わせた動き
例)キーボーディストの右手
・KeyboardLowHit
NoteB3(47)以下の音による位置移動と、NoteOnでの縦Hitを合わせた動き
例)キーボーディストの左手
・MoveAndReturn
NoteOn時に振れ、Onの間はそのまま。Offしたら4/3秒で元に戻る。
例)トランペッターの手
・Bowing
バイオリンの弓のアップダウン。ロジックはとても複雑。
音が鳴り続けると2拍でアップダウン反転する。
移動系命令はIK設定されている(L1、L2が0でない)場合はPivotではなく、Targetへの命令になります。
[回転系]R値を併せて指定します
・Swing
2拍で1揺れする。
例)ギタリスト、ベーシストの胴
・TiltAndReturn
NoteOnの間傾き、NoteOffで元に戻る。
例)サックス
・TiltNoteAndReturn
Noteで傾きの度合いが変わるTiltAndReturn
例)管楽器奏者の胴
・ViolinistSway
バイオリニストの特有の胴の揺れ
・RandomSway
フルート奏者特有の胴の揺れ、ランダム要素あり
[その他]
・RandomVisible
時々表示Onになる。
例)目パチパチ
・VisibleWhileNoteOn
NoteOnの間表示Onになる
例)サックス奏者の顔
・VisibleWhileNoteOff
NoteOffの間表示Onになる
・RandomScale
時々スケールが0.3倍になる
例)目パチパチ
action2指定
※action指定では指定しきれなかった部分をこちらにて指定しています。
[アイドリング時の移動/回転量]
4拍以上無音になった場合、アイドリング状態となり、初期値からの変位量を指定できます。アイドリング状態はキャラは静止しています。
・IMove
X,Y値だけ移動します。IK設定Boneでは対象はTargetになります。
・IRotation
R値だけ回転します。
※IMoveとIRotationは併用できます。
[SpecialEffect系]SpecialEffectが全体でなく、Bone対象の場合、指定します。
・SpJump
ジャンプします。
例)腰(Plevis)
・SpGoRound
ぐるぐる回ります。
例)手(IK指定された前腕など)
・SpExpand
1秒で、大きくなり、次の1秒で元に戻ります。
例)ぼーーっと生きてんじゃねーよ
Export JSON
そして、最終的にExport JSONボタンにてVST PlugInに読み込ませるJSONデータを生成します。これは具体的に何をやっているかと言いますと・・・。AffineTransform表示システムにおける絶対座標系と相対座標系の変換を行っているのです。

とても面倒くさい話なのですが、技術的に超重要なところで、今回の一連の開発において、もっとも悩んだ所です。
Boneモデル作成ツールと、それを動かすVST PlugInではPos座標(X,Y)の持ち方が異なります。(Pivotデータはどちらでも画像原点からの相対値です。)
作成ツールは、個々のパーツをバラバラに動かすことが多いため、各パーツが持つXY座標は絶対座標であり、Pivotの絶対座標は「パート位置+Pivot相対値」で計算しています。
一方VST PlugInでは、パーツの親子関係をもとに関節で連携して動かすため、親パーツからの相対値として記述されます。さらに、実行時の計算を単純化するため、パート位置(X,Y)は原点位置ではなく、Pivot位置としています。
言葉ではわかりにくいと思いますので、図を見てください。この辺の話は理解しなくてもデータ作成はできると思います。まぁ僕自身への備忘録メモですな。
