资讯专栏INFORMATION COLUMN

Blender Python API概述

魏宪会 / 659人阅读

摘要:在交互式控制台中运行此操作时,您将看到视口更新。键入或粘贴到交互式控制台中。用户首选项加载项列表使用显示有关每个加载项的信息。最后两行仅用于测试这允许脚本直接在文本编辑器中运行以测试更改。

Blender Python API概述

本文档的目的是解释Python和Blender如何组合在一起,涵盖了一些在阅读API参考和示例脚本时可能不明显的功能。

Python in Blender

Blender有一个嵌入式Python解释器,它在Blender启动时加载,并在Blender运行时保持活动状态。该解释器运行脚本来绘制用户界面,并用于Blender的一些内部工具。
Blender的嵌入式解释器提供了典型的Python环境,因此关于如何编写Python脚本的教程中的代码也可以使用Blender的解释器运行。Blender为嵌入式解释器提供了Python模块,例如bpy和mathutils,因此可以将它们导入到脚本中,并可以访问Blender的数据,类和函数。处理Blender数据的脚本需要导入模块才能工作。
这是一个简单的示例,它移动附加到名为Cube的对象的顶点:

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

这会直接修改Blender的内部数据。在交互式控制台中运行此操作时,您将看到3D视口更新。

默认环境

在开发自己的脚本时,了解Blender如何设置其Python环境可能会有所帮助。许多Python脚本与Blender捆绑在一起,可以用作参考,因为它们使用脚本作者编写工具的相同API。脚本的典型用法包括:用户界面,导入/导出,场景操作,自动化,定义自己的工具集和定制。
在启动时,Blender会扫描scripts/startup/目录中的Python模块并导入它们。此目录的确切位置取决于您的安装。请参阅目录布局文档。

脚本加载

这看起来很明显,但重要的是要注意直接执行脚本和将脚本作为模块导入之间的区别。
通过直接执行脚本来扩展Blender意味着脚本完成执行后脚本定义的类在Blender中保持可用。与将脚本作为模块导入相比,以这种方式使用脚本使得将来访问其类(例如取消注册它们)变得更加困难。将脚本作为模块导入时,其类实例将保留在模块中,稍后可以通过再次导入该模块来访问。
因此,最好避免直接执行通过注册类来扩展Blender的脚本。
以下是在Blender中直接运行脚本的一些方法。

在文本编辑器中加载并按Run Script。

键入或粘贴到交互式控制台中。

使用Blender从命令行执行Python文件,例如:

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

要作为模块运行:

显而易见的方法,来自文本窗口或交互式控制台的命令。import some_module

打开文本块并勾选“注册”选项,这将加载混合文件。

复制到其中一个目录中scripts/startup,它们将在启动时自动导入。

定义为加载项,启用加载项将其加载为Python模块。

附加组件

一些Blenders功能最好保持可选,除了在启动时加载的脚本我们有附加组件,这些附加组件保存在它们自己的目录中scripts/addons,并且只有在从用户首选项中选择时才会在启动时加载。
附加组件和内置Python模块之间的唯一区别是附加组件必须包含bl_info Blender用于读取元数据的变量,例如名称,作者,类别和URL。
用户首选项加载项列表使用bl_info显示有关每个加载项的信息。
有关bl_info字典的 详细信息,请参阅加载项。

通过类集成

在文本编辑器中运行Python脚本对于测试很有用,但是您需要扩展Blender以使工具可以像其他内置功能一样访问。
Blender Python 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接口的。
例如:

import bpy
class SimpleOperator(bpy.types.Operator):
    bl_idname = "object.simple_operator"
    bl_label = "Tool Name"

    def execute(self, context):
        print("Hello World")
        return {"FINISHED"}

bpy.utils.register_class(SimpleOperator)

