ホーム < ゲームつくろー! < DirectX技術編 < Aの座標にある物をBの座標で見てみると?

その19 Aの座標にある物をBの座標で見てみると?


 親子関係がある連結ボーンでは、親の座標(ペアレント座標)の中に子の座標(チャイルド座標)が混在します。子が親の座標内にある点に向きを変えようと考えたとき、その点を子の座標空間に変換する必要があります。ここでは、そういった座標変換について考えてみます。



@ Aさんの座標にある物をBさんの座標で見る

 下の図をご覧下さい。

 Aの座標をペアレント座標とし、Bの座標をチャイルド座標とします。Aの座標内に目的点×印があります。これをBの座標空間から見たとき、その座標値がどうなるかを検討してみます。ただ、このままだと検討のしようがありませんので、色々工夫を凝らします。まず、次の図をご覧下さい。

 黄色い部分はAの座標軸とBの座標軸のひねり角度(角度差)です。このひねりは煩わしいものですから、Bの座標軸をひねり角度分回転させてAと軸方向を合わせてしまいます。この時、目的点も一緒に回転させると、Bの座標から見る目的点の座標値は変化しません。次に、Bの座標の原点をAの原点に平行移動します。

 これで、AとBの座標がぴったりと重なりました。青いベクトルはBの原点から見た目的点へのベクトルで、Bの回転や移動と一緒に動いてきたので、Bにいる人からはやはり移動前と同様に動いていないように見えます。今、AB両方の座標軸がぴったり重なっているので、Bと一緒に動いてきた目的点の座標値は、Aの座標値とも言えます。お前の物は俺のもの。ジャイアニズムですね(笑)。兎にも角にも、この座標移動によって得られた目的点の座標が、Aの座標にあった目的点をBの座標から見た座標値となるわけです。

 もう一度点の移動だけ見てみます。

 Aの座標でこの動きを見ると、目的点がBの原点を中心に回転し(@)、平行移動しているように見えます。そして、移動後の座標はBの座標からみた目的点の座標値になります。


 ここまでを体系化してしまいましょう。まずAの座標空間での目的点の位置をTaとします。また、Aの原点をOb=(0,0)、Bの原点位置をObと表すことにしましょう(@図)。

 次に、ObをOaに合わせる様に平行移動させさす(A図)。

すると赤丸で表した点の座標はTa-Obという値に変わります。さらに、Bの座標系を回転させて、Aの座標系にぴったりと合わせます。これは、ひねり角度θ分時計回り(逆回り)させると良いので、

上図のように回転させることになります。この時Ta-Obにあった点の座標は、(Ta-Ob)Rtとなります。Rtは回転行列で、具体的には次のような行列になります。

で表されます。巻き戻すので-θとしているのに注意です。以上から、A座標にある点の位置をB座標空間から見た位置座標に変換する式は次のようになります。

 縦書きが好きな方はこちらです。

 (Tx,Ty)がB空間に変換した位置座標、(Txa,Txb)がA座標空間から見た返還前の位置座標、(Oxb,Oyb)がA座標空間から見たB座標空間の原点位置(オフセット位置)です。これらの情報があれば変換は簡単に行うことができます。上式を関数化してしまえば、もうツールとして使えますね。この上記の考え方が、ボーンの制御に繋がります。



A ボーンの制御は座標変換の嵐

 ボーンはポリゴンオブジェクトに埋め込まれる連結した「骨」で、これを動かす事によってアニメーションが実現されます。ボーンを図にしてみるとこんな感じです。

 AのボーンはBのボーンと、BのボーンはCのボーンと繋がっています。そして、これが重要なのですが、オブジェクトに埋め込まれている初期段階でボーンの向きはすべて軸上とされます。上の図だとX軸ですね。これにより、Aのボーンの向きに対するBのボーンの「ひねり角度」、Bのボーンの向きに対するCのボーンの「ひねり角度」が固定されます。これは次の図を見るとより鮮明です。

 ボーンをぐいっと曲げた状態です。緑色のボーンBが自分の座標空間で回転していても、Aのボーンの向きに対するBの座標空間のひねりである-30度は変わっていません。同じように緑のボーンとCの座標空間の-15度の関係も不変です。

 Bのボーン(Aの子に相当)が、親であるAの座標内にある目的点に向かって回転しようと考えたとき、「Aの座標にある点をBから見る」という@で説明した座標変換がそのまま使えます。Aの座標空間に対するBの座標空間のひねり角度は、初期のひねり角度-30度とボーンAの回転角度θAの和で計算できます(上の図だと-5度くらいでしょうか)。Aの座標空間から見たB座標空間の原点の位置座標は分かっていますから、@で説明した変換のための材料がしっかりそろっています。

 では、ボーンCからボーンAの座標内にある目標点を見るにはどうしたらよいのでしょうか?ボーンAはボーンBの存在を知っていますが、ボーンCまでは知りません。親は子しか見えていないのです。ボーンCを知っているのはその親ボーンであるボーンBのみです。そこで、まずボーンA座標にある目的点をボーンBの座標内に移し、その点をさらにボーンCが見るようにします。変換を2回つかうわけです。回転角度の与え方は、1回目の変換では「ボーンAの回転角度-B座標空間のひねり角度」、2回目は「ボーンBの回転角度-C座標空間のひねり角度」となります。対称性が取れていますので分かりやすいですよね。

 具体的な計算式で見てみます。

 ボーンA座標内の目標点の位置をTa、ボーンA自体の回転角度をθBnA、ボーンB空間の原点の位置をOb、そしてボーンB空間の初期ひねり角度をθibとします。TaをボーンB座標空間から見た座標をTbとすると、

Tb = (Ta-Ob)*Rt(θBnA+θib)

となります。ここでRt(θ)は角度θの回転行列を表すとします。

 次に、求めたTbをボーンC空間から見た座標であるTcに変換します。上の表記に習って、ボーンB自体の回転角度θBnB、B座標空間から見たボーンC座標の原点位置をOcとします。この計算は先程と全く同じで、

Tc = (Tb-Oc)*Rt(θBnB+θic)

で表されます。まったく同じ事の繰り返しをしているだけですね。これより、あるボーンの座標空間にある目的点を他のボーンから見るには、上式の回転と平行移動を組み合わせた変換式を親から子に向けて連続的に解いてやれば良い事がわかります。これは何となく「再帰関数」のにおいがしますね。



B 3Dに適用する時の注意

 ボーンに見られる連続的な座標変換の式は2Dも3Dも変わりません。ただ問題は3Dでの「ひねり角度」にあります。2Dでは回転軸は1つですが、3Dでは3つもあります。まともに考えると、何をどう回転したら良いか路頭に迷います。よって3Dの場合は軸回転ではなくてクォータニオンで考えた方が簡単になるかもしれません。ただし、クォータニオンだと角度制限が少し厄介になってしまいます。人や動物の間接は可動範囲が決まっていますが、それは大抵軸回転で制限が設けられています。このことから、クォータニオンの回転を軸回転に変換する機構がどうしても必要になってきます。その辺りの話は次の章で考える事にしましょう。