オブジェクトの向きの取得

2010/3/31

Blender2.49

オブジェクトの向きはObj.orientationで取得するんだけど、それは3次行列を返してくる。この行列はx軸、y軸、z軸それぞれの基底ベクトルを云々かんぬんで、3Dにおいてよく使われる表現らしい。これの方が便利なそうだ。さっぱりわからん。

obj = GameLogic.getCurrentScene().objects["OBCube"]]
#ローカル
local = obj.localOrientation
#グローバル
world = obj.worldOrientation

obj.orientationは書き込み時にはworldの方で、読み込み時にはlocalらしい。非推奨。わかりずらいので使わないほうがよさそうだ。

Orientation Matrix - Basics
http://sites.google.com/site/socialstorage/orientationmatrix-basics

Orientation に関係するスレッド
http://blenderartists.org/forum/showthread.php?t=113172 http://blenderartists.org/forum/showthread.php?t=70111

使い方がわからんので、x,y,zをそれぞれ角度で受け取る方法はないもんかと。あった。

import Blender.Mathutils as Mathutils

~~~

o = obj.localOrientation
matrix = Mathutils.Matrix(o[0],o[1],o[2])
euler = matrix.transpose().toEuler()
rx,ry,rz = euler.x,euler.y,euler.z

transposeは転置?eulerはオイラー。オイラー角というのが普段いう角度のことらしい。

参考
http://blenderartists.org/forum/showthread.php?t=76936


角度から行列にするには

import Blender.Mathutils as`athutilss

~~~

euler = Mathutils.Euler(45, 0, 0)
orientation = euler.toMatrix().transpose()

参考
http://wiki.gameblender.org/index.php?title=Orientation


ちなみに、orientationの行列を角度x,y,zで表すと

| cos(y)cos(z)  sin(x)sin(y)cos(z)-cos(x)sin(z)  cos(x)sin(y)cos(z)+sin(x)sin(z) |
| cos(y)sin(z)  sin(x)sin(y)sin(z)+cos(x)cos(z)  cos(x)sin(y)sin(z)-sin(x)cos(z) |
| -sin(y)       sin(x)cos(y)                     cos(x)cos(y)                    |
こうなる。

これはx軸、y軸、z軸それぞれ回りに回転する変換行列の積を転置したものなんだけども、自分であの行列の正体はなんぞや?っと逆算的に考えた結果導き出されたものなので、根拠は説明できない。


つまるとこ、これによって何ができるかというと、所定の角度にしたい時には

import math

def setRotation(obj,rx,ry,rz,local=False):
    x = math.radians(rx)
    y = math.radians(ry)
    z = math.radians(rz)

    mat = [[0,0,0],[0,0,0],[0,0,0]]
    mat[0][0] = math.cos(y)*math.cos(z)
    mat[1][0] = math.cos(y)*math.sin(z)
    mat[2][0] = -math.sin(y)
    mat[0][1] = math.sin(x)*math.sin(y)*math.cos(z)-math.cos(x)*math.sin(z)
    mat[1][1] = math.sin(x)*math.sin(y)*math.sin(z)+math.cos(x)*math.cos(z)
    mat[2][1] = math.sin(x)*math.cos(y)
    mat[0][2] = math.cos(x)*math.sin(y)*math.cos(z)+math.sin(x)*math.sin(z)
    mat[1][2] = math.cos(x)*math.sin(y)*math.sin(z)-math.sin(x)*math.cos(z)
    mat[2][2] = math.cos(x)*math.cos(y)

    if local:
        obj.localOrientation = mat
    else:
        obj.worldOrientation = mat

こうできる。こう使うものじゃないと思うけど。

Class KX_GameObject localOrientation
http://www.blender.org/documentation/249PythonDoc/GE/GameTypes.KX_GameObject-class.html#localOrientation

The Matrix Object
http://www.blender.org/documentation/249PythonDoc/GE/Mathutils.Matrix-class.html

The Euler object
http://www.blender.org/documentation/249PythonDoc/GE/Mathutils.Euler-class.html



以下、向き用に書いた関数色々。

y軸周りにdegだけ回転したorientationを返す

def rotY(deg,orientation):
    # rotate y
    # | cos(y)  0 sin(y) |
    # |   0     1   0    |
    # | -sin(y) 0 cos(y) |
    l = orientation
    y = math.radians(deg)
    n = [[0,0,0],[0,0,0],[0,0,0]]
    n[0][0] = math.cos(y)*l[0][0] + math.sin(y)*l[2][0]
    n[0][1] = math.cos(y)*l[0][1] + math.sin(y)*l[2][1]
    n[0][2] = math.cos(y)*l[0][2] + math.sin(y)*l[2][2]
    n[1][0] = l[1][0]
    n[1][1] = l[1][1]
    n[1][2] = l[1][2]
    n[2][0] = -math.sin(y)*l[0][0] + math.cos(y)*l[2][0]
    n[2][1] = -math.sin(y)*l[0][1] + math.cos(y)*l[2][1]
    n[2][2] = -math.sin(y)*l[0][2] + math.cos(y)*l[2][2]
    return n