はじめてのBlenderでのAddon制作

ChatGPTを使用してなら、Addon作れそうって試したら沼でした。
とりあえず 下記scriptを記しますが 使用にあたっては自己責任でお願いします。危ない命令とかはしていないのですが、ただ使用用途があるわけでもなく試してみたかっただけなのです。

  どんなスクリプトをつくったのか?
  →選択しているオブジェクトのVipotを移動させるscriptです。

  どんな処理にしたの?下の①と②です。

 ① 選択しているオブジェクトに対して Vipot ボタンを押すと
   オブジェクトを包む正方形を生成させて
   正方形の各頂点にEmptyを生成させて 
   正方形を削除させて
   選択しているオブジェクトは選択できないようにします。
   ここでVipotボタンを押した際の命令は止めます。
 ② 次に表示されている Emptyのどれかを選択している状態で
   Apply ボタンを押すと
   ①で最初に選択していたオブジェクトのOrigin(Vipot) が
   選択したEmptyの位置に移動しています

 どうやってこのAddonは試せるの?
 下記スクリプトを .py形式で保存して 
 それをエクスプローラーから.py形式で保存したものを選択して
 右クリックから .zip圧縮します。
 .zip形式を BlenderのAddonのインストールから選択すると
 インストールできます。
  view3Dの右側にtoolsパネル(toolではないので
  下のほうにタブがあると思います)

 試し方は おさるさんをBlenderで出して、Addonを使ってみると 
 あーこんなの試しに作ったのねぇになると思います。

 で、わかっていることなのですが Cubeという名前のオブジェクトを
 選択しているオブジェクトを包む用のオブジェクト名にしているため
 Cubeというオブジェクトを選択した状態で使用すると、消えますw


みなさんも楽しんでください!

bl_info = {
    "name": "Origin Mover",
    "blender": (2, 80, 0),
    "category": "Object",
}

import bpy
from bpy.types import Operator, Panel

class OBJECT_OT_origin_mover(Operator):
    bl_idname = "object.origin_mover"
    bl_label = "Vipot"
    bl_options = {'REGISTER', 'UNDO'}

    @classmethod
    def poll(cls, context):
        return context.active_object is not None

    def execute(self, context):
        # 1度目のVipotボタン押下で生成したオブジェクトを削除
        if "custom_objects" in context.scene:
            for obj_name in context.scene["custom_objects"]:
                obj = bpy.data.objects.get(obj_name)
                if obj:
                    bpy.data.objects.remove(obj, do_unlink=True)

        # 選択中のオブジェクトを覚える
        context.scene["custom_selected_objects"] = [obj.name for obj in context.selected_objects]

        # すでに生成されているCubeがない場合のみ新しく生成
        if not bpy.data.objects.get('Cube'):
            # 選択していたオブジェクトをDisable selectionにする
            for obj_name in context.scene["custom_selected_objects"]:
                obj = bpy.data.objects.get(obj_name)
                if obj:
                    obj.hide_select = True

            # 新しいCubeを生成
            bpy.ops.mesh.primitive_cube_add(size=2, enter_editmode=False, align='WORLD', location=(0, 0, 0))
            cube = context.active_object

            # エッジの中点に頂点を追加
            bpy.ops.object.mode_set(mode='EDIT')
            bpy.ops.mesh.select_all(action='SELECT')
            bpy.ops.mesh.subdivide(number_cuts=1, smoothness=0, quadcorner='STRAIGHT_CUT', fractal=0, fractal_along_normal=0)
            bpy.ops.object.mode_set(mode='OBJECT')

            # Cubeの各頂点にEmptyを生成
            empty_objects = []
            for vert in cube.data.vertices:
                bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=vert.co)
                empty = context.active_object
                empty.scale = (0.2, 0.2, 0.2)  # ここで表示上のサイズを設定
                empty_objects.append(empty)

            # 選択していたオブジェクトの中心にもCubeの各頂点に生成するEmptyと同じサイズのものを1つ作成
            bpy.ops.object.empty_add(type='CUBE', align='WORLD', location=cube.location)
            extra_empty = context.active_object
            extra_empty.scale = (0.2, 0.2, 0.2)

            # 生成したオブジェクトの名前を保存
            context.scene["custom_objects"] = [cube.name] + [empty.name for empty in empty_objects] + [extra_empty.name]

            # 新しいCubeを削除
            bpy.data.objects.remove(cube, do_unlink=True)

        # Vipotボタンが押されたことをマーク
        context.scene["vipot_button_pressed"] = True

        # Applyボタンが有効になるように設定
        context.scene["apply_button_enabled"] = True

        # Disable Vipot button
        context.scene["vipot_button_enabled"] = False

        return {'FINISHED'}

