2025年10月27日
2025年10月20日
ウェイトマップ値の決定方法について考えてみた その28
今回はペアレントされたオブジェクト上の点を1つの姿勢から他の姿勢に移す変換についてだ。
どんな姿勢でもその点が属しているオブジェクトのローカル座標値は変わらないので、まずもとになる姿勢の点のワールド座標値からローカル座標値に変換する変換を取得して、次にそのローカル座標値を姿勢変更後のワールド座標値に変換する変換を取得して、その2つの変換を順に合成すれば姿勢を変えた先の座標値に変換する変換になる。
例えば下のように2つのペアレントされたオブジェクトCube1とCube2があって、

最初の姿勢の緒元は以下のようになっていて、

これをこのように変えて姿勢を変えた場合、

ワールド座標はこのように変わるはずだ。

さっそくプログラムでやってみると、
import numpy as np
import math
def transform(tx,ty,tz,rx,ry,rz,scx,scy,scz):
rad = math.pi / 180
cx = math.cos(rx*rad)
sx = math.sin(rx*rad)
cy = math.cos(ry*rad)
sy = math.sin(ry*rad)
cz = math.cos(rz*rad)
sz = math.sin(rz*rad)
rotx = np.array([[1.0,0.0,0.0,0.0],
[0.0, cx, sx,0.0],
[0.0, -sx, cx,0.0],
[0.0,0.0,0.0,1.0]]
)
roty = np.array([[ cy,0.0,-sy,0.0],
[0.0,1.0,0.0,0.0],
[ sy,0.0, cy,0.0],
[0.0,0.0,0.0,1.0]]
)
rotz = np.array([[ cz,sz,0.0,0.0],
[ -sz, cz,0.0,0.0],
[0.0,0.0,1.0,0.0],
[0.0,0.0,0.0,1.0]]
)
trns = np.array([[1.0,0.0,0.0,0.0],
[0.0,1.0,0.0,0.0],
[0.0,0.0,1.0,0.0],
[ tx, ty, tz,1.0]]
)
scl = np.array([[scx,0.0,0.0,0.0],
[0.0,scy,0.0,0.0],
[0.0,0.0,scz,0.0],
[0.0,0.0,0.0,1.0]]
)
return scl @ rotz @ rotx @ roty @ trns
cube1_M0 = transform(0,0,0,0,60,-30,1,1,1)
cube2_M0 = transform(0,1.5,0,10,0,-10,1,1,1)
M0 = cube2_M0 @ cube1_M0
cube1_M1 = transform(0,0,0,45,30,0,1,1,1)
cube2_M1 = transform(0,1.5,0,-20,0,60,1,1,1)
M1 = cube2_M1 @ cube1_M1
M = np.linalg.inv(M0) @ M1
p0 = np.array([1.1773,2.5361,-1.0255])
p1 = np.append(p0,1.0) @ M
print('original:',p0)
print('transformed:',p1[:-1])これが実行結果。変換出来ている事がわかる。
original: [ 1.1773 2.5361 -1.0255] transformed: [-0.46398329 1.42950851 2.00973274]
続きはまた次回。
2025年10月06日
ウェイトマップ値の決定方法について考えてみた その27
前回のプログラムでradの定義が抜けていたので追加しておいた。
さて、今までやって来た座標変換はとあるアイテム上にある点の座標をそのアイテムのローカル座標系からアイテムが存在するワールド座標系の座標値に変換するものだ。
ローカル座標系(アイテムの内部で見れば)であればアイテムがどう移動・回転・縮尺されようとその位置に変化は無いが、ワールド座標系(アイテムの外から見れば)ではアイテムの動きや変形によってその中にある点の位置は変化して見える。
逆にある点を特定のアイテムのローカル座標系に変換するにはどうすればいいかと言えば、答えは簡単。今までやった変換の逆をやればいいだけだ。X軸に90度回転しているならば逆に−90度回転させれば元に戻るわけで、変換に使ったパラメータすべてを打ち消す値に置き換えて、スケール→回転→移動の順に変換していたので逆に移動→回転→スケールの順に変換してやればワールド座標からアイテムのローカル座標に変換できる。
そしてこの変換については行列にはそれを逆変換する逆行列が存在していてnumpyでは
numpy.linalg.inv(M)
で簡単に求められる。前回ワールド座標に変換した座標値を逆変換すると当たり前だけど元のローカル座標に戻ることが確認できる。
import numpy as np
import math
tx = -0.5
ty = 0.5
tz = 1.0
rx = -30.0
ry = 50.0
rz = -60.0
scx = 0.8
scy = 1.2
scz = 0.5
rad = math.pi / 180
cx = math.cos(rx*rad)
sx = math.sin(rx*rad)
cy = math.cos(ry*rad)
sy = math.sin(ry*rad)
cz = math.cos(rz*rad)
sz = math.sin(rz*rad)
rotx = np.array([[1.0,0.0,0.0,0.0],
[0.0, cx, sx,0.0],
[0.0, -sx, cx,0.0],
[0.0,0.0,0.0,1.0]]
)
roty = np.array([[ cy,0.0,-sy,0.0],
[0.0,1.0,0.0,0.0],
[ sy,0.0, cy,0.0],
[0.0,0.0,0.0,1.0]]
)
rotz = np.array([[ cz,sz,0.0,0.0],
[ -sz, cz,0.0,0.0],
[0.0,0.0,1.0,0.0],
[0.0,0.0,0.0,1.0]]
)
trns = np.array([[1.0,0.0,0.0,0.0],
[0.0,1.0,0.0,0.0],
[0.0,0.0,1.0,0.0],
[ tx, ty, tz,1.0]]
)
scl = np.array([[scx,0.0,0.0,0.0],
[0.0,scy,0.0,0.0],
[0.0,0.0,scz,0.0],
[0.0,0.0,0.0,1.0]]
)
m1 = scl @ rotz @ rotx @ roty @ trns
tx = 0.0
ty = 1.6
tz = 0.0
rx = 45.0
ry = 30.0
rz = 60.0
scx = 1.0
scy = 1.5
scz = 1.0
rad = math.pi / 180.0
cx = math.cos(rx*rad)
sx = math.sin(rx*rad)
cy = math.cos(ry*rad)
sy = math.sin(ry*rad)
cz = math.cos(rz*rad)
sz = math.sin(rz*rad)
rotx = np.array([[1.0,0.0,0.0,0.0],
[0.0, cx, sx,0.0],
[0.0, -sx, cx,0.0],
[0.0,0.0,0.0,1.0]]
)
roty = np.array([[ cy,0.0,-sy,0.0],
[0.0,1.0,0.0,0.0],
[ sy,0.0, cy,0.0],
[0.0,0.0,0.0,1.0]]
)
rotz = np.array([[ cz,sz,0.0,0.0],
[ -sz, cz,0.0,0.0],
[0.0,0.0,1.0,0.0],
[0.0,0.0,0.0,1.0]]
)
trns = np.array([[1.0,0.0,0.0,0.0],
[0.0,1.0,0.0,0.0],
[0.0,0.0,1.0,0.0],
[ tx, ty, tz,1.0]]
)
scl = np.array([[scx,0.0,0.0,0.0],
[0.0,scy,0.0,0.0],
[0.0,0.0,scz,0.0],
[0.0,0.0,0.0,1.0]]
)
m2 = scl @ rotz @ rotx @ roty @ trns
p = np.array([0.5,1.5,-0.5])
M = m2 @ m1
invM = np.linalg.inv(M)
p1 = np.append(p,1.0) @ M
p2 = p1 @ invM
print('original:',p)
print('world:',p1[:-1])
print('local',p2[:-1])original: [ 0.5 1.5 -0.5] world: [ 0.76227616 3.11999844 -1.51283819] local: [ 0.5 1.5 -0.5]
続きはまた次回。
2025年09月29日
ウェイトマップ値の決定方法について考えてみた その26
前回はアイテム1つの変換マトリクスを求めてみた。今回はさらにアイテムをペアレントした場合について見て行きたい。
結論から言えばペアレントされたアイテムの変換は親アイテムの変換がさらにかかるだけなので、変換マトリクスは親子2つのマトリクスの子→親の順の掛け算になる。

