毎度毎度座標系のスクリプトを作ろうとして、ド忘れしてひどい目に合うので、分からないなりに考え方と手順を書く。
それぞれの辺の中心に面に垂直かつ面の外側に向かってモンキーを置きたい
図にするとこんな感じ。
手順
1、面の垂直方向を調べる
2、辺の外側の向きを調べる
3、辺の中心座標を調べる
4、モンキーの向いている方向を調べる
5、モンキーの置く場所と向きを決める
6、モンキーの位置の微調整
めんどくさいところ
・ローカル座標とグローバル座標の違い(トランスフォーム)で値がおかしくなる。
・マトリックスワールド等計算が面倒な場合は必要な数値をとる為だけに平面をコピペしてトランスフォームを適用し使用後は削除でもいいと思う(だが誤差が一番少ない方法が分からない)。
1、面の垂直方向を調べる
ノーマルの方向でわかる。
plane = bpy.context.object
p_mat = plane.matrix_world
msh = bpy.data.meshes[plane.data.name]
norm = msh.polygons[0].normal
#normalをグローバル座標にする
inv = p_mat.invert()
mat_norm = inv.transposed().to_3x3()
norm = mat_norm @ norm
norm.normalized()
トランスフォームを適用せずマトリックスワールドをかけた場合と適用しただけの場合誤差が少ないのは?
xを60度傾けた面で確認してみたがトランスフォームを適用せずのほうが誤差が少ない様だ。
2、辺の外側の向きを調べる
よくわからんけど辺の向きとノーマルにcrossってのを使うと辺の外側の向きが分かるらしい
辺の向き
・ローカル座標
muki = msh.vertices[1].co- msh.vertices[0].co
・グローバル座標
muki = mw @ msh.vertices[1].co - mw @ msh.vertices[0].co
xaxis = muki.normalized()
辺の外側の向き
cro = muki.cross(norm).normalized()
ノーマライズしないとモンキーに縮小拡大がついてしまう。
muki = muki.normalized()
辺の向きも同様にノーマライズ。
正直理屈が良く分からないorz
計算した値をまとめてマトリックスワールドと掛けた方が誤差が少ない気がするんだけど、まとめてやる方法がよくわからない。
外側の向きはこの図ではマイナスX方向になる
3、辺の中心座標を調べる
単純に数学的に調べるだけ
ローカル座標
loc = (msh.vertices[1].co + msh.vertices[0].co) / 2
グローバル座標
loc = (mw @ msh.vertices[1].co + mw @ msh.vertices[0].co) / 2
これはmwを
loc = mw @ ((msh.vertices[1].co + mw @ msh.vertices[0].co) / 2)
とまとめれるが他のはまとめると値が変わったりするので不用意にまとめると酷い目に会う。
4、モンキーの向きを確認する
モンキーを呼び出したときの向きを目視で確認しておく。
bpy.ops.mesh.primitive_monkey_add(enter_editmode=False, location=(0, 0, 0))
obj = bpy.context.object
モンキーはマイナスY方向が正面になっている。
ついでにモンキーの顔、標準で2mらしい。でかいな。
5、モンキーの置く場所と向きを決める
上の図から
・モンキーの横方向(X)は辺の向きに合わせたい
・モンキーの正面の方向(-Y)は辺のクロスの向きに合わせたい
・モンキーの頭の方向(Z)は平面のノーマルの方向に合わせたい
・辺の中心+モンキーのzの大きさ/2にモンキーを置きたい
以上をまとめてモンキー用のマトリックスワールドを作って入れておく
import mathutils
monkey_mw = mathutils.Matrix([
[muki.x, -cro.x, norm.x, loc.x],
[muki.y, -cro.y, norm.y, loc.y],
[muki.z, -cro.z, norm.z, loc.z],
[0,0,0,1]
])
モンキーの現在の位置のマトリックスワールドと移動後のマトリックスワールドを掛ける。
obj.matrix_world = bpy.context.selected_objects[0].matrix_world @ monkey_mw
6、モンキーの位置の微調整
ここまで出来た。あとちょっと。
モンキーをモンキーの頭の方向に1mほど持ち上げたい。
面の法線方向がZで辺の中心方向がXとして移動したい方向のベクトルを作る vec = mathutils.Vector((0,0,1))
inv = obj.matrix_world.copy()
inv.invert()
vec_rot = vec @ inv
obj.location = obj.location + vec_rot
ローカル座標=反転させたマトリックスワールド@グローバル座標
なので元の位置(obj.location
)にローカル座標にした移動量(vec_rot
)を足している
完成
モンキーを立体にして平面の内側におきたい時は
vec = mathutils.Vector((0,1,1))
とするといい。
参考 ローカル軸上でオブジェクトを移動する