class OBJECT_OT_origin_apply(Operator):
    bl_idname = "object.origin_apply"
    bl_label = "Apply"
    bl_options = {'REGISTER', 'UNDO'}

    @classmethod
    def poll(cls, context):
        # Applyボタンが有効かどうかを確認
        return context.scene.get("apply_button_enabled", False)

    def execute(self, context):
        # 3Dカーソルが選択中のEmptyの位置に移動
        bpy.context.scene.cursor.location = context.active_object.location

        # 選択していたオブジェクトをEnable selectionに戻す
        for obj_name in context.scene["custom_selected_objects"]:
            obj = bpy.data.objects.get(obj_name)
            if obj:
                obj.hide_select = False

        # 選択中のEmptyを削除
        bpy.ops.object.select_all(action='DESELECT')
        for obj_name in context.scene["custom_objects"][1:]:
            obj = bpy.data.objects.get(obj_name)
            if obj:
                obj.select_set(True)
        bpy.ops.object.delete()

        # 選択していたオブジェクトを再度選択し、Origin to 3D Cursorを行った後に選択解除
        if "custom_selected_objects" in context.scene:
            for obj_name in context.scene["custom_selected_objects"]:
                obj = bpy.data.objects.get(obj_name)
                if obj:
                    obj.select_set(True)
                    bpy.context.view_layer.objects.active = obj
                    bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
                    obj.select_set(False)

        # Applyボタンが押されたことをマーク
        context.scene["apply_button_pressed"] = True

        # Vipotボタンが有効になるように設定
        context.scene["vipot_button_enabled"] = True

        # Enable Vipot button
        context.scene["vipot_button_enabled"] = True

        # Disable Apply button
        context.scene["apply_button_enabled"] = False

        # Vipotボタンで生成されたEmptyを削除
        if "custom_objects" in context.scene:
            for obj_name in context.scene["custom_objects"]:
                obj = bpy.data.objects.get(obj_name)
                if obj:
                    bpy.data.objects.remove(obj, do_unlink=True)

        return {'FINISHED'}

class OBJECT_PT_origin_move_panel(Panel):
    bl_label = "Origin Move Panel"
    bl_idname = "PT_ORIGIN_MOVE"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Tools'
    bl_context = "objectmode"

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

        row = layout.row()
        
        # Vipotボタンの有効/無効を確認
        vipot_button_enabled = context.scene.get("vipot_button_enabled", True)
        
        if vipot_button_enabled:
            # Vipotボタン
            row.operator(OBJECT_OT_origin_mover.bl_idname, text="Vipot", icon='MODIFIER')
            
        else:
            # Vipotボタンを無効にする場合
            row.label(text="Vipot (Disabled)", icon='MODIFIER')

        # ApplyボタンをUIに追加
        row = layout.row()
        apply_button = row.operator(OBJECT_OT_origin_apply.bl_idname, text="Apply", icon='FILE_REFRESH')
        
        # Applyボタンの有効/無効を確認
        apply_button.enabled = context.scene.get("apply_button_enabled", False)

def menu_func(self, context):
    self.layout.operator(OBJECT_OT_origin_mover.bl_idname)

def menu_func_apply(self, context):
    self.layout.operator(OBJECT_OT_origin_apply.bl_idname)

def register():
    bpy.utils.register_class(OBJECT_OT_origin_mover)
    bpy.utils.register_class(OBJECT_OT_origin_apply)
    bpy.utils.register_class(OBJECT_PT_origin_move_panel)
    bpy.types.VIEW3D_MT_mesh_add.append(menu_func)

    # カスタムオブジェクトを保存するためのプロパティをシーンに追加
    bpy.types.Scene.custom_objects = bpy.props.StringProperty(default="")

def unregister():
    bpy.utils.unregister_class(OBJECT_OT_origin_mover)
    bpy.utils.unregister_class(OBJECT_OT_origin_apply)
    bpy.utils.unregister_class(OBJECT_PT_origin_move_panel)
    bpy.types.VIEW3D_MT_mesh_add.remove(menu_func)

    # シーンからカスタムオブジェクトのプロパティを削除
    del bpy.types.Scene.custom_objects

if __name__ == "__main__":
    register()


いいなと思ったら応援しよう!

TOX
頂いたチップでカフェします☆