1. サイトトップ
  2. ブログ
  3. 【Blender】ChatGPTを活用してPythonで自作Add-onを作ってみた

【Blender】ChatGPTを活用してPythonで自作Add-onを作ってみた

こんにちは!アートデザイン課の入学です!
この頃、びっくりするほど暑い日が続いてますね。去年はそこまで暑くなかったと思うんですが…。
こまめに水分補給する等、熱中症にはお気を付けてお過ごし下さい!

さて、話は変わりますが、最近、AI技術をテレビで見たり触れたりされている方が多いのではないでしょうか?
今回は、今話題の「ChatGPT」を利用してBlenderで自作アドオンを作ってみようと思います。

使用環境

使用ソフト:
Blender 3.3 LTS

Python 3.10.7
ChatGPT GPT3.5

OS:
Windows11

制作するスクリプトの概要

今回は、こちらの動画のような挙動をするスクリプトを作ってみます。


UI上で分割数を指定して、実行を押すと円柱が再作成される
といった感じですね。

円柱を作った後に分割数を変更しようとしても出来ないので、作り直すことに…
これが面倒に感じたのが今回のきっかけになります。

ただ、いきなりアーティストがプログラムを組むのは少しハードルが高いですよね…。
そこで、登場するのがOpenAI社が開発した「ChatGPT」です。

ChatGPTを有効活用してみよう!

まず、実装したいのは、以下のようなプログラムです。


1. 選択したオブジェクトが円柱かどうかを判定
2. 円柱だった場合は、削除
3. 分割数を指定して円柱を作成



早速、ChatGPTに聞いてみましょう。
質問すると生成してくれるので、試した結果が以下になります。

驚くほど速く生成してくれました…。
さて、生成したスクリプトは本当に動くんでしょうか…? 

早速テストしてみます。

まずは、Blenderで「Workspaceを「Scripting」に変更します。


上の方に、「+New」というボタンがあるので、クリックします。



ここに生成したプログラムをコピー&ペーストします。


そして、円柱を選択した状態で再生ボタンをクリックすると…


なんと動きましたね…! 凄いですねこれは…。
しかも、ちゃんと円柱だけ消すことが出来ています。
一発でメインとなるプログラムの大部分が出来てしまいました。

ただ、生成したままのコードだと、不要な部分や気になる部分があるので、
以下のように直します。

import bpy

# 選択中のオブジェクトを取得
selected_objects = bpy.context.selected_objects

# 選択されたオブジェクトが円柱かどうかチェック
for obj in selected_objects:
   # 選択したオブジェクトが円柱だった場合
    if obj.type == 'MESH' and obj.name.startswith("Cylinder"):
    # オブジェクトを削除
        bpy.data.objects.remove(obj, do_unlink=True)

ちなみに、画像の赤線部が不要な部分なので、消してしまっています。
オブジェクトがアクティブかどうかは今回は関係ないからですね。

これで「選択したオブジェクトが円柱だった場合に、削除する」 ところまで出来ました。

簡単なコードを書いてみよう

次に、円柱を作るコードを書いてみましょう。
まずは左上のシーンビュー円柱を作ります。

この時、分割数を「8」にしましょう。

下の方に何やら履歴が 出力されてますね。

このコードで円柱を作成しているのが分かります。
履歴から右クリックでコピーできるので、先程のスクリプトの後ろに付け足します。

import bpy

# 選択中のオブジェクトを取得
selected_objects = bpy.context.selected_objects

# 選択されたオブジェクトが円柱かどうかチェック
for obj in selected_objects:
    
    # 選択したオブジェクトが円柱だった場合
    if obj.type == 'MESH' and obj.name.startswith("Cylinder"):
        
        # オブジェクトを削除
        bpy.data.objects.remove(obj, do_unlink=True)
        
        # 円柱を作成
        bpy.ops.mesh.primitive_cylinder_add(vertices=8, 
        radius=1, depth=2, enter_editmode=False, align='WORLD', 
        location=(0, 0, 0), scale=(1, 1, 1))

ちなみに…
vertices = 8」というのが、分割数を「8」で円柱を作ることを意味します。
他の数値を指定することができれば、好きな分割数の円柱が作れそうです。
ここは後ほど、UIと連動して分割数を変えられるようにします。
これでメインのスクリプトはほぼ完成です。

このような形で部分的に生成したものを利用することで、書き方が分からない場合のハードルを下げることが出来ます。
ちょっと頑張ったら出来るような気がしてきませんか?

スクリプト生成のコツ

ChatGPTに生成してもらうに当たって、上手く生成できない…。といったことが出てくると思います。

そんな時に、少しでも狙ったコードを生成する方法をご紹介します。
※100%想定通りの物を生成するのは難しいです。
 あくまで想定していたものに近づける方法です。


1. 出来るだけ詳細な情報を与える
2. 分かりやすい文章を心掛ける
3. 何かを指定する場合は「」囲う、または” “強調する
4. 条件が複数ある場合は箇条書きで指定する


