【Blender】三角形の数によってオブジェクトに自動で名前をつけるスクリプト

投稿者: | 2023-05-22

ChatGPTを活用して、選択したオブジェクトの名前を変更し、三角形の数の多い順に「_LOD0」「_LOD1」…という接尾辞をつけるスクリプトを作りました。

スクリプト

# rename_by_triangle_count
import bpy

def calculate_triangle_count(obj):
    if obj.type != 'MESH':
        return 0
    mesh = obj.data
    mesh.calc_loop_triangles()
    return len(mesh.loop_triangles)

selected_objects = [obj for obj in bpy.context.selected_objects if obj.type == 'MESH']

if not selected_objects:
    print("No object selected.")
else:
    object_triangle_counts = {obj: calculate_triangle_count(obj) for obj in selected_objects}
    sorted_objects = sorted(object_triangle_counts, key=object_triangle_counts.get, reverse=True)

    for i, obj in enumerate(sorted_objects):
        obj.name = bpy.context.scene.my_string_prop + f"_LOD{i}"

スクリプトを実行

シーンに、Cube、Cylinder、Icosphere、Sphere、Suzanne の5つのオブジェクトを追加しました。

オブジェクトの名前は、カスタムパネルに入力した値を他のスクリプトで使うのテキストフィールドの入力値にします。

BlenderのScriptingワークスペースのテキストエディタのNewボタンを押して、新しいテキストデータブロックを作り、カスタムパネルを表示するスクリプトをコピペします。

import bpy

class SimplePanel(bpy.types.Panel):
    bl_label = "Simple Panel"
    bl_idname = "SCENE_PT_TestPanel"
    bl_space_type = 'TEXT_EDITOR'
    bl_region_type = 'UI'
    bl_category = 'Test Category'

    def draw(self, context):
        layout = self.layout

        layout.prop(context.scene, "my_string_prop")
        layout.prop(context.scene, "my_enum_prop")

def initialize_properties():
    bpy.context.scene.my_string_prop = "Default String"
    bpy.context.scene.my_enum_prop = "2K"  # Set the default enum

def register():
    bpy.utils.register_class(SimplePanel)    
    bpy.types.Scene.my_string_prop = bpy.props.StringProperty(name="Name")
    bpy.types.Scene.my_enum_prop = bpy.props.EnumProperty(name="Map Size",
                                                          items=[("1K", "1024px", "", 1024),
                                                                 ("2K", "2048px", "", 2048),
                                                                 ("3K", "4096px", "", 4096)],
                                                                 default="2K")
                                                         
    initialize_properties()  # Initialize the properties when the script is run

def unregister():
    bpy.utils.unregister_class(SimplePanel)
    del bpy.types.Scene.my_string_prop
    del bpy.types.Scene.my_enum_prop


if __name__ == "__main__":
    register()

再生アイコンをクリックすると、右のサイドバーにカスタムパネルが表示されるのでオブジェクトの新しい名前を入力します。サイドバーは Ctrl + T で表示されます。

New Text ボタンをクリックして新しいテキストデータブロックを作り、三角形の数を数えるスクリプトをコピペします。

アウトライナーで5つのオブジェクトをすべて選択し、再生アイコンをクリックします。

すると、オブジェクトの名前が変更されました。

三角形の多い順番になっています。

Object1_LOD0 | Tris: 968
Object1_LOD1 | Tris: 480
Object1_LOD2 | Tris: 124
Object1_LOD3 | Tris: 80
Object1_LOD4 | Tris: 12

これで、三角形の数によって自動でオブジェクトの名前を変更できました。

ChatGPT

今回も、ChatGPT(GPT-4)にスクリプトを書いてもらいました。

以下を実装した、BlenderのPythonスクリプトを書いてください。

オブジェクトが選択されていることを確認する。選択されていればそれ以降の処理は行わない。(オブジェクトは複数選択されることを想定するが、一つだけ選択されていても問題ない)
(すべてのオブジェクトがMeshをもっていなければいけません。)
選択されているオブジェクトすべての名前を変更する。名前は選択されたオブジェクトのメッシュの三角形の数が多い順に
bpy.context.scene.my_string_prop + _LOD0
bpy.context.scene.my_string_prop + _LOD1
bpy.context.scene.my_string_prop + _LOD2
と命名します。100番目のオブジェクトの名前は
bpy.context.scene.my_string_prop + _LOD99です。

出力されたスクリプトを実行してもエラーが出なかったのですが、少し効率の悪い処理をしているような気がしました。コードの内容をChatGPTに説明してもらいました。

def calculate_triangle_count(obj):
ここでは、オブジェクトのメッシュ内の三角形の数を計算する関数calculate_triangle_countを定義しています。
    mesh = obj.data
    bm = bmesh.new()
    bm.from_mesh(mesh)
この部分では、引数として与えられたBlenderオブジェクトからメッシュデータを取得し、それを新しいbmeshオブジェクトにロードしています。
    bmesh.ops.triangulate(bm, faces=bm.faces)
