メッシュの細分【第 13 回 Python × Blender】

今回はメッシュの細分(subdivision)について書きたいと思います。



以下のサンプルスクリプトは、立方体のある面を細分するスクリプト例となっています。

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)
# 全ての頂点・辺・面を非選択状態にする.
bpy.ops.mesh.select_all(action='DESELECT')
# 面番号 0 の面を選択.
cube_bmesh.faces.ensure_lookup_table()
cube_bmesh.faces[0].select = True
# 面番号 0 の面を細分.
bpy.ops.mesh.subdivide(number_cuts=1)

実行結果は以下のように、0 番の面が細分されていることがわかるでしょう。
f:id:tamaki_py:20190608220745p:plain



ちなみにこの細分を正十二面体で行おうとすると失敗します。

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]


'''オブジェクトモードから始める必要がある.'''
# オブジェクトモードに変更.
bpy.ops.object.mode_set(mode='OBJECT')
# 全てのオブジェクトを選択.
bpy.ops.object.select_all(action='SELECT')
# 選択された全てのオブジェクトを削除.
bpy.ops.object.delete()
# 正二十面体の配置.
dodecahedron_add("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)
# 全ての頂点・辺・面を非選択状態にする.
bpy.ops.mesh.select_all(action='DESELECT')
# 面番号 0 の面を選択.
dodeca_bmesh.faces.ensure_lookup_table()
dodeca_bmesh.faces[0].select = True
# 面番号 0 の面を細分.
bpy.ops.mesh.subdivide(number_cuts=1)

実行結果は以下のように、0 番の面は細分されず、0 番の面の境界にある辺のみが細分されていることがわかるでしょう。
f:id:tamaki_py:20190608222405p:plain
こうなる理由はいろいろ調べてみたところ、Blender では 5 角形以上の面は n-gon と呼ばれ、これには上にあるような面細分のスクリプトbpy.ops.mesh.subdivide()が働かないからだそうです。



基本的に 3DCG モデリングでは 3 角形・4 角形を用いてモデリングしていくことが想定されているからなんだそうな。



詳しいことはこれから勉強していこうと思います。