例えば上の図でCube1の緒元はこれで

Cube2はこのような設定だとして、

Cube2上の点Pがどのように変換されるかやってみると、

このようになって、
import numpy as np
import math
tx = -0.5
ty = 0.5
tz = 1.0
rx = -30.0
ry = 50.0
rz = -60.0
scx = 0.8
scy = 1.2
scz = 0.5
rad = math.pi / 180
cx = math.cos(rx*rad)
sx = math.sin(rx*rad)
cy = math.cos(ry*rad)
sy = math.sin(ry*rad)
cz = math.cos(rz*rad)
sz = math.sin(rz*rad)
rotx = np.array([[1.0,0.0,0.0,0.0],
[0.0, cx, sx,0.0],
[0.0, -sx, cx,0.0],
[0.0,0.0,0.0,1.0]]
)
roty = np.array([[ cy,0.0,-sy,0.0],
[0.0,1.0,0.0,0.0],
[ sy,0.0, cy,0.0],
[0.0,0.0,0.0,1.0]]
)
rotz = np.array([[ cz,sz,0.0,0.0],
[ -sz, cz,0.0,0.0],
[0.0,0.0,1.0,0.0],
[0.0,0.0,0.0,1.0]]
)
trns = np.array([[1.0,0.0,0.0,0.0],
[0.0,1.0,0.0,0.0],
[0.0,0.0,1.0,0.0],
[ tx, ty, tz,1.0]]
)
scl = np.array([[scx,0.0,0.0,0.0],
[0.0,scy,0.0,0.0],
[0.0,0.0,scz,0.0],
[0.0,0.0,0.0,1.0]]
)
m1 = scl @ rotz @ rotx @ roty @ trns
tx = 0.0
ty = 1.6
tz = 0.0
rx = 45.0
ry = 30.0
rz = 60.0
scx = 1.0
scy = 1.5
scz = 1.0
rad = math.pi / 180.0
cx = math.cos(rx*rad)
sx = math.sin(rx*rad)
cy = math.cos(ry*rad)
sy = math.sin(ry*rad)
cz = math.cos(rz*rad)
sz = math.sin(rz*rad)
rotx = np.array([[1.0,0.0,0.0,0.0],
[0.0, cx, sx,0.0],
[0.0, -sx, cx,0.0],
[0.0,0.0,0.0,1.0]]
)
roty = np.array([[ cy,0.0,-sy,0.0],
[0.0,1.0,0.0,0.0],
[ sy,0.0, cy,0.0],
[0.0,0.0,0.0,1.0]]
)
rotz = np.array([[ cz,sz,0.0,0.0],
[ -sz, cz,0.0,0.0],
[0.0,0.0,1.0,0.0],
[0.0,0.0,0.0,1.0]]
)
trns = np.array([[1.0,0.0,0.0,0.0],
[0.0,1.0,0.0,0.0],
[0.0,0.0,1.0,0.0],
[ tx, ty, tz,1.0]]
)
scl = np.array([[scx,0.0,0.0,0.0],
[0.0,scy,0.0,0.0],
[0.0,0.0,scz,0.0],
[0.0,0.0,0.0,1.0]]
)
m2 = scl @ rotz @ rotx @ roty @ trns
p = np.array([0.5,1.5,-0.5])
pd = np.append(p,1.0) @ m2 @ m1
print(pd[:-1])計算結果は実際のものと一致する。

続きはまた次回。