アストラルプリズム

PC、スマホ、ゲームなどの備忘録と日記

Blender bpy Marix_worldでオブジェクトを操る

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)

辺の向きを軸の向きにそろえる

f:id:katsumi3:20200418164640p:plain
ある辺の向きを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