GodotのGDCubismで遊ぶ
先日うまいことGDCubismがビルドできたので遊んでみます。
モデルはLive2D社が公式がサンプルを無料配布してくれているので、地に頭をこすりつけながらありがたく使わせていただきます。
材料
とりあえずGodotでモデル表示
公式の使用方法の通りにやったらうまく動いたので、特に言う事はないです。
ただ一点、これは俺がアホなせいなのですが、
ノード一覧から GDCubismUserModel を選択して、Assets項目の右にあるファイル選択ボタンを押してください。
ファイル選択ダイアログが表示されますので、そこから任意の *.model3.json ファイルを選択します。
ここで勘違いをして model3.json ファイル だけ Godotのプロジェクトフォルダに置きました。動きませんでした。
他のファイルも必要なんですね。
ひとつ賢くなりました。
そんなこんなで無事表示!
しかも読み込んだ時点でアニメーションしてる!
GDCubismUserModelの子要素としてGDCubismEffectBreath(呼吸)、GDCubismEffectEyeBlink(瞬き)を配置すると待機アニメーションしてくれるようですね。
すごい!
Hello Live2D World!
モデルを動かすその1:実装済みモーションを呼び出す
モデル表示したら次は動かしてみたくなるのがヒトのサガというものですね。
サンプルモデルの「桃瀬ひより」にはモーションが10パターン入ってるようなので、適当にボタンを作って対応するモーションを動かしてみます。
class: GDCubismUserModelのstart_motion()メソッドを呼び出せばいいのかな。
GDCubismMotionQueueEntryHandle start_motion(group: String, no: int, priority: Priority)
指定した group と no の Motion を再生します。
引数のgroupとnoが良く分からないので、先にget_motions()でモデルが持ってるモーションの情報を調べた方が良さそう。
var dict_motion = $GDCubismUserModel.get_motions()
for group in dict_motion.keys():
for no in dict_motion[group]:
print("group: %s, no: %d" % [group, no])
こんな情報が得られた。
group: Idle, no: 0
group: Idle, no: 1
group: Idle, no: 2
group: Flick, no: 0
group: FlickDown, no: 0
group: FlickUp, no: 0
group: Tap, no: 0
group: Tap, no: 1
group: Tap@Body, no: 0
group: Flick@Body, no: 0
で、こんな感じでメソッドを呼び出せば...
$Sprite2D/GDCubismUserModel.start_motion("FlickUp", 0, GDCubismUserModel.PRIORITY_FORCE)
動いた!
すごい!
モデルを動かすその2:パラメータを与えてマウスを目で追う
start_motion()は登録されているモーションを呼び出すものなわけですが、次はパラメータを直接動かしてみます。
分かりやすそうなのはマウスの座標を目で追う動作ですかね。
Live2D Cubism Viewer上で左クリックをホールドしながらぐりぐりしてみると、
角度X
角度Y
目玉X
目玉Y
体の回転X
これら5つのパラメータが反応しているようでした。
(他にもあったけど物理演算っぽい)
Godotの座標系は左上が原点(0,0)、5つのパラメータはそれぞれ
角度X:←-30、+30→
角度Y:↓-30、+30↑
目玉X:←-1、+1→
目玉Y:↓-1、+1↑
体の回転X:←-1、+1→
これらのパラメータに、両目の中心あたりを起点にしたマウスとの距離をパラメータとして与えてみます。
使うのはこの辺かな。
class: GDCubismParameter
GDCubismUserModel の get_parameters 関数で戻される Array に含まれる要素。
このクラスの value に値を書き込むことで、Live2Dモデルの parameter を書き換えることができます。ParameterMode parameter_mode [default: 0]
現在保持しているLive2Dモデルのコントロール方法を指定します。Array get_parameter()
現在保持しているLive2Dモデルを操作するためのクラスを取得します。enum ParameterMode
FULL_PARAMETER = 0
start_motion 関数で指定した Motion を再生する時に指定します。
この指定がされているときは GDCubismParameter による操作は行えません。NONE_PARAMETER = 1
get_parameter 関数で取得した GDCubismParameter を使用して、Live2Dモデルを操作する場合に指定します。
この指定がされているときは start_motion 関数でモーション再生は行えません。
モーション呼び出しかパラメータ指定かどちらかでしかアニメーションしないようですね。
「モーション中にマウスを目で追う」みたいな動きはできないようです。
まずはやってみますか。
とりあえず print(GDCubismUserModel.get_parameter())
してみるとこんな感じ。
[[Wrapped:0], ..., [Wrapped:0]]
[Wrapped:0]
が詰め込まれた配列(70要素)が返ってきます。
この [Wrapped:0]
がGDCubismParameterのようです。
どれがどのパラメータか判別できないので、cdi3.jsonファイル(パラメータ保持ファイル)の中を覗いてみます。
この中のParametersオブジェクトがパラメータのようですね。
ちょうど70個あってget_parameter()の要素数と一致するので、断定してしまいます。
要素番号も上から順に紐づいてるんじゃないかな(適当)。
というわけでこんな感じのスクリプト。
# 顔の中心 :X220、Y127
# マウスのX座標 - 200
var mx = get_viewport().get_mouse_position().x - 220
# 127 - マウスのY座標
var my = 127 - get_viewport().get_mouse_position().y
# GDCubismParameter配列
var arr:Array = $Sprite2D/GDCubismUserModel.get_parameters()
# 角度 X
var ParamAngleX:GDCubismParameter = arr[0]
ParamAngleX.value = mx
# 角度 Y
var ParamAngleY:GDCubismParameter = arr[1]
ParamAngleY.value = my
# 目玉 X
var ParamEyeBallX:GDCubismParameter = arr[9]
ParamEyeBallX.value = mx
# 目玉 Y
var ParamEyeBallY:GDCubismParameter = arr[10]
ParamEyeBallY.value = my
# 体の回転 X
var ParamBodyAngleX:GDCubismParameter = arr[20]
ParamBodyAngleX.value = mx
静止画像だとめちゃくちゃ分かりづらいけど、右上にあるマウス座標を追ってます。
しかも、ボタンを押してアニメーションさせてる最中にもパラメータが更新されました(モーションしながらマウスの動きに追従した)。
これはうれしい誤算だった。
モデルを動かすその3:モデルをマウスクリックでアクション
ハイ本命です。おさわり、したいですよね。
...と言いたいところですが、
Array get_hit_areas()
未実装。
だそうで、モデルの衝突判定が取れないんじゃダイレクトなおさわりは難しそうですかね。
戻り値でなにがしか取れるんですが、どう使うかは謎。
代替手段はあるのかな。
オブジェクトをさかのぼって描画領域を無理やり引っこ抜くとか?
うーん...。
おわり
ざっくり触ってみました。
v0.1.0ということもあって発展途上という感じです。
Live2Dに期待する基本的な動作(待機モーション、モーション呼び出し)は出来ているので、ゲームによっては使うのもアリですね。
選択式の疑似おさわりとかは現状でも可能ですし、モデルの座標がさほど動かないなら決め打ちでクリック範囲作ってのおさわりなんかも出来ますし。
アニメーション終了時のポーズを保持するようなので、パーツごとにアニメーションを作って組み合わせて使うのも良さそう。
定義したパラメータはスクリプトから自由にいじれるようなので、上手く使えば表情を変えながらアニメーションとかもできるのかな。
OSSなので、ソースを追えばもっと詳細が分かると思いますが今回は行き当たりばったりでやってみました。
逆に言うと、何となく実装してもそれなりになる使用感の良いライブラリということですね。
そんなかんじ。