菜鸟学bpy(三)添加面板(Panel)

在进入正文之前,先唠叨一下我最近学习bpy的一些心得:

  1. Python基础知识 对python基础知识有所了解,就跟学习英语一样,一些常用的语法要知道。
  2. 学会看别人的代码 如果遇到不会的可以去参考别人写的bpy代码,文本编辑器里就有很多现成的模板,cookbook、Blender 3D: Noob to Pro 和 API文档 里都有很多教程和例子。
    菜鸟学bpy(三)添加面板(Panel)_第1张图片
    Template.png
  3. 学会查API文档 遇到自己看不懂的代码或者不知道怎么写,可以根据关键字搜索文档,查找相关用法。
    菜鸟学bpy(三)添加面板(Panel)_第2张图片
    API_Search.png
  4. 学会排错 我们在自己写脚本的时候经常会出现各种各样的错误,这些 错误提示信息 通常出现会在系统控制台信息窗口 。根据这些错误提示信息,我们可以逐步找到并排除代码中的错误。
    菜鸟学bpy(三)添加面板(Panel)_第3张图片
    Info_and_System_Console.png

好了,下面进入正题。


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 分类找到新建的面板了。

菜鸟学bpy(三)添加面板(Panel)_第4张图片
Simple_Panel.png

写完这个面板之后,我试着把一些面板属性的代码 注释(#) 掉,发现也可以正常运行,在窗口中生成面板。
就像把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)
菜鸟学bpy(三)添加面板(Panel)_第5张图片
Another_Simple_Panel.png

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)

运行之后我们发现 信息窗口 报错了:

菜鸟学bpy(三)添加面板(Panel)_第6张图片
Info_Error.png

根据错误信息的指示,我们知道问题出在第 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 按钮,单击运行就得到下面的结果了,我们成功了。

菜鸟学bpy(三)添加面板(Panel)_第7张图片
Button_Added.png

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()

运行后添加四棱锥效果如下:


菜鸟学bpy(三)添加面板(Panel)_第8张图片
Property_Adjust.gif

4. 添加变换调节

正常我们添加网格物体,除了一些基本的属性调节之外,还应该有对齐到屏幕位移旋转的变换调节。

菜鸟学bpy(三)添加面板(Panel)_第9张图片
Transformation_Adjustment.png

那我们要怎么在自己的脚本里实现这一点呢?

首先,对齐到屏幕 要用到 BoolProperty,也就是布尔值;
位移旋转 则要用到 FloatVectorProperty,也就是向量。

然后就是前面我们新建网格物体用的是bpy.data.objects.new() 方法,这里不能用了,我们得用 object_utils.object_data_add()方法。区别在于后者可以使用operator作为参数,并使用自身的位移和旋转作为物体的变换参数。

菜鸟学bpy(三)添加面板(Panel)_第10张图片
objects.new.png
菜鸟学bpy(三)添加面板(Panel)_第11张图片
object_data_add.png

完整代码如下:

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(三)添加面板(Panel)_第12张图片
Property_Adjust_1.gif

这基本就是我想要的结果了。


好了,终于说完了。
前面三个部分的内容都是非常基础的,我也尽量保证连贯。后面的东西我也没有什么规划,很可能就是想到哪就写到哪了。
最后还想说的就是,我写这个的目的是分享一些我自己学bpy的经验,同时也希望能够帮到大家,让更多的人加入到学习bpy的行列中来。所以,我也希望大家看完之后能够把自己的学习经验分享出来,大家一起进步。
我新建了一个菜鸟学bpy的专题,这个是接受投稿的。大家可以在上写下自己的收获,并投稿这个专题。
当然,我还希望社区那些会bpy的大神也能来写几篇教程,指点一下大家。-

你可能感兴趣的:(菜鸟学bpy(三)添加面板(Panel))