MMDモーショントレース自動化でのセンター推定


はじめに

この記事は【目次】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化。いつになるやら…