Blender Python API中文介绍文档三

来源:互联网 发布:旅行水杯 知乎 编辑:程序博客网 时间:2024/06/06 05:01

Python API 总览

这篇文章揭示了Python和blender如何联系在一起,涵盖了一些API文档和例子脚本中没有明确的功能

Python in blender

Blender嵌入一个python的解释器,该解释器在Blender启动时加载并激活。这个解释器可以运行脚本来绘制用户界面,也用于Blender一些内部工具

这是一个典型的Python环境,所以如何写Python脚本的教学同样适用。Blender提供bpy模块给解释器盘,这个模块可以导入脚本并获取blender数据,类型和功能。处理blender数据的脚本必须导入这个模块4

以下是一个简单的例子,移动立方体一个顶点:

importbpy

bpy.data.objects["Cube"].data.vertices[0].co.x+=1.0

这直接修改Blender的文件的内部数据,当你在终端运行此命令时可以看到3D试图的更新

默认环境

开发你的脚本之时,了解blender如何启动其python环境很有帮助,很多python脚本与blender捆绑可以作为参考文档,因为他们使用同样的API以确保脚本将工具写入。典型的脚本包括:用户界面,导入导出,场景处理,自动化,设置自定义工具和用户定制

加载脚本

加载方式显而易见,但是要区别执行单个文件和执行模块的区别

脚本扩展Blender,它定义类型超出执行脚本的范畴,这使直接获取这些类型比导入模块从模块获取类型要困难

因此,在不需要注册类型扩展blender的情况下直接执行脚本优先考虑

这是直接在blender运行脚本的一些方式

1. 通过文本编辑器加载然后按下运行脚本

2. 在终端中加载

3. 在系统终端中执行命令行运行python文件

4.  blender --python /home/me/my_script.py

运行脚本模块的方式如下:

1.  明显的方式是: 从文本编辑器和终端命令中importsome_module命令

2. 以文本块打开,勾上注册选项,这回加载blend文件

3. 直接复制到路径scripts/startup,这样在启动时候会自动导入

4. 定义成一个插件,使插件可以以python模块加载

插件

一些blender功能可选保留,同时脚本在启动时候加载,插件都放在路径script/addons,只有在用户自定义界面启动选择了才能在启动时候加载

插件和内嵌python模块的区别是插件必须包含bl_info变量,它用来读取元数据,例如名字,作者,目录和URL

用户自定义插件罗列了每一个插件bl_info的信息

具体可以从See Addons查看bl_info

通过类型集成

运行脚本编辑器中的脚本很有效,但是想要像blender内嵌功能工具使用,api提供了这个集成功能:

  • bpy.types.Panel
  • bpy.types.Menu
  • bpy.types.Operator
  • bpy.types.PropertyGroup
  • bpy.types.KeyingSet
  • bpy.types.RenderEngine

这是故意的限制,对于高级功能例如网格修改,物体类型,着色器节点,必须使用C/C++

Python集成Blender定义的方法对于所有类型都通用。这通过blender类型的Python子类型工作,这些blender界面的基类包括变量和函数。

例如:

importbpy
classSimpleOperator(bpy.types.Operator):
    bl_idname ="object.simple_operator"
    bl_label ="Tool Name"
 
    defexecute(self, context):
        print("Hello World")
        return {'FINISHED'}
 
bpy.utils.register_class(SimpleOperator)

首先,注意通过bpy.types派生,这是一个通用的方法,这样使用可以使得我们明确这是一个操作不是注册面板。所有类属性都以bl_前缀开头。这可以用来区分Blender属性和自定义类型

然后,执行函数中以operator和当前context为参数,前缀不必在此加

最后,注册函数被调用,这将该类加载入blender,详见ClassRegistration

关于继承,blender没有利用各种继承类的限制,注册检查使用的是基类的属性和函数

例子:

importbpy
classBaseOperator:
    defexecute(self, context):
        print("Hello World BaseClass")
        return {'FINISHED'}
 
classSimpleOperator(bpy.types.Operator, BaseOperator):
    bl_idname ="object.simple_operator"
    bl_label ="Tool Name"
 
bpy.utils.register_class(SimpleOperator)

注意到这些类没有定义__init__函数,然而__init__()和__del__()如果定义了就会被调用,类实例生命周期只在执行期。例如每次重绘面板都会产生一个新的实例,因此仅仅在面板实例中存储变量。然而固定变量需要存储在blender数据中,这使得blender重启的时候可以保存状态

注意:模型操作是个例外,当Blender运行时保存模型操作的实例变量而不是存在blender数据中,请看模型操作模板

当blender中注册了类,实例化类型,调用函数,都是通过blender,实际上你无法从脚本实例化类,这和其他python api不同。

importbpy
bpy.ops.object.simple_operator()

用户界面类型通过给定的context绘制,按钮窗口,文件标题,工具条等等,当该区域显示时候绘制,不能直接以python脚本调用绘制。(?不是说没法从脚本实例化吗,是的!)

注册

模块注册

