bmeshのデータ更新について調べてみた。
オブジェクトモードと編集モードでは更新タイミングが違うので要注意。
長くなるので結論だけ先に書く
##################################
オブジェクトモードで使う場合
命令文:
bm = bmesh.new() bm.from_mesh(plane.data)
3dビューから手動及びbpy.opy系を使って頂点を変更したときは以下が必要
編集モードやオブジェクトモードに行っても更新されないでデータも壊れないし何も起きない
plane.data.update() bm = bmesh.new()
pythonコンソールから頂点データを編集した場合は
bm.to_mesh(plane.data)
を使わないと実際のオブジェクトには反映されない
(データを色々いじった後に最後に実行するといい)
################################
#####################
編集モードの場合
命令文:
bm = bmesh.from_edit_mesh(plane.data)
3Dビューから手動で変更後は即データが更新される
bpy.ops系使っても即時更新される
pythonコンソールからの変更も即時更新
(画面表示はオブジェクトモードになってから更新される)
loopsも読み取り専用とあるが
bm.faces[0].loops[8].vert.co.x=5
のように即時更新
#######################
以下実験結果
オブジェクトモードで使った場合
plane = bpy.context.object #bmshをオブジェクトモードのまま使う bm = bmesh.new() bm.from_mesh(plane.data) bm.verts.ensure_lookup_table() ff=bm.copy() ff.verts.ensure_lookup_table() #頂点の座標を表示 print("ff : ", ff.verts[0].co) print("bm : ", bm.verts[0].co)
結果
ff :
bm :
copy()したffもensure_lookup_table()が必要。面倒。
その後手動で頂点を動かす
(infoにはbpy.ops.bpy.ops.transform.translateが表示されてるのでbpy.opsを使ったのと同等?)
移動した頂点位置は(0,0,0)になってるはずだけど取れた値は最初と変わらない。
ff :
bm :
bmeshで頂点を変更した際に使うbm.to_mesh(plane.data)を使ってみても変化なし
ffもbmも頂点データをコピーしてるだけで内容が更新されないのかもしれない。
bm.from_mesh(plane.data) bm.verts.ensure_lookup_table() #頂点の座標を表示 print("ff : ", ff.verts[0].co) print("bm : ", bm.verts[0].co)
更新されてない
ff :
bm :
bm.free() print("ff : ", ff.verts[0].co) print("bm : ", bm.verts[0].co)
結果
ff :
bmの方は当然bmeshがないよというエラーになる
Traceback (most recent call last):
File "
ReferenceError: BMesh data of type BMesh has been removed
bm.from_mesh(plane.data) bm.verts.ensure_lookup_table() print("ff : ", ff.verts[0].co) print("bm : ", bm.verts[0].co)
結果
ff :
ffのprint以外はすべてエラー
plane = bpy.context.object #bmshをオブジェクトモードのまま使う bm = bmesh.new() bm.from_mesh(plane.data) bm.verts.ensure_lookup_table() #頂点の座標を表示 print("ff : ", ff.verts[0].co) print("bm : ", bm.verts[0].co)
結果
ff :
bm :
どういう事だってばよ。全く更新されてない
てかここでオブジェクトをオブジェクトモード→エディットモード→オブジェクトモードに戻すと元の形に戻った。
どういう事だってばよ...
plane.data.update() bm.from_mesh(plane.data) bm.verts.ensure_lookup_table() #頂点の座標を表示 print("ff : ", ff.verts[0].co) print("bm : ", bm.verts[0].co)
結果
ff :
bm :
変わらない
plane.data.update() bm = bmesh.new() bm.from_mesh(plane.data) bm.verts.ensure_lookup_table() #頂点の座標を表示 print("ff : ", ff.verts[0].co) print("bm : ", bm.verts[0].co)
結果
ff :
bm :
更新された
結論
オブジェクトモードでbmesh使ってる時に3dビューで手動(bps.ops系も?)使ったら
plane.data.update() bm = bmesh.new()
が必要・・・
疲れた...bm.from_mesh(plane.data)にある通りplane.dataをplane.data.update()で更新してあげないとダメでかつbmもbm = bmesh.new()でおニューにしてあげないといけないのね、わかった。
pythonコンソールから変更した場合
print("saisyo",bm.verts[0].co.y) bm.verts[0].co.y=0 print("mae : ",bm.verts[0].co.y) bm.to_mesh(plane.data) print("ato : ",bm.verts[0].co.y)
結果
saisyo 5.0
mae : 0.0
ato : 0.0
データーが変わってるのはmaeだけど実際オブジェクトに反映されてるのは
bm.to_mesh(plane.data)
した後なので要注意
編集モードの場合
こっちはたぶん超楽だと思われ。
bpy.ops.object.mode_set(mode='EDIT') plane=bpy.context.object bm = bmesh.from_edit_mesh(plane.data) bm.verts.ensure_lookup_table() ff=bm.copy() ff.verts.ensure_lookup_table() #頂点の座標を表示 print("ff : ", ff.verts[0].co) print("bm : ", bm.verts[0].co)
結果
ff :
bm :
その後手動で頂点を移動
print("ff : ", ff.verts[0].co) print("bm : ", bm.verts[0].co)
結果
ff :
bm :
即変更が反映されている
pythonコンソール側での更新
bm.verts[0].co.y=0 print(bm.verts[0].co.y)
結果
0.0
画面には反映されないがオブジェクトには反映されている様子。
(カーソルを持って行ったりすると画面が更新される)
bpy.ops.transform.translate(value=(0, 5, 0), ....を使っても
print(bm.verts[0].co.y)
結果
5
即時更新される