首先请注意,我们将其成员子类化bpy.types,这对于可以与Blender集成并使用的所有类都是通用的,因此我们知道这是一个运算符而不是注册时的Panel。
两个类属性都以bl_前缀开头。这是一个用于区分Blender属性和您自己添加的属性的约定。
接下来看到execute函数,它接受运算符的实例和当前上下文。公共前缀不用于函数。
最后调用寄存器函数,这将获取类并将其加载到Blender中。请参阅班级注册。
关于继承,Blender不对所使用的类继承施加限制,注册检查将使用父类中定义的属性和函数。
class mix-in示例:

import bpy
class BaseOperator:
    def execute(self, context):
        print("Hello World BaseClass")
        return {"FINISHED"}

class SimpleOperator(bpy.types.Operator, BaseOperator):
    bl_idname = "object.simple_operator"
    bl_label = "Tool Name"

bpy.utils.register_class(SimpleOperator)

请注意,这些类没有定义__init__(self)函数。而__init__()和__del__()如果定义了将被调用,在类实例寿命仅跨越执行。因此,例如一个面板将为每次重绘都有一个新实例,因此很少有理由在面板实例中存储变量。相反,持久变量应存储在Blenders ata中,以便在重新启动Blender时可以恢复状态。
注意

模态运算符是一个例外,它们的实例变量保持为Blender运行,请参见模态运算符模板。
因此,一旦类在Blender中注册,实例化类并调用函数就由Blender完成。实际上,您无法像在大多数Python API中所期望的那样从脚本中实例化这些类。
要运行运算符,可以通过运算符api调用它们,例如:

import bpy
bpy.ops.object.simple_operator()

用户界面类给出了绘制,按钮窗口,文件头,工具栏等的上下文,然后在显示该区域时绘制它们,因此Python脚本不会直接调用它们。

注册 模块注册

启动时加载的Blender模块需要register()和unregister()功能。这些是Blender从您的代码调用的唯一函数,否则它是常规的Python模块。
一个简单的Blender / Python模块可能如下所示:

import bpy

class SimpleOperator(bpy.types.Operator):
    """ See example above """

def register():
    bpy.utils.register_class(SimpleOperator)

def unregister():
    bpy.utils.unregister_class(SimpleOperator)

if __name__ == "__main__":
    register()

这些函数通常出现在包含类注册的脚本的底部,有时会添加菜单项。您也可以将它们用于内部目的,为您自己的工具设置数据,但要小心,因为加载新的混合文件时寄存器不会重新运行。
使用了注册/取消注册调用,因此可以在Blender运行时切换加载项和重新加载脚本。如果寄存器调用放在脚本的主体中,则会在导入时调用注册,这意味着导入模块或将其类加载到Blender之间没有区别。
当脚本从另一个模块导入类时,这会成为问题,因为很难管理正在加载哪些类以及何时加载。
最后两行仅用于测试:

if __name__ == "__main__":
    register()

这允许脚本直接在文本编辑器中运行以测试更改。register()将脚本作为模块导入时,此调用将不会运行,因为__main__保留用于直接执行。

类注册

使用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(SomeClass)就足够了,但是当有很多类或子模块子模块有自己的类时,将它们全部列入注册可能会很繁琐。
为了更方便的加载/卸载bpy.utils.register_module(模块)和bpy.utils.unregister_module(模块)功能存在。
一个脚本,它定义了许多自己的操作符,面板菜单等,你只需要编写:

def register():
    bpy.utils.register_module(__name__)

def unregister():
    bpy.utils.unregister_module(__name__)

内部Blender在可注册类型上收集子类,通过定义它们的模块存储它们。通过将模块名称传递给bpy.utils.register_module Blender,可以注册该模块及其子模块创建的所有类。

类间依赖性

在自定义Blender时,您可能希望将自己的设置组合在一起,毕竟,它们可能必须与其他脚本共存。要对这些属性进行分组,需要定义类,对于组内的组或组内的集合,您可以发现自己必须处理注册/取消注册的顺序。
自定义属性组本身就是需要注册的类。
假设您要存储自定义引擎的材质设置。

# Create new property
# bpy.data.materials[0].my_custom_props.my_float
import bpy

class MyMaterialProps(bpy.types.PropertyGroup):
    my_float = bpy.props.FloatProperty()

