blender bpyでops系が遅いのはわかってるがdata系ではmesh、bmesh、Matrix・・・どれが早いのか実際に調べてみた
簡単に立方体をグローバルY方向に3移動を100回繰り返す
長いので最初に結論。
・オブジェクトモードならobj.locationとmatrix_world.translationを使うと良い
・原点の位置を変えずに全体の形を変形させたい場合はMatrixローカル座標)が早い
・編集モードのみの頂点移動はmeshよりbmeshが早い
・オブジェクトが沢山ある場合はmeshかオブジェクトモードでのbmeshを使うと良い
・編集モードとオブジェクトモードを行き来するのも結構時間がかかる
ops.transform.translate→0.01秒
obj.location→0.0001
matrix_world.translation→0.0002秒
mesh→0.001秒
bmesh(編集モード)→0.0004秒
bmesh(編集モードとオブジェクトモードを行き来した)→0.04秒
bmesh(オブジェクトモード)→0.004秒
編集モードとオブジェクトモードを行き来しただけ→0.04秒
以下詳細
ops系
import bpy ,time start = time.time() for i in range(0,100): bpy.ops.transform.translate(value=(0, 3, 0), orient_type='GLOBAL') end =time.time() elapsed_time = end - start print(elapsed_time)
結果 0.010007858276367188
0.01秒
data系(obj.location)
import bpy ,time start = time.time() obj = bpy.context.object for i in range(0,100): obj.location.y = (i+1)*3 end =time.time() elapsed_time = end - start print(elapsed_time)
結果 0.0
測定されないので100回から1万回に変更したらやっと測定された。
0.010066747665405273/100で
0.0001秒
つまりopsの100倍速い。
data系(Matrix)
import bpy ,time start = time.time() from mathutils import Matrix obj = bpy.context.object for i in range(0,100): obj.matrix_world.translation.y=(i+1)*3 end = time.time() elapsed_time = end - start print(elapsed_time)
結果 0.0
公平に最初にmathutilsをインポートする時間も測定。
測定されないので100回から1千回に変更したら測定された。
0.001949310302734375/10で
0.0002秒
opsの52倍
locationより2倍遅いがインポートの時間も微小と思われるので良さそう
data系(Matrixローカル座標)
import bpy,time start = time.time() from mathutils import Matrix,Vector context = bpy.context obj = context.object msh = obj.data for i in range(0,100): inv = obj.matrix_world.inverted() Tr = Matrix.Translation(inv@Vector((0,3,0))) msh.transform(Tr) end = time.time() elapsed_time = end - start print(elapsed_time)
結果
千回で測定
0.0020112991333007812/10
0.0002秒
Matrix.Translationは原点は動かないのでmeshやbmeshと同じ。
原点を移動せずに全体の形を変えたい時はこれが早い
data系(mesh)
ローカル座標のみの移動
import bpy ,time start = time.time() obj = bpy.context.object msh = obj.data for i in range(0,100): for v in msh.vertices: v.co.y = v.co.y + 3 end = time.time() elapsed_time = end - start print(elapsed_time)
結果
千回にしたら測定された
0.010063648223876953/10
0.001秒
グローバル座標に変換しつつ移動。
import bpy ,time start = time.time() from mathutils import Matrix,Vector obj = bpy.context.object inv = obj.matrix_world.inverted() msh = obj.data for i in range(0,100): for v in msh.vertices: v.co = v.co + inv @ Vector((0,3,0)) end = time.time() elapsed_time = end - start print(elapsed_time)
結果
千回にして測定された
0.010052680969238281/10
0.001秒
matrix_worldを使用しているのでその分遅くはなるがもともとが0.001秒、matorixが0.00019秒なので微小。
data系(bmesh)
import bpy ,time start = time.time() import bmesh bpy.ops.object.mode_set(mode='EDIT') obj = bpy.context.object msh = obj.data bm=bmesh.from_edit_mesh(msh) for i in range(0,100): for v in bm.verts: v.co.y = v.co.y + 3 bpy.ops.object.mode_set(mode='OBJECT') end = time.time() elapsed_time = end - start print(elapsed_time)
結果
一万回で以下略。
0.035222530364990234/100
0.0004秒
meshよりbmeshのほうが早くて驚いた。
しかし、bmeshはオブジェクトモードと編集モードを行き来する必要があるのでそこも割と時間がかかると思われる。
import bpy ,time start = time.time() for i in range(0,100): bpy.ops.object.mode_set(mode='EDIT') bpy.ops.object.mode_set(mode='OBJECT') end = time.time() elapsed_time = end - start print(elapsed_time)
結果
0.04009270668029785
0.04秒なのでまとめて作業する必要ある。
編集モードとオブジェクトモードを行き来しつつbmeshで移動
import bpy ,time start = time.time() import bmesh obj = bpy.context.object msh = obj.data for i in range(0,100): bpy.ops.object.mode_set(mode='EDIT') bm = bmesh.from_edit_mesh(msh) for v in bm.verts: v.co.y = v.co.y + 3 bpy.ops.object.mode_set(mode='OBJECT') end = time.time() elapsed_time = end - start print(elapsed_time)
結果 0.04002857208251953
0.04秒
まあ、こんな感じかな・・・。
同じくbmeshで編集モードに移動しなくても出来る方法でやってみた。
(たくさんのオブジェクトを行き来する想定)
import bpy ,time start = time.time() import bmesh for i in range(0,100): obj = bpy.context.object msh=obj.data bm = bmesh.new() bm.from_mesh(obj.data) for v in bm.verts: v.co.y = v.co.y + 3 bm.to_mesh(msh) bm.free() end = time.time() elapsed_time = end - start print(elapsed_time) bpy.context.view_layer.update()
結果
0.003983259201049805
0.004秒
沢山のオブジェクトを行き来する場合ならこちらが圧倒的に早い。