ここではtriangulate関数を使用して、bmesh内の全てのフェースを三角形に分割しています。
    triangle_count = len(bm.faces)
    bm.free()
    return triangle_count
次に、三角形の数(すなわち、triangulated bmesh内のフェースの数)を計算し、bmeshを解放してから、三角形の数を返しています。

そこで、三角形の数をカウントする方法をネットで検索すると、BMesh.calc_loop_trianglesメソッドを使ったコードが見つかったので、そのスクリプト全体をChatGPTに送り、どちらのほうが効率が良いか回答してもらいました。

実際のパフォーマンスは多くの要素、例えばメッシュの複雑さ、オブジェクトの数、システムのスペックなどに依存しますが、概念的には以下の考え方があります。

1. bmesh.ops.triangulateを用いた方法(最初のコード)では、まず新しいbmeshオブジェクトを作成し、その中にメッシュデータをロードします。その後、全フェースを三角形に変換し、その数を数えます。この操作はメモリと計算時間を要求しますが、メッシュがどのような形状であっても(四角形、N角形)正確に三角形の数を計算できます。

2. calc_loop_trianglesを用いた方法(あなたが提供したコード)では、オブジェクトのメッシュデータに直接アクセスし、その三角形を計算します。その後、三角形の数を数えます。この方法は新たなbmeshオブジェクトを作成しないため、メモリ使用量は少なくなります。しかし、calc_loop_trianglesの内部動作に依存しますが、同じく全ての形状のフェースを三角形に分割して数えることができます。

一般的には、calc_loop_trianglesを用いた方法の方がメモリ効率が良いと考えられますが、具体的なパフォーマンスはBlenderのバージョンやシステムの具体的な状況によります。

どちらの方法も実際の使用においては実行前にプロファイリングを行い、どちらが特定のユースケースで最適かを決定することが望ましいです。

せっかくなので、calc_loop_trianglesメソッドを用いた方法に書き換えてもらいました。

はじめのコードをcalc_loop_trianglesを使った方法に書き換えてください。

すると、冒頭のスクリプトを得られました。スクリプトの説明も書いてもらいました。

ChatGPTによる説明

1. 必要なモジュールのインポート

import bpy

Pythonでプログラミングを始める際の最初のステップは必要なモジュールをインポートすることです。このスクリプトではBlenderのPython APIを利用するために、bpyというモジュールをインポートしています。

2. 三角形数を計算する関数の定義

def calculate_triangle_count(obj):
    if obj.type != 'MESH':
        return 0
    mesh = obj.data
    mesh.calc_loop_triangles()
    return len(mesh.loop_triangles)

この部分では、メッシュオブジェクトの三角形の数を計算する関数を定義しています。オブジェクトがメッシュでない場合、関数は0を返します。それ以外の場合は、メッシュのデータを取得し、calc_loop_trianglesを使用して三角形の数を計算し、その数を返します。

3. 選択されたメッシュオブジェクトの取得

selected_objects = [obj for obj in bpy.context.selected_objects if obj.type == 'MESH']

この行では、現在選択されているすべてのメッシュオブジェクトを取得しています。これはリスト内包表記というPythonの特性を利用しています。これにより、選択されたオブジェクトの中からメッシュタイプのものだけを選択してリストにまとめます。

4. 選択されたオブジェクトのチェック

if not selected_objects:
    print("No object selected.")

ここでは、選択されたオブジェクトがない場合、つまり選択されたメッシュオブジェクトがない場合にメッセージを出力します。選択されたメッシュオブジェクトが存在しないと、以下の処理を続けることはできません。

5. 各オブジェクトの三角形数の計算とオブジェクトのソート

else:
    object_triangle_counts = {obj: calculate_triangle_count(obj) for obj in selected_objects}
    sorted_objects = sorted(object_triangle_counts, key=object_triangle_counts.get, reverse=True)

この部分では、選択されたすべてのメッシュオブジェクトについて三角形の数を計算し、それを辞書に格納します。その後、三角形の数に基づいてオブジェクトをソートします。key=object_triangle_counts.getにより、辞書の値(つまり三角形の数)に基づいてソートを行うことができます。reverse=Trueは、三角形の数が多いオブジェクトから順にソートすることを意味します。

6. オブジェクトの名前変更

for i, obj in enumerate(sorted_objects):
    obj.name = bpy.context.scene.my_string_prop + f"_LOD{i}"

最後に、ソートされたオブジェクトのリストをループして、各オブジェクトの名前を新しい名前に変更します。新しい名前はmy_string_propとそのオブジェクトの順位(LODと呼ばれる)に基づいています。この命名規則は、より多くの三角形を持つオブジェクトがより高いLODを持つことを意味します。

以上、このスクリプトの各部分の説明でした。このスクリプトを使えば、選択されたメッシュオブジェクトの名前を、そのメッシュの三角形の数に基づいて一括で変更することができます。

参考:https://docs.blender.org/api/current/bmesh.types.html

コメントを残す

メールアドレスが公開されることはありません。