Matrixを使ってオブジェクトを操る
グローバル座標での移動
正直言うとグローバル座標ではobj.location、obj.rotation、obj.scaleを使った方が楽だし早い。
グローバル座標でオブジェクトをZ方向に1移動する
obj.location = obj.location + Vector((0,0,1))
と同じ
import bpy from mathutils import Matrix obj = bpy.context.object mat = obj.matrix_world Tr = Matrix.Translation((0, 0, 1)) obj.matrix_world = Tr @ mat
ローカル座標の方向にグローバル値でグローバル空間を移動
(原点も一緒に移動する)
bpy.ops.transform.translate(value=val, orient_type='LOCAL', orient_matrix_type='GLOBAL')
と同じ
import bpy from mathutils import Vector, Matrix obj = bpy.context.object a = 0 b = 0 c = 1 val=[a,b,c] msh = obj.data va = [d/s for d,s in zip(val,obj.scale)] mat = obj.matrix_world obj.location = mat @ Vector(va)
グローバル座標でオブジェクトを10°、20°、30°回転させる
obj.rotation_euler = (obj.rotation_euler[0]+radians(10), obj.rotation_euler[1]+radians(20), obj.rotation_euler[2]+radians(30))
と同じ
回転の時だけやけに面倒
import bpy from mathutils import Matrix,Euler from math import radians obj = bpy.context.object mat = obj.matrix_world rot = [10,20,30] orig_loc,orig_rot,orig_scale = mat.decompose() new_rot = [o+radians(n) for o,n in zip (orig_rot.to_euler(),rot)] orig_loc_mat = Matrix.Translation(orig_loc) orig_rot_mat = orig_rot.to_matrix().to_4x4() new_rot_mat = Euler((new_rot),'XYZ').to_matrix().to_4x4() orig_scale_mat = (Matrix.Scale(orig_scale[0],4,(1,0,0)) @ Matrix.Scale(orig_scale[1],4,(0,1,0)) @ Matrix.Scale(orig_scale[2],4,(0,0,1))) obj.matrix_world = orig_loc_mat @ new_rot_mat @ orig_scale_mat
拡大縮小
オブジェクトのx軸を4倍、y軸を5倍、z軸を6倍にする
obj.scale = (obj.scale[0]*4,obj.scale[1]*5,obj.scale[2]*6)と同じ
import bpy from mathutils import Matrix sc = [4,5,6] obj = bpy.context.object mat = obj.matrix_world new_scale_mat = (Matrix.Scale(sc[0],4,(1,0,0)) @ Matrix.Scale(sc[1],4,(0,1,0)) @ Matrix.Scale(sc[2],4,(0,0,1))) obj.matrix_world = mat @ new_scale_mat
#指定した位置を基準に拡大縮小をする
bpy.ops.transform.resize(
value = trans_val,
orient_type='LOCAL',
center_override = zero_p)
と同じ。
import bpy from mathutils import Vector, Matrix ppp = bpy.context.object mat_ppp = ppp.matrix_world zero_p = mat_ppp @ ppp.data.vertices[0].co lo_zero_p = ppp.data.vertices[0].co trans_val = Vector((2,3,4)) new_scale_mat = (Matrix.Scale(trans_val[0],4,(1,0,0)) @ Matrix.Scale(trans_val[1],4,(0,1,0)) @ Matrix.Scale(trans_val[2],4,(0,0,1))) ppp.matrix_world = mat_ppp @ new_scale_mat new_p = zero_p-ppp.matrix_world @ lo_zero_p ppp.location = ppp.location + new_p #matorixではなくスケールで変更してた場合はupdate()の必要あり。 bpy.context.object.scale = [sca[0] * trans_val[0] , sca[1] * trans_val[1] , sca[2] * trans_val[2]] bpy.context.view_layer.update() dist = zero_p - ppp.matrix_world @ lo_zero_p ppp.location = ppp.location + dist
指定した位置を基準に拡大縮小をする
メッシュ内で拡大縮小、倍数はグローバル値で向きにそった値
mukiで決めた方向に拡大縮小する
import bpy from mathutils import Vector, Matrix world_norm = Vector((0,0,1)) ppp = bpy.context.object msh = ppp.data mat_ppp = ppp.matrix_world zero_p = mat_ppp @ ppp.data.vertices[0].co lo_zero_p = ppp.data.vertices[0].co trans_val = Vector((2,3,4)) muki0 = mat_ppp @ msh.vertices[msh.loops[0].vertex_index].co muki1 = mat_ppp @ msh.vertices[msh.loops[1].vertex_index].co muki = (muki1-muki0).normalized() cro = muki.cross(world_norm).normalized() loc = ppp.location m = Matrix([ [muki.x, -cro.x, world_norm.x, loc.x], [muki.y, -cro.y, world_norm.y, loc.y], [muki.z, -cro.z, world_norm.z, loc.z], [0,0,0,1] ]) for v in msh.vertices: xx = (((m @ v.co).x) * trans_val[0]) yy = (((m @ v.co).y) * trans_val[1]) zz = (((m @ v.co).z) * trans_val[2]) v.co = m.inverted() @ Vector((xx,yy,zz)) xx = (((m @ lo_zero_p).x) * trans_val[0]) yy = (((m @ lo_zero_p).y) * trans_val[1]) zz = (((m @ lo_zero_p).z) * trans_val[2]) new_zero_p = m.inverted() @ Vector((xx,yy,zz)) dist = zero_p - (ppp.matrix_world @ new_zero_p) ppp.location = ppp.location + dist
せん断
あまり使うことがないので分からない
とりあえずこんなのもあるよって感じ。
obj = bpy.context.object msh = obj.data shear_mat = Matrix.Shear('XY', 4, (1, 1)) msh.transform(shear_mat)
辺の向きを軸の向きにそろえる
ある辺の向きをx軸の向きに平行にする
原点ごと(0,0,0)に移動する
import bpy from mathutils import Matrix #ループでの頂点の番号 loop_no = 5 plane = bpy.context.object msh = plane.data p_mat = plane.matrix_world.copy() norm = msh.polygons[0].normal mx_inv = p_mat.inverted() mx_norm = mx_inv.transposed().to_3x3() world_norm = mx_norm @ norm world_norm.normalize() #ループじゃない頂点の番号 vertex_no = msh.loops[loop_no].vertex_index muki0 = p_mat @ msh.vertices[vertex_no].co if loop_no + 1 == len(msh.loops): muki1 = p_mat @ msh.vertices[msh.loops[0].vertex_index].co else: muki1 = p_mat @ msh.vertices[msh.loops[loop_no + 1].vertex_index].co muki = (muki1 - muki0).normalized() cro = muki.cross(world_norm).normalized() loc = plane.location m = Matrix([[muki.x,-cro.x, world_norm.x, loc.x], [muki.y,-cro.y, world_norm.y, loc.y], [muki.z,-cro.z, world_norm.z, loc.z], [0, 0, 0, 1]]) new_mat = m.inverted() @ p_mat bpy.context.object.matrix_world = new_mat #頂点だけ移動・あるいは移動した頂点の位置だけ知りたい時 for v in msh.vertices: v.co = p_mat.inverted()@(new_mat @ v.co)
ローカル座標での移動
原点はそのままでオブジェクトだけが移動する
ローカル軸に沿ってzが1移動
import bpy from mathutils import Matrix obj = bpy.context.object mat = obj.matrix_world msh = obj.data Tr = Matrix.Translation((0, 0, 1)) #移動距離はグローバル値にしたい場合 Tr = Matrix.Translation((0*obj.scale[0] , 0*obj.scale[1] , 1*obj.scale[2])) msh.transform(Tr)
ノーマルの方向に移動
#移動量はグローバル、オブジェクトモード
#選択している面がノーマルの方向に移動
import bpy a = 0 b = 0 c = 5 import mathutils obj = bpy.context.object msh = obj.data va = mathutils.Vector((a,b,c)) mat = obj.matrix_world m = mat.copy() for p in msh.polygons: if p.select: norm = p.normal mx_inv = mat.inverted() mx_norm = mx_inv.transposed().to_3x3() world_norm = mx_norm @ norm world_norm.normalize() m[0][2] = world_norm[0] m[1][2] = world_norm[1] m[2][2] = world_norm[2] gro = m @ va lo = mx_inv @ gro for id in p.vertices: msh.vertices[id].co = msh.vertices[id].co + lo #オブジェクトごと移動する場合(原点も一緒に移動する場合) #オブジェクトモードで回転されたものに限る import bpy from mathutils import Vector, Matrix obj = bpy.context.object a = 0 b = 9 c = 1 val=[a,b,c] msh = obj.data va = [d/s for d,s in zip(val,obj.scale)] mat = obj.matrix_world m = mat.copy() norm = msh.polygons[0].normal mx_inv = mat.inverted() mx_norm = mx_inv.transposed().to_3x3() world_norm = mx_norm @ norm world_norm.normalize() m[0][2] = world_norm[0] m[1][2] = world_norm[1] m[2][2] = world_norm[2] obj.location = m @ Vector(va)
ローカル座標でオブジェクトを10°、20°、30°回転させる
ローカルな座標にそって回転
import bpy from mathutils import Matrix,Euler from math import radians obj = bpy.context.object msh = obj.data mat = obj.matrix_world rot = [10,20,30] orig_loc,orig_rot,orig_scale = mat.decompose() new_rot = [(o+radians(n)) for o,n in zip (orig_rot.to_euler(),rot)] #new_rot = [radians(n) for o,n in zip (orig_rot.to_euler(),rot)] orig_loc_mat = Matrix.Translation(orig_loc) orig_rot_mat = orig_rot.to_matrix().to_4x4() new_rot_mat = Euler((new_rot),'XYZ').to_matrix().to_4x4() orig_scale_mat = (Matrix.Scale(orig_scale[0],4,(1,0,0)) @ Matrix.Scale(orig_scale[1],4,(0,1,0)) @ Matrix.Scale(orig_scale[2],4,(0,0,1))) msh.transform(mat.inverted() @ new_rot_mat @ orig_scale_mat)
拡大縮小
オブジェクトのx軸を4倍、y軸を5倍、z軸を6倍にする
(倍数はグローバル値)
import bpy from mathutils import Matrix sc = [4,5,6] obj = bpy.context.object msh = obj.data mat = obj.matrix_world new_scale_mat = (Matrix.Scale(sc[0],4,(1,0,0)) @ Matrix.Scale(sc[1],4,(0,1,0)) @ Matrix.Scale(sc[2],4,(0,0,1))) msh.transform(new_scale_mat)
ノーマルの方向にオブジェクトを移動
移動量はグローバル量
編集モードで面の向きが変わっている場合
ノーマルの向きZは決まっているがその他の向きを決めてやる必要がある。
mukiがノーマルの方向と同じになってしまうとcrossの値が出ないので(ここではmuki→xの方向1,0,0にしようとした)要注意。
3Dビュー上のノーマルのxとyの向きは物体の長い方(どっちかわすれた)がXかYになる。
つまり状況によってノーマルのXとYの軸の向きが入れ替わるので要注意。
import bpy from mathutils import Vector, Matrix obj = bpy.context.object a = 0 b = 5 c = 5 val=Vector((a,b,c)) msh = obj.data va = Vector([d/s for d,s in zip(val,obj.scale)]) mat = obj.matrix_world m = mat.copy() norm = msh.polygons[0].normal mx_inv = mat.inverted() mx_norm = mx_inv.transposed().to_3x3() world_norm = mx_norm @ norm world_norm.normalize() msh = obj.data muki0 = mat @ msh.vertices[msh.loops[0].vertex_index].co muki1 = mat @ msh.vertices[msh.loops[1].vertex_index].co muki = (muki1-muki0).normalized() #muki = Vector((1,0,0)) cro = muki.cross(world_norm).normalized() loc = obj.location m = Matrix([ [muki.x, -cro.x, world_norm.x, loc.x], [muki.y, -cro.y, world_norm.y, loc.y], [muki.z, -cro.z, world_norm.z, loc.z], [0,0,0,1] ]) #別のオブジェクトをノーマルの向きにそって移動する場合 #bpy.data.objects['モンキー'].matrix_world = m #bpy.data.objects['モンキー'].location = m @ val #自分自身を移動させる場合(回転等必要がない) obj.location = m @ val
指定した辺をxyに平行になる様に回転させる
import bpy from mathutils import Vector, Matrix ppp = bpy.context.object msh = ppp.data mat_ppp = ppp.matrix_world norm = ppp.data.polygons[0].normal mx_inv = mat_ppp.inverted() mx_norm = mx_inv.transposed().to_3x3() world_norm = mx_norm @ norm world_norm.normalize() muki0 = mat_ppp @ msh.vertices[msh.loops[0].vertex_index].co muki1 = mat_ppp @ msh.vertices[msh.loops[1].vertex_index].co muki = (muki1-muki0).normalized() cro = muki.cross(world_norm).normalized() loc = ppp.location sca = ppp.scale m = Matrix([ [muki.x, -cro.x, world_norm.x, loc.x], [muki.y, -cro.y, world_norm.y, loc.y], [muki.z, -cro.z, world_norm.z, loc.z], [0,0,0,1] ]) Tr = Matrix.Translation(loc) Sc = (Matrix.Scale(sca[0],4,(1,0,0)) @ Matrix.Scale(sca[1],4,(0,1,0)) @ Matrix.Scale(sca[2],4,(0,0,1))) ppp.matrix_world=Tr @ m.inverted() @ mat_ppp ppp.matrix_world=mat_ppm msh.transform(m.inverted()@Tr@Sc) m.inverted()@mat_ppp@msh.vertices[3].co #オブジェクトを回転 ppp.matrix_world=Tr @ m.inverted() @ mat_ppp #メッシュを回転(拡大縮小のある場合は分からなかった) msh.transform(m.inverted()@ Tr) #座標を変換 m.inverted()@ mat_ppp @ msh.vertices[3].co @ Tr @Sc + loc