在进入正文之前,先唠叨一下我最近学习bpy的一些心得:
- Python基础知识 对python基础知识有所了解,就跟学习英语一样,一些常用的语法要知道。
-
学会看别人的代码 如果遇到不会的可以去参考别人写的bpy代码,文本编辑器里就有很多现成的模板,cookbook、Blender 3D: Noob to Pro 和 API文档 里都有很多教程和例子。
-
学会查API文档 遇到自己看不懂的代码或者不知道怎么写,可以根据关键字搜索文档,查找相关用法。
-
学会排错 我们在自己写脚本的时候经常会出现各种各样的错误,这些 错误提示信息 通常出现会在系统控制台 和 信息窗口 。根据这些错误提示信息,我们可以逐步找到并排除代码中的错误。
好了,下面进入正题。
1. 添加面板(Panel)
参考API文档中的例子,我们先定义一个最简单的面板 :
import bpy #这个必须有
class AddPyramidPanel(bpy.types.Panel):
bl_idname = 'OBJECT_PT_Pyramid' #ID名称
bl_space_type = 'VIEW_3D' #面板所在窗口类型
bl_region_type = 'TOOLS' #面板所在区域
bl_category = 'Create' #面板所属分类
bl_context = 'objectmode' #面板作用情境
bl_label = 'Add Pyramid' #标签,也就是面板显示的标题
#定义面板元素
def draw(self, context):
pass #pass表示什么都没有,空面板
#注册面板
bpy.utils.register_class(AddPyramidPanel)
将上面的代码输入到文本编辑器,并运行脚本(Run Script) ,就可以在3D视图 窗口的工具栏下的 Create 分类找到新建的面板了。
写完这个面板之后,我试着把一些面板属性的代码 注释(#) 掉,发现也可以正常运行,在窗口中生成面板。
就像把bl_category = 'Create'
这一行注释掉,不定义面板分类,面板就自动跑到 Misc (杂项) 分类下去了。
import bpy #这个必须有
class AddPyramidPanel(bpy.types.Panel):
# bl_idname = 'OBJECT_PT_Pyramid' #ID名称
bl_space_type = 'VIEW_3D' #面板所在窗口类型
bl_region_type = 'TOOLS' #面板所在区域
# bl_category = 'Create' #面板所属分类
# bl_context = 'objectmode' #面板作用情境
bl_label = 'Add Pyramid' #标签,也就是面板显示的标题
#定义面板元素
def draw(self, context):
pass #pass表示什么都没有,空面板
#注册面板
bpy.utils.register_class(AddPyramidPanel)
2. 在面板上添加按钮
我们在draw
方法中添加 标签 和 按钮 如下:
import bpy #这个必须有
class AddPyramidPanel(bpy.types.Panel):
bl_idname = 'OBJECT_PT_Pyramid' #ID名称
bl_space_type = 'VIEW_3D' #面板所在窗口类型
bl_region_type = 'TOOLS' #面板所在区域
bl_category = 'Create' #面板所属分类
bl_context = 'objectmode' #面板作用情境
bl_label = 'Add Pyramid' #标签,也就是面板显示的标题
#定义面板元素
def draw(self, context):
layout = self.layout
layout.label(text = 'Height:') #添加标签
layout.operator(AddPyramid.bl_idname) #添加按钮
#注册面板
bpy.utils.register_class(AddPyramidPanel)
运行之后我们发现 信息窗口 报错了:
根据错误信息的指示,我们知道问题出在第
16
行,因为我们的AddPyramid
这个operator
并没有定义。
注:关于layout的用法可以参考文档中的 UILayout(bpy_struct) 和 User Interface Layout,界面元素比较多,你可以慢慢研究。
所以我们把上面的代码复制到上次写的添加四棱锥 的 operator
代码里,并把无关代码行注释(#)掉:
import bpy #加载bpy,这个是必须有的
#定义添加网格的方法
def Add_Pyramid(height = 2):
h = height #四棱锥高度
#顶点
verts = [(1,1,0),
(-1,1,0),
(-1,-1,0),
(1,-1,0),
(0,0,h)]
#边
edges = [(0,1),
(1,2),
(2,3),
(3,0),
(0,4),
(1,4),
(2,4),
(3,4)]
#面
faces = [(0,1,4),
(1,2,4),
(2,3,4),
(3,0,4),
(0,1,2,3)]
mesh = bpy.data.meshes.new('Pyramid_Mesh') #新建网格
mesh.from_pydata(verts, edges, faces) #载入网格数据
mesh.update() #更新网格数据
pyramid=bpy.data.objects.new('Pyramid', mesh) #新建物体“Pyramid”,并使用“mesh”网格数据
scene=bpy.context.scene
scene.objects.link(pyramid) #将物体链接至场景
#添加一个Operator类AddPyramid
class AddPyramid(bpy.types.Operator):
bl_idname = 'mesh.pyramid_add' #定义ID名称
bl_label= 'Pyramid' #定义显示的标签名
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
Add_Pyramid() #调用Add_Pyramid()方法
return {'FINISHED'} #执行结束后返回值
#定义面板
class AddPyramidPanel(bpy.types.Panel):
bl_idname = 'OBJECT_PT_Pyramid' #ID名称
bl_space_type = 'VIEW_3D' #面板所在窗口类型
bl_region_type = 'TOOLS' #面板所在区域
bl_category = 'Create' #面板所属分类
bl_context = 'objectmode' #面板作用情境
bl_label = 'Add Pyramid' #标签,也就是面板显示的标题
#定义面板元素
def draw(self, context):
layout = self.layout
layout.label(text = 'Height:') #添加标签
layout.operator(AddPyramid.bl_idname) #添加按钮
#定义添加菜单方法
#def menu_func(self, context):
# self.layout.operator(AddPyramid.bl_idname, icon = 'MESH_CONE')
#定义注册类方法
def register():
bpy.utils.register_class(AddPyramid)
#注册面板
bpy.utils.register_class(AddPyramidPanel)
# bpy.types.INFO_MT_mesh_add.append(menu_func) #添加菜单
#定义取消注册类方法
def unregister():
bpy.utils.unregister_class(AddPyramid)
#取消注册面板
bpy.utils.unregister_class(AddPyramidPanel)
# bpy.types.INFO_MT_mesh_add.remove(menu_func) #移除菜单
#直接执行py文件时,注册Operator
if __name__ == '__main__':
register()
再次点击 运行脚本(Run Script),在工具栏 创建(Create) 分类下找到 Pyramid
按钮,单击运行就得到下面的结果了,我们成功了。
3. 添加属性
还记得之前定义四棱锥 operator
里定义了一个 height(高度)
参数吗?
能不能把这个参数变成添加 四棱锥 时的可调节参数呢?
首先我们就得用到另一个bpy的模块——Property,还可以参考这里。这玩意就是我界面上那些输入框和各种参数调整用到的东西。
这里我们要添加的 height
应该是属于 FloatProperty
(浮点数,也就是小数) 的,所以我们要添加的代码就有:
from bpy.props import FloatProperty #加载FloatProperty
operator
的代码也得做一些添加和修改了:
class AddPyramid(bpy.types.Operator):
bl_idname = 'mesh.pyramid_add' #定义ID名称
bl_label= 'Pyramid' #定义显示的标签名
bl_options = {'REGISTER', 'UNDO'}
height = FloatProperty(
name = 'Height',
description = 'Pyramid Height',
min = 0.0,
default = 2.0)
def execute(self, context):
Add_Pyramid(self.height) #调用Add_Pyramid()方法
return {'FINISHED'} #执行结束后返回值
完整代码如下:
import bpy #加载bpy,这个是必须有的
from bpy.props import FloatProperty #加载FloatProperty
#定义添加网格的方法
def Add_Pyramid(height = 2):
h = height #四棱锥高度
#顶点
verts = [(1,1,0),
(-1,1,0),
(-1,-1,0),
(1,-1,0),
(0,0,h)]
#边
edges = [(0,1),
(1,2),
(2,3),
(3,0),
(0,4),
(1,4),
(2,4),
(3,4)]
#面
faces = [(0,1,4),
(1,2,4),
(2,3,4),
(3,0,4),
(0,1,2,3)]
mesh = bpy.data.meshes.new('Pyramid_Mesh') #新建网格
mesh.from_pydata(verts, edges, faces) #载入网格数据
mesh.update() #更新网格数据
pyramid=bpy.data.objects.new('Pyramid', mesh) #新建物体“Pyramid”,并使用“mesh”网格数据
scene=bpy.context.scene
scene.objects.link(pyramid) #将物体链接至场景
#添加一个Operator类AddPyramid
class AddPyramid(bpy.types.Operator):
bl_idname = 'mesh.pyramid_add' #定义ID名称
bl_label= 'Pyramid' #定义显示的标签名
bl_options = {'REGISTER', 'UNDO'}
height = FloatProperty(
name = 'Height',
description = 'Pyramid Height',
min = 0.0,
default = 2.0)
def execute(self, context):
Add_Pyramid(self.height) #调用Add_Pyramid()方法
return {'FINISHED'} #执行结束后返回值
class AddPyramidPanel(bpy.types.Panel):
bl_idname = 'OBJECT_PT_Pyramid' #ID名称
bl_space_type = 'VIEW_3D' #面板所在窗口类型
bl_region_type = 'TOOLS' #面板所在区域
bl_category = 'Create' #面板所属分类
bl_context = 'objectmode' #面板作用情境
bl_label = 'Add Pyramid' #标签,也就是面板显示的标题
#定义面板元素
def draw(self, context):
layout = self.layout
layout.label(text = 'Height:') #添加标签
layout.operator(AddPyramid.bl_idname) #添加按钮
#定义添加菜单方法
#def menu_func(self, context):
# self.layout.operator(AddPyramid.bl_idname, icon = 'MESH_CONE')
#定义注册类方法
def register():
bpy.utils.register_class(AddPyramid)
#注册面板
bpy.utils.register_class(AddPyramidPanel)
# bpy.types.INFO_MT_mesh_add.append(menu_func) #添加菜单
#定义取消注册类方法
def unregister():
bpy.utils.unregister_class(AddPyramid)
bpy.utils.unregister_class(AddPyramidPanel)
# bpy.types.INFO_MT_mesh_add.remove(menu_func) #移除菜单
#直接执行py文件时,注册Operator
if __name__ == '__main__':
register()
运行后添加四棱锥效果如下:
4. 添加变换调节
正常我们添加网格物体,除了一些基本的属性调节之外,还应该有对齐到屏幕、位移与旋转的变换调节。
那我们要怎么在自己的脚本里实现这一点呢?
首先,对齐到屏幕 要用到 BoolProperty
,也就是布尔值;
位移和旋转 则要用到 FloatVectorProperty
,也就是向量。
然后就是前面我们新建网格物体用的是bpy.data.objects.new()
方法,这里不能用了,我们得用 object_utils.object_data_add()
方法。区别在于后者可以使用operator
作为参数,并使用自身的位移和旋转作为物体的变换参数。
完整代码如下:
import bpy #加载bpy,这个是必须有的
from bpy.props import FloatProperty, FloatVectorProperty, BoolProperty
#定义添加网格的方法
def Add_Pyramid(self, context, height = 2):
h = height #四棱锥高度
#顶点
verts = [(1,1,0),
(-1,1,0),
(-1,-1,0),
(1,-1,0),
(0,0,h)]
#边
edges = [(0,1),
(1,2),
(2,3),
(3,0),
(0,4),
(1,4),
(2,4),
(3,4)]
#面
faces = [(0,1,4),
(1,2,4),
(2,3,4),
(3,0,4),
(0,1,2,3)]
mesh = bpy.data.meshes.new('Pyramid_Mesh') #新建网格
mesh.from_pydata(verts, edges, faces) #载入网格数据
mesh.update() #更新网格数据
from bpy_extras import object_utils
object_utils.object_data_add(context, mesh, operator=self)
# pyramid=bpy.data.objects.new('Pyramid', mesh) #新建物体“Pyramid”,并使用“mesh”网格数据
# scene=bpy.context.scene
# scene.objects.link(pyramid) #将物体链接至场景
#添加一个Operator类AddPyramid
class AddPyramid(bpy.types.Operator):
bl_idname = 'mesh.primitive_pyramid_add' #定义ID名称
bl_label= 'Pyramid' #定义显示的标签名
bl_options = {'REGISTER', 'UNDO'}
view_align = BoolProperty(
name="Align to View",
default=False,
)
height = FloatProperty(
name = 'Height',
description = 'Pyramid Height',
min = 0.0,
default = 2.0)
location = FloatVectorProperty(
name = 'Location',
subtype = 'TRANSLATION')
rotation = FloatVectorProperty(
name="Rotation",
subtype='EULER',
)
def execute(self, context):
Add_Pyramid(self, context, self.height) #调用Add_Pyramid()方法
return {'FINISHED'} #执行结束后返回值
class AddPyramidPanel(bpy.types.Panel):
bl_idname = 'OBJECT_PT_Pyramid'
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'
bl_category = 'Create'
bl_context = 'objectmode'
bl_label = 'Add Pyramid'
def draw(self, context):
layout = self.layout
layout.label(text = 'Height:')
layout.operator(AddPyramid.bl_idname)
#定义添加菜单方法
#def menu_func(self, context):
# self.layout.operator(AddPyramid.bl_idname, icon = 'MESH_CONE')
#定义注册类方法
def register():
bpy.utils.register_class(AddPyramid)
#注册面板
bpy.utils.register_class(AddPyramidPanel)
# bpy.types.INFO_MT_mesh_add.append(menu_func) #添加菜单
#定义取消注册类方法
def unregister():
bpy.utils.unregister_class(AddPyramid)
bpy.utils.register_class(AddPyramidPanel)
# bpy.types.INFO_MT_mesh_add.remove(menu_func) #移除菜单
#直接执行py文件时,注册Operator
if __name__ == '__main__':
register()
运行后添加四棱锥效果如下:
这基本就是我想要的结果了。
好了,终于说完了。
前面三个部分的内容都是非常基础的,我也尽量保证连贯。后面的东西我也没有什么规划,很可能就是想到哪就写到哪了。
最后还想说的就是,我写这个的目的是分享一些我自己学bpy的经验,同时也希望能够帮到大家,让更多的人加入到学习bpy的行列中来。所以,我也希望大家看完之后能够把自己的学习经验分享出来,大家一起进步。
我新建了一个菜鸟学bpy的专题,这个是接受投稿的。大家可以在简书上写下自己的收获,并投稿这个专题。
当然,我还希望社区那些会bpy的大神也能来写几篇教程,指点一下大家。-