例として、上記4つを「意識した場合」と「意識していない場合」で比較してみましょう。

例.「意識していない場合
Blenderで選択したオブジェクトが円柱だった場合には削除して、削除後、分割数を指定して円柱を作成するPythonスクリプトを教えていただけないでしょうか?

よく見ると、指定していない部分も生成してくれていますね…。

例.「意識した場合
Blenderで以下の条件を満たすPythonのスクリプトを教えていただけないでしょうか?
1.選択したオブジェクトの名前が「Cylinder」だった場合を判定
2.「円柱」だった場合は削除
3.「分割数」を「8」と指定して再作成

こちらはほぼ完璧ですね!

いかがでしょうか?
意識した場合」の方が分かりやすく、より詳細に伝えていると思います。
また、想定に近い生成結果になっているのが分かります。
今回は、「悪い例」をChatGPT側でそれらしく補完してくれています。
その為、良さそうな生成結果になっていますが、見当違いな結果になる可能性も十分にあり得ます。
上手く生成できない場合は、「どうしたら分かりやすいか」を意識してみてください!

条件分岐を追加

さて、先程メインのスクリプトが大体完成した所まで行きました。
ここでおまけとして「条件分岐」を追加しようかと思います。
現状、円柱を選択する前提で書いているので、立方体等の対象外のオブジェクトを選択した場合に対応できないからです。
処理は通りますが、何も起きません。
これでは状況が分かりづらい為、不親切な設計になっています。

そこで、「何も選択していない」or「円柱以外を選択」した場合に文字出力するようにしてみます。

すでに円柱を選択した場合の条件分岐をしている箇所がありますね。
以下のif文です。

# 選択したオブジェクトが円柱だった場合
    if obj.type == 'MESH' and obj.name.startswith("Cylinder"):

これは、もし選択したオブジェクトがメッシュかつオブジェクトの名前が「Cylinder」で始まる場合、次の処理に進むという内容です。

==」は左辺と右辺が同じという意味です。
この部分を利用して、「円柱ではない場合」に書き換えるとこうなります。

# 選択物が円柱ではない場合
elif obj.type == 'MESH' and obj.name != "Cylinder":
    print('\n円柱ではありません。')

elif」はさらに条件分岐したい時に使います。
!=」は左辺と右辺は同じではないという意味になります。
選択したオブジェクト≠”Cylinder” 」の場合に、最後に書いたprint関数で( )内の文字が出力されるといった形です。

残るは「何も選択していない」場合の条件分岐ですね。
こちらはとてもシンプルで以下のようになります。

# 何も選択していない場合    
elif selected_objects is None:            
    print('\n何も選択されていません。') 

選択したオブジェクトがNone場合にすれば良さそうです。
Noneというのは、という意味です。
これで、何も選択していない場合に文字を出力してくれるはずです。

ちなみに、文字出力を確認するには、専用のウィンドウを出す必要があります。
Window」 → 「ToggleSystemConsole」 で黒いウィンドウが出ます。
こちらに、print関数で出力した文字が表示されます。


では、動作テストしてみましょう!


…あれ? おかしいですね。「何も選択しない」場合に何も出力されません。
print関数が動いていないので、条件分岐が上手く機能していないような感じがしますが。
うーん、困りました。 原因が全く分かりません…。

トラブルシューティング

先程のようにプログラムを書いていて、上手く動いてくれない時があります。
どうしても原因が分からない場合はどうしましょうか?
分からない問題と睨み合いをするのは結構大変です…。

そこで、ChatGPTに解決のヒントを貰う方法で修正する方法を紹介します。
早速、以下のような形で聞いてみました。


返答はこちら。


なるほど!!
どうやら「bpy.context.selected_objects」を使用して何も選択していない場合は空リストを返している為、None(空)に出来ない仕様のようです。
元々コードに問題があった様ですね…。

「bpy.context.selected_objects」 というのは、選択したオブジェクトの情報を取得するためのコードです。
今回は、オブジェクトの名前を取得するために使っています。

解決策まで提示して貰えたので、そのままお借りしてみます。
これで試してみましょう。
どうでしょうか・・・・?!

動きました!!
ちゃんと「円柱ではない」、「何も選択していない」場合の条件分岐も出来てますね。
生成だけでなく、解析も行えて、解説もしてくれます。
これは驚くべきサービスなんじゃないでしょうか…?

UIを表示して利便性向上

UIの描画部分もChatGPTのお力を借りようと思います。
分割数を変更できるUI」、「実行ボタン」この2つを生成してもらいました。
早速聞いてみた結果がこちらです。

この部分がちょっと気になりますね。

これではサイドバーに表示される名前が「Custom_Tools」になるので、変えます。
円柱を再作成するツールなので、名前を「Recreate_Cylinder」にします。

