VBA で棒人間がラジオ体操をする エクセルアニメーション のその2です。
その1の内容はこちら↓。

順運動学(FK)の限界
前回は、胴体と首、手、足のバラバラだった動きを連結して、連動した動作ができるようになりましたが、ご覧のとおり、左右に揺れると空中浮遊しています。
これは、「胴体の位置を決める ➔ 股関節 ➔ 膝 ➔ 足先」という順番で座標を計算しているため、胴体(親)が動けば、末端の足先(子)まで強制的に連動して動いてしまう仕組み(順運動学:Forward Kinematics(FK / フォワード・キネマティクス)にしていたためなのです。
順運動学は、位置決めの計算がとても簡単という特徴があります。基本、足し算と掛け算の組み合わせだけですみます。ただ、この方法だと、手先の位置を「ピンポイントでここに固定したい」という制御ができません。
逆運動学(IK)の導入
ちょっと空中浮遊だと恰好悪いため、次に逆運動学のロジックを取り入れてみます。最初に「手先(足先)の目標座標」を決め、そこに向かって腕や足が届くように、途中の肘や膝、股関節の角度を数学的に「逆算」する仕組み(逆運動学:Inverse Kinematics(IK / インバース・キネマティクス))です。
これができると、キャラクターが地面を踏みしめたり、壁に手を突いたり、ドアノブを掴んだりする自然風な動きを作ることができます。ただし、計算が難しくなるので、プログラムが大変になるのと、PCの負荷はその分高くなります。
動きのロジックを、足をモデルに簡単に説明します。足は、「太もも(膝上)」、「すね(膝下)」の2つの直線から構成されています。このうち、次の2つの点は、動きとともに、決まった位置にあるものになります。
- 始点(股関節):胴体の動きに合わせて自動的に決まる(長方形の角)。
- 終点(足先):絶対に動かしたくないので、地面の座標に固定する。
この「挟まれた中間の点(膝)」を、以下のロジックで計算します。
🛠 ステップ1:股関節から足先までの「直線距離」を測る
胴体が上下に動くと、固定された足先との距離が変わります(胴体が下がれば近く、上がれば遠くなります)。まずは、この2点間のストレートな距離をプログラムで測ります。

ΔX、ΔYを戻しますと

というようになります。
ところで、d(足の長さ)の最大は、太ももの長さ+すねの長さ になりますので、胴体の高さ(Ya)がこれを超えてしまった場合は、胴から足がちぎれてしまうことになるので、そこまでが胴体の高さ(Ya)の限界値、というようになります。
🛠 ステップ2:太ももとすねの長さから「膝の位置」を割り出す
「股関節」「足先」の座標が決まり、それぞれの線の長さも分かっています。ここから「膝」の位置を求めます。どうやって?
こんな図でわかりますかね?

・股関節にコンパスの針を刺し、**「太ももの長さ」**で円を描く。
・足先にコンパスの針を刺し、**「すねの長さ」**で円を描く。
この2つの円が重なった交点が「膝」の位置になります。内側、外側で2カ所でますが、ポーズで使い分ける必要がでますね。
交点の座標を計算するとなると2次方程式を解かないといけなくなり、面倒です。それより、上の図で描いた「黄緑」、「えんじ」、「黒」の各線の長さはわかっており、この3線で作られる三角形で余弦定理を用いれば「膝の座標」(上の図だと、黄緑とえんじの交点」を出すことができます。
※余弦定理を忘れてしまった・・・という方は、下記のサイトの説明がわかりやすいです。

🛠 ステップ3:割り出した「膝」を経由して足を一本につなぐ
では、具体的にVBAコードに落としていきます。下の図を用いて説明します。

①基準の角度(α)
まず、股関節から足先が「どっちの方向にあるか」という大まかな基準の角度 αを出しておきます。
Excelに、Atan2 という便利な関数がありますので、それを使います。ステップ1で計算した「横のズレ(ΔX)」と「縦のズレ(ΔY)」の2つの数値を Atan2 に入れるだけで、画面の水平線から見た正確な方向(角度)を計算できます。

②太ももの「方向(角度)」
「足を内側に曲げる」とした場合、上の図で見ますと、股関節から足先に向かう「基準の角度(α)」から、θ だけ内側にずらした角度が、太ももを伸ばす方向になります。
θを求めます。ステップ2で頭出しした、余弦定理を用います。

ここからθを求めますと、

胴体の動きに合わせて、d の長さが変わりますが、右の式で cosθ 値が算出できます。あとは、VBAの WorksheetFunction.Acos を使って、cos θ の数値をラジアン単位の「角度 θ」に変換します。
コードは、こんなイメージです。
'--- ① 画面の水平線から足先に向かう「基準の角度 α」を出す ---
Alpha = WorksheetFunction.Atan2(dx, dy)
'--- ② 余弦定理の公式をそのままVBAの計算式にする ---
CosTheta = (a ^ 2 + d ^ 2 - b ^ 2) / (2 * a * d)
' 💡安全弁:数値が「-1 ~ 1」からはみ出すとAcosがエラーを吐くのでガードします
If CosTheta > 1 Then CosTheta = 1
If CosTheta < -1 Then CosTheta = -1
'--- ③ コサインの数値を「ラジアン単位の角度 θ」に変換する ---
Theta = WorksheetFunction.Acos(CosTheta)
③三角関数で「膝の座標」を算出する
①と②より、
太ももの角度 = α + θ
と計算できます。これで、方向が決まりました。
股関節の座標からその方向に線を伸ばせば完了です。
X(膝)=X(股関節) + a・cos(太ももの角度)
Y(膝)=Y(股関節) + a・sin(太ももの角度)
※ a は上図の黄緑色の線の長さ(太ももの長さ)になります。
コードは、こんなイメージです。上のコードから繋がります。
'--- ① 基準の角度に開き角をプラスして、太ももの最終的な角度にする ---
' プラスにして、膝がグッと内側に曲げる
RadThigh = Alpha + Theta
'--- ② 三角関数を使って、膝のX座標とY座標をピンポイントで計算 ---
KneeX = HipX + a * Cos(RadThigh)
KneeY = HipY + a * Sin(RadThigh)
'--- ③ 確定した座標 ---
' 1. 太もも:股関節~膝の座標
Thigh.X1 = HipX: Thigh.Y1 = HipY
Thigh.X2 = KneeX: Thigh.Y2 = KneeY
' 2. すね :膝の座標~地面に固定された足先
Shin.X1 = KneeX: Shin.Y1 = KneeY
Shin.X2 = FootX: Shin.Y2 = FootY
「すね」は新たに計算しなくても、膝の位置がわかっているので自然に決まりますね。
こんな感じで、プログラムを組みますと、下の動画のような動きになります。わかりやすいように胴体と片足のみにしてみました。
一旦、ここまで
自分でも忘れないように、作り方を細かく記載していましたらとても長くなってしまいました。まあ、でもなんとなく整理してみてよかったような気もします。
あと1回くらい基本動作編を続けるようですかね。早く、ラジオ体操自体に行きたいのですが(まだ作っていないのです)。先に作っちゃうと、ページ作るのが面倒になっちゃうので、同時進行していった方が自分には合っているようです。
それではまた!
コメント