3D オブジェクトの頂点・辺・面の選択【第 10 回 Python × Blender】

bmeshオブジェクトから頂点(vertex)・辺(edge)・面(face)のいくつかを個別に選択するにはBMesh.verts, BMesh.edges, BMesh.facesのブール値を変更します。



以下は正十二面体オブジェクトを定義して配置し、そのうちいくつかの頂点・辺・面を選択する Python サンプルスクリプトです。

import bpy
import bmesh
import math


'''数学定数.'''
# 黄金比.
phi = (1 + math.sqrt(5))/2


'''オブジェクトモードから始めなければなりません. scene が empty(空)であるときスクリプトは動きません.'''
# オブジェクトモードに変更.
bpy.ops.object.mode_set(mode='OBJECT')
# 全てのオブジェクトを選択.
bpy.ops.object.select_all(action='SELECT')
# 選択された全てのオブジェクトを削除.
bpy.ops.object.delete()


'''正十二面体オブジェクトを作成し, 編集モードに切り替えます.'''
# 正十二面体の頂点リスト. 座標で定義し, 頂点番号はリストインデックスと一致.
verts = [(1 / phi, 0, phi), (-1 / phi, 0, phi), (1, 1, 1), (-1, 1, 1), (-1, -1, 1), (1, -1, 1), (0, phi, 1 / phi), (0, -phi, 1 / phi), (phi, 1 / phi, 0), (-phi, 1 / phi, 0), (-phi, -1 / phi, 0), (phi, -1 / phi, 0), (0, phi, -1 / phi), (0, -phi, -1 / phi), (1, 1, -1), (-1, 1, -1), (-1, -1, -1), (1, -1, -1), (1 / phi, 0, -phi), (-1 / phi, 0, -phi)]
# 正二十面体の面リスト.
faces = [(0, 2, 6, 3, 1), (0, 1, 4, 7, 5), (0, 5, 11, 8, 2), (2, 8, 14, 12, 6), (3, 6, 12, 15, 9), (1, 3, 9, 10, 4), (4, 10, 16, 13, 7), (5, 7, 13, 17, 11), (8, 11, 17, 18, 14), (12, 14, 18, 19, 15), (9, 15, 19, 16, 10), (13, 16, 19, 18, 17)]
# 正十二面体メッシュの定義.
meshes = bpy.data.meshes.new("Dodecahedron")
# 正十二面体オブジェクトの定義.
dodeca = bpy.data.objects.new("Dodecahedron", meshes)
# 正十二面体オブジェクトの位置を宣言.
dodeca.location = bpy.context.scene.cursor_location
# scene に正十二面体オブジェクトを追加.
bpy.context.scene.objects.link(dodeca)
# メッシュを生成.
meshes.from_pydata(verts, [], faces)
# 正十二面体の辺を生成.
meshes.update(calc_edges=True)
# 正十二面体オブジェクトをアクティブ化.
bpy.context.scene.objects.active = bpy.data.objects["Dodecahedron"]
# 編集モードに切り替え.
bpy.ops.object.mode_set(mode='EDIT')


'''正十二面体オブジェクトの頂点・辺・面の選択.'''
# 見易さのために面モード(Face Mode)に切り替え.
bpy.ops.mesh.select_mode(type="FACE")
# bmesh オブジェクトのインスタンス化.
dodeca_bmesh = bmesh.from_edit_mesh(bpy.context.object.data)
# 全ての頂点・辺・面を非選択状態にする.
bpy.ops.mesh.select_all(action='DESELECT')
# 面番号 0 の面を選択.
dodeca_bmesh.faces.ensure_lookup_table()
dodeca_bmesh.faces[0].select = True
# 辺番号 1 の辺を選択.
dodeca_bmesh.edges.ensure_lookup_table()
dodeca_bmesh.edges[1].select = True
# 頂点番号 8 の辺を選択.
dodeca_bmesh.verts.ensure_lookup_table()
dodeca_bmesh.verts[8].select = True

以上のスクリプトを実行すると、実行結果はだいたい以下のようになるでしょう。
f:id:tamaki_py:20190603190105p:plain
実際にいくつかの面と辺が選択されていることがオレンジのハイライトで分かります。



注意していただきたいのは、上記のサンプルスクリプトインスタンス化されたbmeshオブジェクトであるdodeca_bmeshの頂点・辺・面のいくつかを選択する際に、ensure_lookup_table()を多用しているところです。



この理由は前回のbmeshオブジェクトのインスタンス化の話に関連しています。
tamaki-py.hatenablog.com
このように各選択操作毎にensure_lookup_table()を呼ばないと、前回お伝えしたようにインスタンス化されたbmeshオブジェクトはメモリと計算量を食うので、ガベージコレクタが率先してそのbmeshオブジェクトを削除しようとしてしまうからです。



このensure_lookup_table()を呼び忘れると、以下のようなエラーがターミナルに出てくるはずです。

IndexError: BMElemSeq[index]: outdated internal index table, run ensure_lookup_table() first

また上記サンプルコードで、編集モードに切り替えた後bpy.ops.mesh.select_mode(type="FACE")コマンドで面モード(Face Mode)というメッシュ選択モードに入っていることがわかると思います。



メッシュ選択モードは他にも、頂点モード(Vert Mode)辺モード(Edge Mode)があります。



Blender のインターフェース上では 3D Viewport のヘッダーを右にスクロールしていくと見つかる以下のアイコンで、これら 3 つのメッシュ選択モードを切り替えることができます。
f:id:tamaki_py:20190603192937p:plain



左から頂点モード(Vert Mode)・辺モード(Edge Mode)・面モード(Face Mode)となっています。
f:id:tamaki_py:20190603193027p:plain
今回はこれらのメッシュ選択モードに関して詳しくは述べませんが、面モードでは頂点・辺・面 3 種類のメッシュを同時に選択表示することができるので、今回ではこのモードにしているというだけです。