Blenderのpythonでクオータニオン(Quaternion)を勉強した。しかし、BlenderのQuaternionの機能は一切使わない。Quaternionを使った計算方法、モデルの操作方法が知りたいからだ。
まとめ 先に、まとめを書く。
クォータニオンで
オブジェクトの回転ができる。
回転が、任意のベクトルでできる。
注意点
アフィンと違い、行列の積ではない。Quaternion同士の積は、独自ルールのかけ算が要る。 原点を中心として回転になるので、原点を通らないベクトルで回転させたいときは、座標系の変換がいる。 VIDEO
やりたい事、やりたくない事 ググったら、
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を回転させるのでもよかった気がする。
が、あえてオブジェクトをすべて動かすことで、何か理解した気になった。