はじめに
この記事は【目次】MMDモーショントレース自動化への挑戦 の一環です。
導入方法や他の技術解説等は、上記目次から各記事を参照してください。
ほぼ自分用作業メモ。
Github
3d-pose-baseline-vmd
VMD-3d-pose-baseline-multi
課題
3d-pose-baseline-vmd で取得した3Dデータにはセンター移動データが含まれていない
アプローチ
- Openposeでは関節位置の移動が取れている事から、Openposeのデータを流用すればセンター移動ができるのでは、と推定
- 基準点があれば、移動量も計測できるのではないかと想定
解決策
力業です。スマートじゃない…
動画は、Babo様のSNOBBISMをお借りしております。利用許諾ありがとうございます!
事前準備
Openposeの関節位置情報取得
Openposeで解析された2Dの関節位置情報をVMD生成処理時に使用する。
ただし、Openposeそのもののデータは暴れたり飛んだりしているので、3d-pose-baseline-vmd
で3Dに変換する直前の正規化2Dデータ(smoothed.txt
)を準備する。
直立フレームの選定
できるだけ正面向きで直立しているフレームを決める。
具体的には、Openposeで首と両足付け根が二等辺三角形になっているフレーム。
このフレームを、MMD上のセンターが(0,0,0)であると見なし、以下処理を行っていく。
X軸移動
処理対象フレームの首、左足付け根、右足付け根のX軸の平均値を求める。
首だけにしなかったのは、Y軸方向に傾いてた場合を考慮するため。
おおざっぱに言えば、へその位置を求めるようなもんです。
# 首・左足・右足の中心部分をX軸移動
x_avg = ((smoothed_2d[n][0].x() + smoothed_2d[n][1].x() + smoothed_2d[n][2].x()) / 3) - smoothed_2d[upright_idx][0].x()
bone_frame_dic["センター"][n].position.setX(x_avg * upright_xy_scale)
カメラからの距離で移動量が変わるので、その辺は外部パラメータで今のところ吸収しています。
Y軸移動
処理対象フレームの左足付け根、右足付け根のY軸の平均値を求める。
片足だけにしなかったのは、Z軸方向に傾いてた場合を考慮するため。
# 左足と右足の位置の平均
leg_avg = abs((smoothed_2d[n][1].y() + smoothed_2d[n][2].y()) / 2)
# 足の上下差
leg_diff = upright_leg_avg - leg_avg
# Y軸移動
if is_groove:
# グルーブがある場合には、そっちに割り当てる
bone_frame_dic["グルーブ"][n].position.setY(leg_diff * upright_xy_scale)
else:
bone_frame_dic["センター"][n].position.setY(leg_diff * upright_xy_scale)
これも外部パラメータで移動量調整できるようにしています。
準標準モデルをトレース対象として読み込んだ場合には、グルーブにY軸移動量を割り当てます。
#トレーサーとしての好みです
Z軸移動
※暫定処理です。今後調整の可能性大。
ざっくり言うと、首と両足付け根の二次元面積を、2Dと3Dの両方で算出して、その縮尺の割合で求めてます。
2D直立フレームの二次元面積
図は「直立フレームの選定」参照。
# 直立フレームの三角形面積
smoothed_upright_area = calc_triangle_area(smoothed_2d[upright_idx][0], smoothed_2d[upright_idx][1], smoothed_2d[upright_idx][2])
3D直立フレームの投影二次元面積
# 3Dでの首・左足・右足の投影三角形
pos_upright_area = calc_triangle_area(positions_multi[upright_idx][8], positions_multi[upright_idx][1], positions_multi[upright_idx][4])
2D処理フレームの二次元面積
# 2Dでの首・左足・右足の投影三角形
smoothed_now_area = calc_triangle_area(smoothed_2d[n][0], smoothed_2d[n][1], smoothed_2d[n][2])
3D処理フレームの投影二次元面積
# 3Dでの首・左足・右足の投影三角形
pos_now_area = calc_triangle_area(positions_multi[n][8], positions_multi[n][1], positions_multi[n][4])
2D面積の縮尺
カメラから見て、遠ざかるほど、縮尺は小さくなる
# 2Dでの現在の縮尺
smoothed_scale = smoothed_now_area / smoothed_upright_area
3D面積の縮尺
傾きが大きいほど、縮尺は小さくなる
# 3Dでの現在の縮尺
pos_scale = pos_now_area / pos_upright_area
Z軸の算出
3D面積の縮尺 * (1 - 2D面積の縮尺)
で、傾きを考慮したZ軸距離を算出する
1. 1 - 2D面積の縮尺
は、MMDセンター基準のZ軸位置。
→ マイナス値であれば近づき、プラス値であれば遠ざかる
2.3D面積の縮尺
で、傾き分の補正を行う
→ 傾きが大きい(3D縮尺が小さい)ほど、Z軸の移動量は小さくなる
要は、真横向きとか、傾きが大きいと、2D面積が小さくてもあんまり奥には配置しない、って事です。
# Z軸移動位置の算出
now_z_scale = pos_scale * (1 - smoothed_scale)
# Z軸の移動補正
bone_frame_dic["センター"][n].position.setZ(now_z_scale * center_z_scale)
Z軸補正は、XY移動量と連動しないパターンがあったので、別途外部パラメータで移動量調整できるようにしています。
課題
- 腰から上半身を前向きに折るような姿勢の場合、Z軸移動で、希望より前に移動しがち。
- XYおよびZ軸の移動量が外部パラメータ依存。自動判定できたらいいなぁ…
次回予定
最大の難関、足IK化。いつになるやら…