Blenderとか3DCGとか

スクリプト寄りです。

Blenderでワールドマトリクスからオブジェクトの軸方向を取得

2.79.6での検証です。2.8はまだ・・・
また、ボーンの扱いは特殊らしい?ので、未検証です。

取得対象

移動と回転をさせたキューブについて、各軸の方向を取得する方法の紹介です。

f:id:masayuki-osaka-blend:20190108134008p:plain
確認し易くするために、Axis(とName)をオンにしています

ワールドマトリクスとは

オブジェクトに親子関係がある場合、各オブジェクトのlocation, rotation, scaleへは、親との相対的な値が入っています。それに対し、親子関係を無視した(親子関係を解消した場合に相当する)状態を表すものをワールドマトリクスといいます。これを利用して、オブジェクトのXYZ軸がどの方向を向いているのかが取得できます。
 ワールドマトリクスを取得するには以下のコードを実行します("Cube"の例)。

import bpy
# Cubeのオブジェクトを取得
obj = bpy.data.objects["Cube"]
# Cubeのワールドマトリクスを取得
matrix_world = obj.matrix_world
# 取得したマトリクスを表示
print(matrix_world)

表示結果はシステムコンソールに表示されるので、確認するにはToggle System Console(システムコンソール切替)を押しておく必要があります。
f:id:masayuki-osaka-blend:20190108172751p:plain

マトリクスの読み方

f:id:masayuki-osaka-blend:20190108172353p:plain
Blenderのマトリクスは、左端の縦(一列目)がX軸の方向を表します。同様に二列目がY軸、三列目がZ軸の方向を表します。
 それぞれ上から順に、原点から見た各軸のx, y, zの座標を示します。 f:id:masayuki-osaka-blend:20190108180351p:plain
例えばこのキューブのX軸の向きは、原点から見て
  x=0.7272, y=-0.6838, z=-0.0602
の方向を向いたベクトルと並行だということになります。

なお、四列目は位置のワールド座標を表しており、
  x=1.5527, y=-0.5653, z=3.1395
の場所にこのキューブがあることを示しています。

マトリクスの一番下の行は、とりあえず無視してください。

プログラム上で取得しやすくする

マトリクスは横の一行ごとに抽出することができ、 以下のコードを実行すると各列を抜き取れます。

import bpy
obj = bpy.data.objects['Cube']
matrix_world = obj.matrix_world
print(matrix_world)
print(matrix_world[0])  # 最初の行を取得して表示
print(matrix_world[1])  # 2行目を表示
print(matrix_world[2])  # 3行目を表示
print(matrix_world[3])  # 最後の行を表示

f:id:masayuki-osaka-blend:20190108191309p:plain
ところが、Blenderでは各軸の情報が縦に並んでいるため、この方法では軸の情報が取得できません。 例えば二行目は、各軸の向きと位置のうち、y座標を並べたものが表示されてしまいます。
f:id:masayuki-osaka-blend:20190108210418p:plain
そこで以下のコードで、マトリクスの縦と横を入れ替えます

import bpy
obj = bpy.data.objects['Cube']
matrix_world = obj.matrix_world
print('---matrix_world---')
print(matrix_world)
# 縦と横を入れ替える(transpose)
transposed_matrix = matrix_world.transposed()
print('---transposed---')
print(transposed_matrix)  # 縦と横を入れ替えたマトリクスを表示

f:id:masayuki-osaka-blend:20190108223844p:plain
各軸の情報が横に並ぶようになります


 今回は軸の方向を調べるのが目的なので、四列目と四行目は不要になります。次のコードは縦横を入れ替えたマトリクスを三行三列だけにして、各行を表示させています。

import bpy
obj = bpy.data.objects['Cube']
matrix_world = obj.matrix_world
# 縦と横を入れ替える(transpose)
transposed_matrix = matrix_world.transposed()
print('---transposed---')
print(transposed_matrix)  # 縦と横を入れ替えたマトリクスを表示
# 3行3列に絞る(4行目、4列目を捨てる)
transposed_3x3 = transposed_matrix.to_3x3()
print('---transposed 3x3---')
print(transposed_3x3)  # 3行3列にしたマトリクスを表示
# 各行を表示
print(transposed_3x3[0])  # X軸の方向を表示
print(transposed_3x3[1])  # Y軸の方向を表示
print(transposed_3x3[2])  # Z軸の方向を表示

f:id:masayuki-osaka-blend:20190108225645p:plain
これで各軸の方向を取得することができました。

確認する

各軸の向きが取得できたので、その向きがあっているかを確認してみます。
 下の図は、3つのEmptyを作成して名前を変え、取得した座標を各locationへ入力、それを原点のEmptyの子供にしたものです。
f:id:masayuki-osaka-blend:20190108233123p:plain
原点の親EmptyをCubeと同じ場所にすることで、Cubeの座標表示と各ロケータの位置が揃うことが確認できます。
f:id:masayuki-osaka-blend:20190108233856p:plain

あとがき

カメラの向いている方向を取得する必要があり、調べた副産物を記事にしてみました。

 カメラの視線方向は取得したZ軸の方向に対して、各xyz座標値に-1を掛けた向き(=Z軸のマイナスの向き)になります。
 今回の例では、"Cube"の代わりに"Camera"だったとして、取得したZ軸の向きが
 x=-0.2276, y=-0.3230, z=0.9186
でしたので、カメラの視線方向は
 x=0.2276, y=0.3230, z=-0.9186
となります。

 Mayaでは「カメラの視線方向を取得」というそのものな命令があるのですが、Blenderでは見当たらなかったので入り用でしたらご参照ください。(ひょっとしたらあるのかも・・・)

 あと、Mayaでワールドマトリクスを取得した場合、今回の「縦と横を入れ替えたマトリクス」と同等のものが取得されます。Blenderのように各軸の向きを縦並びにするケースをcolumn-major order、Mayaのように横並びにするものをrow-major orderと呼ぶそうで、アプリケーションによって違いがあるようです。
 カメラの視線方向はBlenderもMayaも「マイナスZ方向」なのは変わりません。なぜマイナスなのだろう・・・