Blenderのpythonでクオータニオン(Quaternion)を勉強した。しかし、BlenderのQuaternionの機能は一切使わない。Quaternionを使った計算方法、モデルの操作方法が知りたいからだ。
まとめ
先に、まとめを書く。
クォータニオンで
オブジェクトの回転ができる。
回転が、任意のベクトルでできる。
注意点
- アフィンと違い、行列の積ではない。Quaternion同士の積は、独自ルールのかけ算が要る。
- 原点を中心として回転になるので、原点を通らないベクトルで回転させたいときは、座標系の変換がいる。
やりたい事、やりたくない事
- やりたくない事
- Quaternionの数学的な理解。
- やりたいこと
- Quaternionの数学的操作。
ググったら、
blenderのpythonを使って、オブジェクトを回転させている記事はあった。)
しかし、オブジェクトの操作のAPIが、クォータニオンを直接受け取れるから実行できるコマンドの記事だった。クォータニオンを使って、計算をしているわけではなかった。
クォータニオンが、回転のどこら辺に効いているのかを知りたい。
そこで、自分で用意した3×3×3=27個の点の回転をクォータニオンで計算する。
クォータニオンは…
その前に、クォータニオンについて、参考書やネットなどで情報収集した。
- クォータニオンは複素数の拡張版。実数一つに、虚数三つ、計四つ。これは暗記した知識として持っている。「先頭が角度で、その後にx,y,zに関わる何か?」な状態。何も具体的にイメージできない。
- プログラムとかだと、独自の型をもったクォータニオン型の変数として表されることが多い。行列みたく、単なる長さ4の配列じゃなめなのか。
- 回転を表すクォータニオンはサイズが1らしい。だったらサイズ1以外だったらどうなっちゃうのか。
そもそも、回転を表すクォータニオンを準備できたとして、どうやって物を(例えばxyz座標上の点を)回転操作するのか。掛け算?
「どうせアフィンみたく行列の掛け算でできるんだろ?もったいぶるなよ。」とか思ってたが違った。
Blenderのモデル
下記コードでできたモデルを使った。
coord = [[[[i,j,k] for i in range(3)] for j in range(3)] for k in range(3)]
for i in range(3):
for j in range(3):
for k in range(3):
bpy.ops.mesh.primitive_uv_sphere_add(size=1, view_align=False, enter_editmode=False, location=(coord[i][j][k][0]*3, coord[i][j][k][1]*3, coord[i][j][k][2]*3), layers=(True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False))
mat = bpy.data.materials.new("Material_%s_%s_%s"%(coord[i][j][k][0]+1, coord[i][j][k][1]+1, coord[i][j][k][2]+1))
bpy.context.object.data.materials.append(mat)
bpy.context.object.active_material_index = 0
bpy.context.object.active_material.diffuse_color = (coord[i][j][k][0]/3.0, coord[i][j][k][1]/3.0, coord[i][j][k][2]/3.0)
bpy.context.object.data.name = "ball_%s_%s_%s"%(coord[i][j][k][0]+1, coord[i][j][k][1]+1, coord[i][j][k][2]+1)
bpy.context.object.name = "ball_%s_%s_%s"%(coord[i][j][k][0]+1, coord[i][j][k][1]+1, coord[i][j][k][2]+1)
拾ってきた式
クォータニオンの操作は、この本を参考にした。。面白かった。
クォータニオン
クォータニオンは、こんな感じで4つ1セット書かれている。
座標
位置ベクトルをクォータニオンで表す。
座標が[x,y,z]だとしたら、
クォータニオンは[0,x,y,z]と最初に0をつけるだけ。(本当は0+xi+yj+zkと書くべき?)
回転を表すルール
上記が成立するクォータニオンは、回転を表現できる。
回転を表しつつ、上記ルールを守るための、三角関数を使ったクォータニオン
「二つしかないからクォータニオンじゃないじゃん!」→実部と虚部を分けて書いてあるだけ。
- 右側(虚部)の数値は、虚部で分け合って使う。
- 分け合い方で、回転軸のベクトルを作る。
- さらに上記「二乗して合計して1」というルールも守って作らなければならない。
は、逆四元数。虚部の正負がひっくり返った四元数。
cosとsinがどんな塩梅で合計1になりそうかは、ちょっと分からん。
↑こんな感じで配分してみた。
1/3は、三等分だから。
√2は、わからん。
とにかく、√2/3しとくと、「二乗して合計して1」ルールを満たす。
回転操作
クォータニオンのかけ算
回転にはクォータニオンのかけ算を使う。
クォータニオンのかけ算のルールは、以下の式。独自ルール。甘くはなかったか。
これは、関数を使って実現しておく。スカラー,i,j,kは別々に計算して返せばいいだろう。自作なので、わざわざクォータニオン型とか作らんで、配列でやっとけばいっか。自分がわかってればいいもんね。
def quakakezan(q=[1,2,3,4],r=[5,6,7,8]):
a=q[0]*r[0]-q[1]*r[1]-q[2]*r[2]-q[3]*r[3]
b=q[0]*r[1]+q[1]*r[0]+q[2]*r[3]-q[3]*r[2]
c=q[0]*r[2]+q[2]*r[0]+q[3]*r[1]-q[1]*r[3]
d=q[0]*r[3]+q[3]*r[0]+q[1]*r[2]-q[2]*r[1]
e =[a,b,c,d]
return e
想定外の変数が入ってきたら、エラーで止まるかも。
最初から値が入っているのは、自分がどんな値を入れたらいいか忘れそうだし、関数のすぐ下にコメントアウトで説明書き入れたって、どうせ読まないから、あえて入れちゃう。
回転操作
- 座標の位置クォータニオンを作る。
- 前述、回転のためのクォータニオンを作る。
- 2.を、前と後ろから、かける
もちろん、四元数のかけ算のルールで計算する。
テクスチャを貼っていないから気づかないだろうけど、ボールは回転していない。同じ向きを画面に向けたまま。
BlenderのQuaternionの機能を使って回転させると、ボールの向きも変わるが、それはしなかった。
コード全体は、YouTubeの説明のところに書いてあるので、ぜひ見てください。
振り返ってみると
テクスチャを貼って、オブジェクトのvertexを回転させるのでもよかった気がする。
が、あえてオブジェクトをすべて動かすことで、何か理解した気になった。