class SimplePanel(bpy.types.Panel):
    bl_label = "分割数設定と実行"
    bl_idname = "OBJECT_PT_simple_panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Recreate_Cylinder'

また、画像の赤線部は不要なので、消しています。

さて、問題無く動くかテストしてみましょう。
同じように再生ボタンをクリックします。


…ちゃんと必要なUIが表示されてますね!
ただ、このままでは「UI」が表示されただけで、連動しません。
UIで操作可能にするためにちょっと書き換える必要が出て来ます。

実行ボタンの動作

まずは、実行ボタンが動くように書き換えようと思いますが…
折角なので、こちらもChatGPTに聞いてみました。



こちらも素早くかつ丁寧に答えてくれました。


def execute(self, context):」という部分の中に円柱を再作成するスクリプト」を書けば実行してくれるみたいですね!

このスクリプトもお借りしましょう!
本当にChatGPTさんには頭が上がらないですね…。
これで、実行ボタンが機能するようになりました!


後は、分割数をUI上で操作した数値通りに動くようにするだけです。
現状は8分割でしか円柱を作成出来ないので、UIと連動するようにします。

分割数のUIを連動させる

まず、UI上の分割数の情報を取得する必要があります。
例えば、UIの分割数が「20」だった場合にその数値を取ることが出来れば、連動できそうです。


難しそうに聞こえますが、結構簡単に出来るのでご安心を!


その前に、一つ設定する必要があります。
Edit」→「Preferences」→「Interface」→「Python Tooltips✅」



この設定をすると、様々な情報に対してPythonで取得するコードをコピーできるようになります。


次に、シーンビューにある「分割数」のUI上で右クリック →「Copy Full Data Path」を選択します。


シーンビューの下に画像のようなコンソールがあると思うので、先程コピーしたコードをペーストして、Enterを押してみてください。


なんと、UI上の「分割数」で指定した数値が返ってきます。
これを利用すれば、連動できるようになる訳です。


後はスクリプトに組み込むだけです。
実行ボタンで記入した実行部分をちょっと書き換えます。
まずは先程、 UI上の「分割数」 を取得するコードを変数に代入します。

subdivision_axis = bpy.data.scenes["Scene"].subdivisions

次に、円柱を作るコードに分割数を指定する部分があるので、上記の変数「subdivision_axis」を指定します。
vertices = subdivision_axis」の形にする感じですね。

bpy.ops.mesh.primitive_cylinder_add(vertices=subdivision_axis, 
enter_editmode=False, align='WORLD', 
location=(0, 0, 0), scale=(1, 1, 1))

これで、UI上で操作できるようになりました!
こんな感じです。

残るはAdd-onとして登録出来るようにするだけです!

Add-onのインストール

まずはBlenderがテンプレートを用意しているので、そのコードを開きます。
Templates」→「Python」→「Addon Add Object


コードがずらりと出てくると思いますが、使うのは赤く囲った部分だけです!
このコードをスクリプトの一番最初に持ってきます。

それぞれ、好きなように書き換えます。

bl_info = {
    "name": "Recreate_Cylinder", #スクリプトの名前
    "author": "Nyugaku", #作者名
    "version": (1, 0),
    "blender": (2, 80, 0), #Blenderの対応バージョン
    "location": "View3D > Sidebar > View Tab",
    "description": "分割数を指定して円柱を再作成します。", #説明文
    "warning": "",
    "doc_url": "",
    "category": "Add Mesh",
}

これでスクリプトは完了です。

次に名前と拡張子.pyを付けてファイルを保存しましょう。
Recreate_Cylinder.py」という命名にします。

Text」→「Save As」を押して、保存場所を指定して別名保存します。


最後にAdd-onをインストールします。
Edit」→「Preferences」 →「Add-ons」→「Install



先程保存した拡張子.pyのファイルを指定して、「Install Add-on」を押します。


後はインストールしたAdd-onに✅を入れれば、完了です!
これで有効化されて、自作アドオンが使えるようになりました!!

Blender起動時にサイドバーに自作アドオンが表示されていれば、成功です!

最後に

今回は、ChatGPTを利用してAdd-onを自作するかなりボリューミーな記事だったかと思います。
量が少し多くなってしまったので触れられていませんが、機能拡張ができます。
例えば、選択したオブジェクトのワールド座標を格納しておいて、その座標を指定して作成すると、元々あった位置に円柱を作成することが出来ます。
すると、違う位置にある複数の円柱をまとめて分割数を変える等ができるようになるので、更に便利になります。

あとは、文字出力もコンソールに出すのではなく、シーンビューに警告として表示してもっと分かりやすくする…。なども可能です!

ChatGPTがどれだけ凄いサービスか少しでも伝わったと思いますので、興味を持っていただけると嬉しいです!
この記事が少しでも皆さんのお役に立てれば幸いです。

参考文献


【免責事項】

本サイトでの情報を利用することによる損害等に対し、
株式会社ロジカルビートは一切の責任を負いません。