Blender在启动时加载模块,要求register()和unregister()函数。这是blender唯一的通过脚本代码调用的函数,在你的python脚本模块中

一个简单的blender/python模块是这样的:

importbpy
classSimpleOperator(bpy.types.Operator):
    """ See example above """
defregister():
    bpy.utils.register_class(SimpleOperator)
defunregister():
    bpy.utils.unregister_class(SimpleOperator)
if __name__ =="__main__":
    register()

这些函数通常放在包含类注册(有时添加菜单选项)的脚本底部,你也可以为了内部目的(为你自己的工具设置数据)来使用这些函数,但是要注意当一个新的blend文件加载时注册函数无法再次运行的。(注册一次)

类注册

blender注册一个类使得类定义被加载到blender中,类可以通过存在的函数来获取:

当类被加载,可以通过bpy.types获取(使用bl_idname,不是类的名字)

加载类之后,blender运行检查确保属性和功能可以找到,属性需要有正确的类型,功能函数要有正确的参数。

大部分时候你不需要关心这个,如果确实有问题,类定义会在注册时,通过函数参数def execute(self,context,spam)抛出一个异常:

ValueError: expected Operator, SimpleOperator class "execute" function to have 2 args, found 3使用bl_idname=1会引发如下错误:

TypeError: validating class error: Operator.bl_idname expected a string type, not int

多类

上述在blender加载类,简单的例子调用 bpy.utils.register_class足够了,当有很多类和包,子模块有自己的类,这样就显得冗余了

更方便的加载bpy.utils.register_module(module)和bpy.utils.unregister_module(module)函数

一个脚本定义看了很多自己的操作,面板菜单等等,你需要这样写:

defregister():
    bpy.utils.register_module(__name__)
 
defunregister():
    bpy.utils.unregister_module(__name__)

Blender集合了各个可注册类型子类,把他们存放在定义的模块中。通过bpy.utils.register_module注册所有的该模块和子模块的类

内部类依赖

用户属性也需要被注册才能使用

# Create new property
# bpy.data.materials[0].my_custom_props.my_float
importbpy
 
classMyMaterialProps(bpy.types.PropertyGroup):
    my_float = bpy.props.FloatProperty()
 
defregister():
    bpy.utils.register_class(MyMaterialProps)
    bpy.types.Material.my_custom_props= bpy.props.PointerProperty(type=MyMaterialProps)
 
defunregister():
    del bpy.types.Material.my_custom_props
    bpy.utils.unregister_class(MyMaterialProps)
 
if __name__ =="__main__":
    register()

如果不注册,会引发错误:

ValueError: bpy_struct "Material" registration error: my_custom_props could not register

子属性类定义与注册:

# Create new property group with a sub property
# bpy.data.materials[0].my_custom_props.sub_group.my_float
importbpy
 
classMyMaterialSubProps(bpy.types.PropertyGroup):
    my_float = bpy.props.FloatProperty()
 
classMyMaterialGroupProps(bpy.types.PropertyGroup):
    sub_group = bpy.props.PointerProperty(type=MyMaterialSubProps)
 
defregister():
    bpy.utils.register_class(MyMaterialSubProps)
    bpy.utils.register_class(MyMaterialGroupProps)
    bpy.types.Material.my_custom_props= bpy.props.PointerProperty(type=MyMaterialGroupProps)
 
defunregister():
    del bpy.types.Material.my_custom_props
    bpy.utils.unregister_class(MyMaterialGroupProps)
    bpy.utils.unregister_class(MyMaterialSubProps)
 
if __name__ =="__main__":
    register()

基类先注册,解注册正好相反

操作类

当blender运行的时候可以添加属性,伴随注册,但是有一些特殊的情况通过脚本修改类型是有用的

例如:

# add a new property to an existing type
bpy.types.Object.my_float= bpy.props.FloatProperty()
# remove
del bpy.types.Object.my_float

自定义的属性组的子类组也有类似操作:

classMyPropGroup(bpy.types.PropertyGroup):
    pass
MyPropGroup.my_float= bpy.props.FloatProperty()

等价于:

classMyPropGroup(bpy.types.PropertyGroup):
    my_float = bpy.props.FloatProperty()

动态类定义(高级)

数据,例如渲染着色器定义和删除类型on the fly

for i inrange(10):
    idname ="object.operator_%d"% i
 
    deffunc(self, context):
        print("Hello World",self.bl_idname)
        return {'FINISHED'}
 
    opclass =type("DynOp%d"% i,
                   (bpy.types.Operator, ),
                   {"bl_idname": idname, "bl_label":"Test","execute": func},
                   )
    bpy.utils.register_class(opclass)

通过type()函数来定义类,这是一个创建类的替代语义,适用于动态创建类

调用如下操作:

>>> bpy.ops.object.operator_1()
Hello World OBJECT_OT_operator_1
{'FINISHED'}
>>> bpy.ops.object.operator_2()
Hello World OBJECT_OT_operator_2
{'FINISHED'}
0 0
原创粉丝点击