bpy基础
blender的核心由C/C++编写,包括计算、渲染等等,blender的接口是Python封装的,包括用户界面、插件等等,也就是bpy。
因此bpy的运行环境需要blender。
bpy接口分为数据读写、数据结构、消息、内核。
读写分为直接读写和通过工具读写两种。
###直接读写
bpy访问数据库由data模块提供,bpy.data可以访问blender中所有的数据块。我们在数据类型中讲述所有的数据实例方法。
cube = bpy.data.objects.get("cube")
names = [name for name in bpy.data.materials]
###上下文
上下文环境是blender的特性之一。上下文是对当前选中、当前激活、当前模式的记录。上下文的数据是context模块,操作是ops模块。
obj = bpy.context.active_object
selected_objs = bpy.context.selected_objects
bpy.ops.object.select_all()
bpy.ops.render.render()
###数据类型
types模块包含了blender绝大部分类型,如操作符、面板,总共3000余个,主要的有1000余个。当然,不包含python原生数据类型,int, list, str等等,此外不包含某些底层C结构体,如物理缓存、渲染引擎内部临时数据等等。
bpy.types.Light
bpy.types.Panel
bpy.types.ShaderNodeTree #着色器节点树
bpy.types.UILayout
这些类型都是抽象类,不能实例化。如果想创建一个类型的实例,需要通过不同方式创建。
有些需要在data中实例化,这被称作工厂模式:
mesh = bpy.data.meshes.new()
有些由注册类注册,且需继承:
1 | class MyPanel(bpy.types.Panel): |
特殊地,bpy.types.Macro是动态构建的。
如果把types看作结构体,那么其中的成员在bpy中对应props。实际上,types就是对核心C++结构体的python映射,不过props不简单的是成员映射,而是更复杂的序列化结构。
1 | class ApplyModifier(bpy.types.Operator): |
bpy在types中提供了PropertyGroup,它的好处除了将props集合起来,还可以复用。PropertyGroup可以继承后注册,特殊地,也可以直接实例化。
###内核与消息
bpy.app管理blender本身的状态。包含
bpy.app.handlers 钩子(Hooks)
bpy.app.translations 国际化(i18n)
bpy.app.timers 定时器
以及其他如version等等。
bpy.app.handlers在生命周期节点,如加载文件前/后、渲染前/后、帧变化前/后等调用钩子
1 | def my_handler(scene): |
钩子挂载仅在本次blender运行有效,因此注意如果重启blender需要重新挂载。
bpy.msgbus是新的接口,监听数据变化,是订阅-发布模式。这个接口较浅,对C数据变化不敏感,常用于UI。
有关回调的第三种方法,是定义在数据类型本身的方法。如bpy.types.SpaceView3D.draw_handler_add
###其他
path是blender的路径工具。utils是blender的其他工具模块。
我们对bpy的接口有了初步的认识,接下来深入bpy的生命周期、内存与回收。
bpy是对blender核心数据的反射,这被称作RNA(Reflaction Data Access)。
Blender使用“引用计数”和所有权管理内存,他不会自动回收数据,而是在手动Purge或保存后关闭时清理。bpy的数据是python负责,回收临时对象。
从UI开始,当用户点击鼠标 -> 操作系统
-> Blender Windows 调用 bpy.obs
–obs执行顺序:poll(检查) -> invoke(捕获鼠标) -> execute(执行)
-> 修改 bpy.data -> 涉及布尔运算?
–> yes bmesh读取mesh并计算 -> 写回mesh
–> no 直接下一步
-> bpy.data 设置为脏 -> 依赖图(DAG)设置相关联节点为脏
-> 渲染引擎或主程序循环请求Evaluate
-> 依赖图调度执行Modifier,计算约束 -> 生成副本Evaluated
-> 渲染引擎读取Evaluated -> GPU呈现
只有用户点击保存(或应用Apply)后Evaluated会存入原始数据。