メッシュの押し出し【第 12 回 Python × Blender】

今日はメッシュの押し出し(extrude)について書きたいと思います。



今回のサンプルスクリプトは、正十二面体の面のいくつかを、その面の法線方向に押し出す Python スクリプトです。

import bpy
import bmesh


'''オブジェクトモードから始める必要がある.'''
# オブジェクトモードに変更.
bpy.ops.object.mode_set(mode='OBJECT')
# 全てのオブジェクトを選択.
bpy.ops.object.select_all(action='SELECT')
# 選択された全てのオブジェクトを削除.
bpy.ops.object.delete()
# 立方体オブジェクトを配置.
bpy.ops.mesh.primitive_cube_add(radius=0.5, location=(0, 0, 0))
# 編集モードに切り替え.
bpy.ops.object.mode_set(mode='EDIT')


'''立方体の面を全て押し出す.'''
# 見易さのために面モード(Face Mode)に切り替え.
bpy.ops.mesh.select_mode(type="FACE")
# bmesh オブジェクトのインスタンス化.
cube_bmesh = bmesh.from_edit_mesh(bpy.context.object.data)
# 立方体の面数(6 面)分ループ処理.
for i in range(6):
    # 全ての頂点・辺・面を非選択状態にする.
    bpy.ops.mesh.select_all(action='DESELECT')
    # 面番号 i の面を選択.
    cube_bmesh.faces.ensure_lookup_table()
    cube_bmesh.faces[i].select = True
    # 面番号 0 の面を法線方向に 1 押し出す.
    bpy.ops.mesh.extrude_region_move(TRANSFORM_OT_translate={"value": (0, 0, 1), "constraint_axis": (True, True, True),"constraint_orientation": 'NORMAL'})
# 最後にもう一度押し出す.
bpy.ops.mesh.extrude_region_move(TRANSFORM_OT_translate={"value": (0, 0, 1), "constraint_axis": (True, True, True),"constraint_orientation": 'NORMAL'})

実行結果は以下のようになるはずです。
f:id:tamaki_py:20190604234432p:plain



上記プログラムを見ると、bpy.ops.mesh.extrude_region_move(TRANSFORM_OT_translate={"value": (0, 0, 1), "constraint_axis": (True, True, True),"constraint_orientation": 'NORMAL'})によって選択状態にある面が法線方向に 1 ずらされているのが分かります。



立方体ではなく、正十二面体で遊んでみるとこうなります。

import bpy
import bmesh
import math


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


'''正十二面体を配置する関数.'''
def dodecahedron_add(name, location=(0, 0, 0)):
    # 正十二面体の頂点リスト. 座標で定義し, 頂点番号はリストインデックスと一致.
    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(name)
    # 正十二面体オブジェクトの定義.
    dodecahedron = bpy.data.objects.new(name, meshes)
    # 正十二面体オブジェクトの位置を宣言.
    dodecahedron.location = location
    # scene に正十二面体オブジェクトを追加.
    bpy.context.scene.objects.link(dodecahedron)
    # メッシュを生成.
    meshes.from_pydata(verts, [], faces)
    # 正十二面体の辺を生成.
    meshes.update(calc_edges=True)
    # 正十二面体オブジェクトをアクティブ化.
    bpy.context.scene.objects.active = bpy.data.objects[name]


'''scene が empty であるとき, スクリプトは動かないのでオブジェクトモードから始める必要がある.'''
# オブジェクトモードに変更.
bpy.ops.object.mode_set(mode='OBJECT')
# 全てのオブジェクトを選択.
bpy.ops.object.select_all(action='SELECT')
# 選択された全てのオブジェクトを削除.
bpy.ops.object.delete()
# 正十二面体オブジェクトを配置.
dodecahedron_add(name="Dodeca.1")
# 編集モードに切り替え.
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)
# 正十二面体の面数(12 面)分ループ処理.
for i in range(12):
    # 全ての頂点・辺・面を非選択状態にする.
    bpy.ops.mesh.select_all(action='DESELECT')
    # 面番号 i の面を選択.
    dodeca_bmesh.faces.ensure_lookup_table()
    dodeca_bmesh.faces[i].select = True
    # 面番号 i の面を適当に押し出す.
    bpy.ops.mesh.extrude_region_move(TRANSFORM_OT_translate={"value": (0, 0, 1), "constraint_axis": (True, True, True),"constraint_orientation": 'NORMAL'})
    bpy.ops.mesh.extrude_region_move(TRANSFORM_OT_translate={"value": (0.5, 0, 1), "constraint_axis": (True, True, True),"constraint_orientation": 'NORMAL'})
    bpy.ops.mesh.extrude_region_move(TRANSFORM_OT_translate={"value": (-0.5, 0, 1), "constraint_axis": (True, True, True),"constraint_orientation": 'NORMAL'})

実行結果は以下のようになるはずです。
f:id:tamaki_py:20190605001233p:plain
う〜ん、サンゴみたい🐟