【Blender 开发】Add-on 模板代码解析
Add-on 模板插件
启用该插件
其上的信息对应于后文的
bl_info
结构体
注册该插件的代码段为
# ------------------------------------------------------------------------
# 注册 Registration
# ------------------------------------------------------------------------
# 需要注册的类
classes = (
MyProperties,
WM_OT_HelloWorld,
OBJECT_MT_CustomMenu,
OBJECT_PT_CustomPanel
)
def register():
# 导入函数
from bpy.utils import register_class
# 遍历要注册的类,并注册
for cls in classes:
register_class(cls)
bpy.types.Scene.my_tool = PointerProperty(type=MyProperties)
def unregister():
from bpy.utils import unregister_class
for cls in reversed(classes):
unregister_class(cls)
del bpy.types.Scene.my_tool
if __name__ == "__main__":
register()
插件加载后的效果
该界面 UI 对应的代码段为
- 属性的定义
# ------------------------------------------------------------------------
# 窗口属性定义 Properties
# ------------------------------------------------------------------------
class MyProperties(PropertyGroup):
# RNA 属性(全局属性) x : 属性类(内容)
my_bool: BoolProperty(
name="开/关",
description="我是布尔类型",
default = False
)
my_int: IntProperty(
name = "整数值",
description="我是整数值",
default = 23,
min = 10,
max = 100
)
my_float: FloatProperty(
name = "浮点值",
description = "我是浮点值",
default = 23.7,
min = 0.01,
max = 30.0
)
my_float_vector: FloatVectorProperty(
name = "浮点矢量值",
description="Something",
default=(0.0, 0.0, 0.0),
min= 0.0, # float
max = 0.1
)
my_string: StringProperty(
name="用户输入",
description=":",
default="",
maxlen=1024,
)
my_path: StringProperty(
name = "目录",
description="选择一个目录:",
default="",
maxlen=1024,
subtype='DIR_PATH'
)
my_enum: EnumProperty(
name="下拉列表:",
description="应用数据给属性.",
items=[ ('OP1', "选项 1", ""),
('OP2', "选项 2", ""),
('OP3', "选项 3", ""),
]
)
注意:数字属性
subtype
可选如下
- PIXEL
- PERCENTAGE
- ANGLE
- DISTANCE
- UNSIGNED
- FACTOR
- TIME
- NONE
注意:字符串属性
subtype
可选如下
- FILE_PATH
- DIR_PATH
- FILE_NAME
- BYTE_STRING
- PASSWORD
- NONE
注意:矢量属性
subtype
可选如下
- COLOR
- VELOCITY
- EULER
- XYZ
- NONE
- TRANSLATION
- CCELERATION
- QUATERNION
- COLOR_GAMMA
- DIRECTION
- MATRIX
- AXISANGLE
- LAYER
- 面板布局的设置
# ------------------------------------------------------------------------
# 对象模式的面板 Panel in Object Mode
# ------------------------------------------------------------------------
class OBJECT_PT_CustomPanel(Panel):
bl_label = "我的面板"
bl_idname = "OBJECT_PT_custom_panel"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "我的小工具"
bl_context = "objectmode"
# poll 函数在 3D 面板更新时调用,用来判断显示面板:当前是_ 必须存在 context.object
@classmethod
def poll(self,context):
return context.object is not None
def draw(self, context):
layout = self.layout
scene = context.scene
mytool = scene.my_tool
# 把属性放入布局
layout.prop(mytool, "my_bool")
layout.prop(mytool, "my_enum", text="")
layout.prop(mytool, "my_int")
layout.prop(mytool, "my_float")
layout.prop(mytool, "my_float_vector", text="")
layout.prop(mytool, "my_string")
layout.prop(mytool, "my_path")
# 放置操作项
layout.operator("wm.hello_world")
# 放置菜单
layout.menu(OBJECT_MT_CustomMenu.bl_idname, text="预设", icon="SCENE")
# 放置分隔符
layout.separator()
注意:
bl_space_type
字段可选的类型如下
- EMPTY
- NLA_EDITOR
- NODE_EDITOR
- INFO
- VIEW_3D
- IMAGE_EDITOR
- LOGIC_EDITOR
- FILE_BROWSER
- TIMELINE
- SEQUENCE_EDITOR
- PROPERTIES
- CONSOLE
- GRAPH_EDITOR
- CLIP_EDITOR
- OUTLINER
- DOPESHEET_EDITOR
- TEXT_EDITOR
- USER_PREFERENCES
注意:
bl_region_type
字段可选的类型如下
- WINDOW
- HEADER
- CHANNELS
- TEMPORARY
- UI
- TOOLS
- TOOL_PROPS
- PREVIEW
自定义操作项
点击插件的 操作项
- 点击前的面板界面
- 点击后控制台打印
对应代码段为
# ------------------------------------------------------------------------
# 操作项 Operators
# ------------------------------------------------------------------------
class WM_OT_HelloWorld(Operator):
bl_label = "Print Values Operator" # 工具显示名称,也就是 F3 搜的名称
bl_idname = "wm.hello_world" # 工具 id,也就是控制台可以直接调用的名称,比如 bpy.ops.wm.hello_world
# 执行函数(工具的功能)
def execute(self, context):
scene = context.scene
mytool = scene.my_tool
# 在控制台打印以下值
print("Hello World")
print("bool state:", mytool.my_bool)
print("int value:", mytool.my_int)
print("float value:", mytool.my_float)
print("string value:", mytool.my_string)
print("enum state:", mytool.my_enum)
# 需要返回值给 bl 接受,FINISHED 代表完成,也就是正常退出的意思
return {'FINISHED'}
自定义菜单
对应代码段为
# ------------------------------------------------------------------------
# 菜单 Menus
# ------------------------------------------------------------------------
class OBJECT_MT_CustomMenu(bpy.types.Menu):
bl_label = "Select"
bl_idname = "OBJECT_MT_custom_menu"
# draw 函数用于绘制菜单
def draw(self, context):
# 创建一个布局
layout = self.layout
# 把操作项放入布局(下面是官方的操作项,你可以填自己的)
layout.operator("object.select_all", text="Select/Deselect All").action = 'TOGGLE'
layout.operator("object.select_all", text="Inverse").action = 'INVERT'
layout.operator("object.select_random", text="Random")
完整代码与详细注释
代码是 Blender 自带的插件模板
bl_info = {
"name": "Add-on Template", # 插件名称
"description": "", # 插件描述
"author": "blender", # 插件作者
"version": (0, 0, 3), # 插件版本
"blender": (3, 0, 0), # 适用于 Blender 版本
"location": "3D View > Tools", # 生效区域
"warning": "", # 本插件的警告信息(在首选项-插件-插件信息显示)
"wiki_url": "", # 本插件的 wiki 链接(在首选项-插件-插件信息显示)
"tracker_url": "", # 本插件的 tracker 链接(在首选项-插件-插件信息显示)
"category": "Development" # 本插件所属分类,可以(在首选项-插件-插件分类筛选)
}
import bpy # 导入 blender 模块主体
# 从 props(bl 属性模块)导入对应的属性类
# 不导也行,你也可以这样写 myInt = bpy.props.IntProperty(XX)
from bpy.props import (StringProperty,
BoolProperty,
IntProperty,
FloatProperty,
FloatVectorProperty,
EnumProperty,
PointerProperty,
)
# 从 props(bl 类型模块)导入对应的 UI 类
from bpy.types import (Panel,
Menu,
Operator,
PropertyGroup,
)
# ------------------------------------------------------------------------
# 窗口属性定义 Properties
# ------------------------------------------------------------------------
class MyProperties(PropertyGroup):
# RNA 属性(全局属性) x : 属性类(内容)
my_bool: BoolProperty(
name="开/关",
description="我是布尔类型",
default = False
)
my_int: IntProperty(
name = "整数值",
description="我是整数值",
default = 23,
min = 10,
max = 100
)
my_float: FloatProperty(
name = "浮点值",
description = "我是浮点值",
default = 23.7,
min = 0.01,
max = 30.0
)
my_float_vector: FloatVectorProperty(
name = "浮点矢量值",
description="Something",
default=(0.0, 0.0, 0.0),
min= 0.0, # float
max = 0.1
)
my_string: StringProperty(
name="用户输入",
description=":",
default="",
maxlen=1024,
)
my_path: StringProperty(
name = "目录",
description="选择一个目录:",
default="",
maxlen=1024,
subtype='DIR_PATH'
)
my_enum: EnumProperty(
name="下拉列表:",
description="应用数据给属性.",
items=[ ('OP1', "选项 1", ""),
('OP2', "选项 2", ""),
('OP3', "选项 3", ""),
]
)
# ------------------------------------------------------------------------
# 操作项 Operators
# ------------------------------------------------------------------------
class WM_OT_HelloWorld(Operator):
bl_label = "Print Values Operator" # 工具显示名称,也就是 F3 搜的名称
bl_idname = "wm.hello_world" # 工具 id,也就是控制台可以直接调用的名称,比如 bpy.ops.wm.hello_world
# 执行函数(工具的功能)
def execute(self, context):
scene = context.scene
mytool = scene.my_tool
# 在控制台打印以下值
print("Hello World")
print("bool state:", mytool.my_bool)
print("int value:", mytool.my_int)
print("float value:", mytool.my_float)
print("string value:", mytool.my_string)
print("enum state:", mytool.my_enum)
# 需要返回值给 bl 接受,FINISHED 代表完成,也就是正常退出的意思
return {'FINISHED'}
# ------------------------------------------------------------------------
# 菜单 Menus
# ------------------------------------------------------------------------
class OBJECT_MT_CustomMenu(bpy.types.Menu):
bl_label = "Select"
bl_idname = "OBJECT_MT_custom_menu"
# draw 函数用于绘制菜单
def draw(self, context):
# 创建一个布局
layout = self.layout
# 把操作项放入布局(下面是官方的操作项,你可以填自己的)
layout.operator("object.select_all", text="Select/Deselect All").action = 'TOGGLE'
layout.operator("object.select_all", text="Inverse").action = 'INVERT'
layout.operator("object.select_random", text="Random")
# ------------------------------------------------------------------------
# 对象模式的面板 Panel in Object Mode
# ------------------------------------------------------------------------
class OBJECT_PT_CustomPanel(Panel):
bl_label = "我的面板"
bl_idname = "OBJECT_PT_custom_panel"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "我的小工具"
bl_context = "objectmode"
# poll 函数在 3D 面板更新时调用,用来判断显示面板:当前是_ 必须存在 context.object
@classmethod
def poll(self,context):
return context.object is not None
def draw(self, context):
layout = self.layout
scene = context.scene
mytool = scene.my_tool
# 把属性放入布局(注意和定义的顺序不一样)
layout.prop(mytool, "my_bool")
layout.prop(mytool, "my_enum", text="")
layout.prop(mytool, "my_int")
layout.prop(mytool, "my_float")
layout.prop(mytool, "my_float_vector", text="")
layout.prop(mytool, "my_string")
layout.prop(mytool, "my_path")
# 放置操作项
layout.operator("wm.hello_world")
# 放置菜单
layout.menu(OBJECT_MT_CustomMenu.bl_idname, text="预设", icon="SCENE")
# 放置分隔符
layout.separator()
# ------------------------------------------------------------------------
# 注册 Registration
# ------------------------------------------------------------------------
# 需要注册的类
classes = (
MyProperties,
WM_OT_HelloWorld,
OBJECT_MT_CustomMenu,
OBJECT_PT_CustomPanel
)
def register():
# 导入函数
from bpy.utils import register_class
# 遍历要注册的类,并注册
for cls in classes:
register_class(cls)
bpy.types.Scene.my_tool = PointerProperty(type=MyProperties)
def unregister():
from bpy.utils import unregister_class
for cls in reversed(classes):
unregister_class(cls)
del bpy.types.Scene.my_tool
if __name__ == "__main__":
register()
注意:
bl_info
中的Category
字段对应可选的分类有
- 3D View
- Compositing
- Lighting
- Object
- Rigging
- Text Editor
- Add Mesh
- Development
- Material
- Paint
- Scene
- UV
- Add Curve
- Game Engine
- Mesh
- Physics
- Sequencer
- User Interface
- Animation
- Import-Export
- Node
- Render
- System
(完)
转载自:https://juejin.cn/post/7173386565207457806