はじめての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()
いいなと思ったら応援しよう!