def register():
    bpy.utils.register_class(MyMaterialProps)
    bpy.types.Material.my_custom_props = bpy.props.PointerProperty(type=MyMaterialProps)

def unregister():
    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
import bpy

class MyMaterialSubProps(bpy.types.PropertyGroup):
    my_float = bpy.props.FloatProperty()

class MyMaterialGroupProps(bpy.types.PropertyGroup):
    sub_group = bpy.props.PointerProperty(type=MyMaterialSubProps)

def register():
    bpy.utils.register_class(MyMaterialSubProps)
    bpy.utils.register_class(MyMaterialGroupProps)
    bpy.types.Material.my_custom_props = bpy.props.PointerProperty(type=MyMaterialGroupProps)

def unregister():
    del bpy.types.Material.my_custom_props
    bpy.utils.unregister_class(MyMaterialGroupProps)
    bpy.utils.unregister_class(MyMaterialSubProps)

if __name__ == "__main__":
    register()

注意

最低级别需要首先注册,而unregister()是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

这适用于您自己定义的PropertyGroup子类。

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

......这相当于:

class MyPropGroup(bpy.types.PropertyGroup):
    my_float = bpy.props.FloatProperty()
动态定义类(高级)

在某些情况下,数据的说明符可能不在Blender,renderman着色器定义中,例如,将它们定义为类型并在运行中删除它们可能很有用。
for i in range(10):

idname = "object.operator_%d" % i

def func(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()被调用来定义类。这是Python中类创建的替代语法,更适合动态构造类。
要从上一个示例中调用运算符:

>>> bpy.ops.object.operator_1()
Hello World OBJECT_OT_operator_1
{"FINISHED"}
>>> bpy.ops.object.operator_2()
Hello World OBJECT_OT_operator_2
{"FINISHED"}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/42160.html

相关文章

  • Blender参考API用法

    摘要:在控制台中输入路径。因此,下一步是通过参考文件检查访问画笔的位置。上下文画笔纹理对比度由于每个属性都是按照我们在控制台中组成数据路径的方式给出的可以有多种方式来访问相同的数据,您选择的方法通常取决于任务。 Blender参考API用法 Blender有许多互连数据类型,它们具有自动生成的引用api,它通常具有编写脚本所需的信息,但可能难以使用。 本文档旨在帮助您了解如何使用参考API。...

    MonoLog 评论0 收藏0
  • Blender插件教程

    摘要:插件教程什么是插件插件只是一个带有一些附加要求的模块,因此可以在包含有用信息的列表中显示它。安装附加组件时,将在控制台中打印源和目标路径。现在尝试将此脚本复制到并在默认多维数据集上运行它。 Blender插件教程 什么是插件?插件只是一个带有一些附加要求的Python模块,因此Blender可以在包含有用信息的列表中显示它。 举个例子,这是最简单的插件: bl_info = {name...

    scola666 评论0 收藏0
  • Blender下用Python实现模型文件导入、渲染和动画生成

    摘要:为了让数值计算的结果能够有更好的渲染效果,这段时间一直在用这个开源软件来处理计算结果。 为了让数值计算的结果能够有更好的渲染效果,这段时间一直在用Blender这个开源软件来处理计算结果。 因为是处理大量数据的计算结果,所以不得不考虑用Python编写脚本来实现批量处理,编写过程中,Google帮我解决了大部分实现过程中的障碍,下面是完整的实现过程: 将计算结果的mesh文件导入到...

    villainhr 评论0 收藏0
  • django官方文档1.11编翻:首页

    摘要:源网页说明文档所有关于你应该且必须知道的。性能和优化概述的兼容性旨在兼容多种不同版本的支持的兼容性地理框架打算成为世界级的地理框架。其目标是尽可能简单地构建应用程序并利用空间使能数据的功能。 源网页:https://docs.djangoproject.co... django说明文档 所有关于django你应该且必须知道的。 第一步 你是否django编程新手,那就从此开始!从零开始...

    Michael_Lin 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<