アストラルプリズム

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

blender python アドオンの動きを軽くする

アドオンにいろんな機能をつけようと思うとどんどん重たくなってしまう。
実はbpy.ops系は重たいのだ・・・。

回避方法
・何でもかんでもモジュールを呼ばない
・アドオン使用時の数値入力するところを別の場所に作る
・bpy.ops系を使わない

何でもかんでもモジュールを呼ばない

importなにがしでいろんなの呼ぶのに時間がかかるのであんまり多用しないほうが良い
便利だけど。

アドオン使用時の数値入力するところを別の場所に作る

実際早くなるわけではないが体感的に違うと思う。
アドオン使用時に数値入力するあの黒いUIだと、数値を変更するたびにアドオンがお試し実行されてしまうので数値入力だけで重たく感じてしまう。
そこで別の場所にUIを作るとそういうのが回避されて、体感的に軽くなる。
黒い入力欄→Propertyクラスを使用
別の場所に作る→Panelクラス使用

bpy.ops系を使わない

代わりにbpy.data系でオブジェクトをいじって最後にまとめてコレクションにリンクするのが早い。
実際に実行時間を測ってみる
元のオブジェクトを100個複製

↓ bpy.ops

import bpy,time
start = time.time()
src_obj = bpy.context.active_object

for i in range(0,100):
    bpy.context.view_layer.objects.active = src_obj 
    src_obj.select_set(True)
    bpy.ops.object.duplicate()
    bpy.context.object.select_set(False)
end = time.time()
elapsed_time = end - start
print(elapsed_time)

↓data系

import bpy,time
start = time.time()
co = bpy.context.collection
src_obj = bpy.context.active_object

for i in range(0,100):
    new_obj  = src_obj.copy()
    new_obj.data = src_obj.data.copy()
    co.objects.link(new_obj)

end =time.time()
elapsed_time = end - start
print(elapsed_time)
結果

bpy.ops系 0.38秒
data系 0.078秒
bpy.ops系はdata系の5倍時間がかかる。

100個もコピーしないよと思うかもしれないが、アドオン起動時に黒い窓で入力すると少し重たいだけで結構イラっとくるので使っていきたい

↓その他data系で移動、複製、適用する方法はこっち
katsumi3.hatenablog.com


おまけ
せっかく100個もオブジェクトをコピーしたので100回全選択も比較してみたが

bpy.ops系 0.057秒
data系 0.026秒

二倍違う
こういうのの積み重ねでアドオンどんどん遅くなってるんだなと思った。
以下スクリプト
bpy.ops

import bpy,time
start = time.time()

for i in range(0,100):
    for obj in bpy.context.collection.objects:
        #bpy.context.view_layer.objects.active = obj
        obj.select_set(True)
        
    for obj in bpy.context.collection.objects:
        #bpy.context.view_layer.objects.active = obj
        obj.select_set(False)

end = time.time()
elapsed_time = end - start
print(elapsed_time)

↓data系

import bpy,time
start = time.time()

for i in range(0,100):
    for obj in bpy.context.collection.objects:
        obj.select_set(True)
        
    for obj in bpy.context.collection.objects:
        obj.select_set(False)

end = time.time()
elapsed_time = end - start
print(elapsed_time)