本日は Blender の技術調査枠です。
Blender2.8で利用可能なpythonスクリプトを作ります。
面の法線を元にした辺の設定
Z軸の法線方向が上向きの面と下向きの面の境界の辺にシーム/シャープ/クリース/ベベルを設定します。
最初に面の向きを元に面を選択し、辺に接続された一方の面のみ選択されている場合、境界と判断して辺を選択します。
その選択した辺に対してシーム/シャープ/クリース/ベベルの設定を行います。
・apply_mark_edges_Znormal.py
# bpyインポート import bpy # メッシュ操作のため import bmesh # Z軸の法線方向が上向きの面と下向きの面の境界の辺にシーム/シャープ/クリース/ベベルを設定する def mark_edges_Znormal(arg_objectname="Default", arg_seam=False, arg_sharp=False, arg_crease=False, arg_bevel=False) -> bool: """Z軸の法線方向が上向きの面と下向きの面の境界の辺にシーム/シャープ/クリース/ベベルを設定する Keyword Arguments: arg_objectname {str} -- [description] (default: {"Default"}) arg_seam {bool} -- シームの設定有無 (default: {False}) arg_sharp {bool} -- シャープの設定有無 (default: {False}) arg_crease {bool} -- クリースの設定有無 (default: {False}) arg_bevel {bool} -- ベベルの設定有無 (default: {False}) Returns: bool -- 実行正否 """ # 指定オブジェクトを取得する # (get関数は対象が存在しない場合 None が返る) selectob = bpy.data.objects.get(arg_objectname) # 指定オブジェクトが存在するか確認する if selectob == None: # 指定オブジェクトが存在しない場合は処理しない return False # オブジェクトがメッシュであるか確認する if selectob.type != 'MESH': # 指定オブジェクトがメッシュでない場合は処理しない return False # 不要なオブジェクトを選択しないように # 全てのオブジェクトを走査する for ob in bpy.context.scene.objects: # 非選択状態に設定する ob.select_set(False) # 指定のオブジェクトのみを選択状態にする selectob.select_set(True) # 対象オブジェクトをアクティブに変更する bpy.context.view_layer.objects.active = selectob # 編集モードに移行する # モード切替のマニュアル # (https://docs.blender.org/api/current/bpy.ops.object.html#bpy.ops.object.mode_set) bpy.ops.object.mode_set(mode='EDIT', toggle=False) # メッシュデータを取得する # メッシュアクセスのマニュアル # (https://docs.blender.org/api/current/bmesh.types.html?highlight=bmedge#bmesh.types.BMesh) meshdata = bmesh.from_edit_mesh(selectob.data) # 選択モードを面選択モードにする meshdata.select_mode = {'FACE'} # 一度選択を全てクリアする bpy.ops.mesh.select_all(action='DESELECT') # 辺または面の選択状態を更新する meshdata.select_flush_mode() # 辺または面を操作する場合はテーブルを更新する meshdata.verts.ensure_lookup_table() # 辺を走査する # 面アクセスのマニュアル # (https://docs.blender.org/api/current/bmesh.types.html?highlight=bmedge#bmesh.types.BMFace) for face in meshdata.faces: # 指定の数の面を選択する if face.normal[2] > 0.0: # 面を選択状態にする face.select_set(True) else: # 面を非選択状態にする face.select_set(False) # メッシュデータを取得する # メッシュアクセスのマニュアル # (https://docs.blender.org/api/current/bmesh.types.html?highlight=bmedge#bmesh.types.BMesh) meshdata = bmesh.from_edit_mesh(selectob.data) # 選択モードを面選択モードにする meshdata.select_mode = {'EDGE'} # 辺または面の選択状態を更新する meshdata.select_flush_mode() # 辺または面を操作する場合はテーブルを更新する meshdata.verts.ensure_lookup_table() # 辺を走査する # 辺アクセスのマニュアル # (https://docs.blender.org/api/current/bmesh.types.html?highlight=bmedge#bmesh.types.BMEdge) for edge in meshdata.edges: # 辺に接続された面を取得する faces = edge.link_faces # 接続された面が2つであることを確認する if len(faces) == 2: # 選択数をチェックする selectcount = 0 # 各面を走査する for face in faces: if face.select == True: # 選択状態の面をカウントする selectcount += 1 # 選択状態の面の数を確認する if selectcount == 1: # 1つ(片方)のみ選択状態であれば辺を選択状態にする edge.select_set(True) else: # 辺を非選択状態にする edge.select_set(False) else: # 辺を非選択状態にする edge.select_set(False) # 辺または面の選択状態を更新する meshdata.select_flush_mode() # オブジェクトデータを更新する selectob.data.update() # 現在選択中の辺に対して設定を行う # シームの設定を行う if arg_seam == True: bpy.ops.mesh.mark_seam(clear=False) # シャープの設定を行う if arg_sharp == True: bpy.ops.mesh.mark_sharp() # クリースの設定を行う if arg_crease == True: bpy.ops.transform.edge_crease(value=1.0) # ベベルの設定を行う if arg_bevel == True: bpy.ops.transform.edge_bevelweight(value=1.0) # オブジェクトモードに移行する bpy.ops.object.mode_set(mode='OBJECT', toggle=False) return True # 関数の実行例 mark_edges_Znormal(arg_objectname="Target", arg_seam=True, arg_sharp=True, arg_crease=True, arg_bevel=True)
面の法線を元にした辺の分離
Z軸の法線方向が上向きの面と下向きの面の境界の辺にシャープを設定します。
その後、[辺分離]モディファイアを[シャープな辺]に対して適用して辺を分離します。
・apply_apply_split_sharpedge.py
# bpyインポート import bpy # メッシュ操作のため import bmesh # Z軸の法線方向が上向きの面と下向きの面の境界の辺にシーム/シャープ/クリース/ベベルを設定する def mark_edges_Znormal(arg_objectname="Default", arg_seam=False, arg_sharp=False, arg_crease=False, arg_bevel=False) -> bool: """Z軸の法線方向が上向きの面と下向きの面の境界の辺にシーム/シャープ/クリース/ベベルを設定する Keyword Arguments: arg_objectname {str} -- [description] (default: {"Default"}) arg_seam {bool} -- シームの設定有無 (default: {False}) arg_sharp {bool} -- シャープの設定有無 (default: {False}) arg_crease {bool} -- クリースの設定有無 (default: {False}) arg_bevel {bool} -- ベベルの設定有無 (default: {False}) Returns: bool -- 実行正否 """ # 指定オブジェクトを取得する # (get関数は対象が存在しない場合 None が返る) selectob = bpy.data.objects.get(arg_objectname) # 指定オブジェクトが存在するか確認する if selectob == None: # 指定オブジェクトが存在しない場合は処理しない return False # オブジェクトがメッシュであるか確認する if selectob.type != 'MESH': # 指定オブジェクトがメッシュでない場合は処理しない return False # 不要なオブジェクトを選択しないように # 全てのオブジェクトを走査する for ob in bpy.context.scene.objects: # 非選択状態に設定する ob.select_set(False) # 指定のオブジェクトのみを選択状態にする selectob.select_set(True) # 対象オブジェクトをアクティブに変更する bpy.context.view_layer.objects.active = selectob # 編集モードに移行する # モード切替のマニュアル # (https://docs.blender.org/api/current/bpy.ops.object.html#bpy.ops.object.mode_set) bpy.ops.object.mode_set(mode='EDIT', toggle=False) # メッシュデータを取得する # メッシュアクセスのマニュアル # (https://docs.blender.org/api/current/bmesh.types.html?highlight=bmedge#bmesh.types.BMesh) meshdata = bmesh.from_edit_mesh(selectob.data) # 選択モードを面選択モードにする meshdata.select_mode = {'FACE'} # 一度選択を全てクリアする bpy.ops.mesh.select_all(action='DESELECT') # 辺または面の選択状態を更新する meshdata.select_flush_mode() # 辺または面を操作する場合はテーブルを更新する meshdata.verts.ensure_lookup_table() # 辺を走査する # 面アクセスのマニュアル # (https://docs.blender.org/api/current/bmesh.types.html?highlight=bmedge#bmesh.types.BMFace) for face in meshdata.faces: # 指定の数の面を選択する if face.normal[2] > 0.0: # 面を選択状態にする face.select_set(True) else: # 面を非選択状態にする face.select_set(False) # メッシュデータを取得する # メッシュアクセスのマニュアル # (https://docs.blender.org/api/current/bmesh.types.html?highlight=bmedge#bmesh.types.BMesh) meshdata = bmesh.from_edit_mesh(selectob.data) # 選択モードを面選択モードにする meshdata.select_mode = {'EDGE'} # 辺または面の選択状態を更新する meshdata.select_flush_mode() # 辺または面を操作する場合はテーブルを更新する meshdata.verts.ensure_lookup_table() # 辺を走査する # 辺アクセスのマニュアル # (https://docs.blender.org/api/current/bmesh.types.html?highlight=bmedge#bmesh.types.BMEdge) for edge in meshdata.edges: # 辺に接続された面を取得する faces = edge.link_faces # 接続された面が2つであることを確認する if len(faces) == 2: # 選択数をチェックする selectcount = 0 # 各面を走査する for face in faces: if face.select == True: # 選択状態の面をカウントする selectcount += 1 # 選択状態の面の数を確認する if selectcount == 1: # 1つ(片方)のみ選択状態であれば辺を選択状態にする edge.select_set(True) else: # 辺を非選択状態にする edge.select_set(False) else: # 辺を非選択状態にする edge.select_set(False) # 辺または面の選択状態を更新する meshdata.select_flush_mode() # オブジェクトデータを更新する selectob.data.update() # 現在選択中の辺に対して設定を行う # シームの設定を行う if arg_seam == True: bpy.ops.mesh.mark_seam(clear=False) # シャープの設定を行う if arg_sharp == True: bpy.ops.mesh.mark_sharp() # クリースの設定を行う if arg_crease == True: bpy.ops.transform.edge_crease(value=1.0) # ベベルの設定を行う if arg_bevel == True: bpy.ops.transform.edge_bevelweight(value=1.0) # オブジェクトモードに移行する bpy.ops.object.mode_set(mode='OBJECT', toggle=False) return True # シャープ辺を対象とする辺分離モディファイアを適用する def apply_split_sharpedge(arg_objectname="Default") -> bool: """対象オブジェクトにブーリアンモディファイアの差分を適用する Keyword Arguments: arg_objectname {str} -- 対象オブジェクト名 (default: {"Default"}) Returns: bool -- 実行正否 """ # 指定オブジェクトを取得する # (get関数は対象が存在しない場合 None が返る) selectob = bpy.data.objects.get(arg_objectname) # 指定オブジェクトが存在するか確認する if selectob == None: # 指定オブジェクトが存在しない場合は処理しない return False # オブジェクトがメッシュであるか確認する if selectob.type != 'MESH': # 指定オブジェクトがメッシュでない場合は処理しない return False # 指定オブジェクトをアクティブに変更する bpy.context.view_layer.objects.active = selectob # 「辺分離」モディファイアを追加する # 辺分離モディファイアのインタフェース # (https://docs.blender.org/api/current/bpy.types.EdgeSplitModifier.html) bpy.ops.object.modifier_add(type='EDGE_SPLIT') # 作成モディファイアを取得する split_modifier = selectob.modifiers[-1] # シャープ辺のみで分離 split_modifier.use_edge_angle = False split_modifier.use_edge_sharp = True # 「辺分離」モディファイアを適用する bpy.ops.object.modifier_apply(apply_as='DATA',modifier=split_modifier.name) return True # 関数の実行例 mark_edges_Znormal(arg_objectname="Target", arg_sharp=True) apply_split_sharpedge(arg_objectname="Target")