在 Blender 完全加载后执行脚本
Execute script after Blender is fully loaded
如何在 Blender 完全加载后自动执行 python 脚本?
上下文
我的脚本根据种子生成场景。我想创建几千个图像,但由于 Blender 在一百代左右后泄漏内存,所以一切都变得非常慢并最终崩溃。我想通过每次会话仅创建 x 个图像并在每次会话后完全重新启动 Blender 来缓解问题。
问题
如果我手动加载 blend 文件并单击脚本编辑器中的播放按钮,一切都会按预期进行。当我尝试在启动后调用脚本时,它在 add_curve_spirals.py
行 184 中崩溃,因为 context.space_data
是 None
。
由于手动启动脚本工作正常,问题是 Blender 处于某种错误状态。使用或不使用 GUI (--background
) 启动它都不会影响这一点。
失败的解决方案
blender myfile.blend --python myscript.py
在上下文完全准备好之前执行脚本,因此产生错误。
- 使用处理程序延迟执行 (
bpy.app.handlers.load_post
) 在完全加载文件后调用我的脚本,但上下文仍未准备好并产生错误。
- 将 Blender 中的脚本设置为在启动时自动执行 (Text/Register) 也会产生错误。
- 稍后使用套接字 as suggested here 向 Blender 发送命令。等待输入命令的服务器脚本在启动期间阻止 Blender 并阻止其完全加载,因此效果与直接执行脚本相同。
- 使用定时事件(
bpy.app.timers.register(render_fun, first_interval=10)
。
以上是我发现的自动执行脚本的所有方法。在每种情况下,脚本似乎都执行得太早/处于错误状态,并且都以相同的方式失败。
我想强调的是脚本不是这里的问题。即使我可以绕过特定行,也可能会出现许多类似的问题,我不想重写整个脚本。那么在正确的状态下自动调用它的最佳方法是什么?
事实证明,问题出在执行上下文上。这在手动调用定时事件后变得很清楚,例如场景完全加载后,定时事件仍然在错误的上下文中执行。
由于崩溃发生在 add_curve_spirals
插件中,解决方案是提供一个上下文覆盖运算符调用。我脚本的其余部分对上下文并不同样敏感,但工作得很好。
我不清楚我究竟应该如何覆盖上下文,但这目前有效(从互联网的其他部分收集,所以我不了解所有细节):
def get_context():
# create a context that works when blender is executed from the command line.
idx = bpy.context.window_manager.windows[:].index(bpy.context.window)
window = bpy.context.window_manager.windows[idx]
screen = window.screen
views_3d = sorted(
[a for a in screen.areas if a.type == 'VIEW_3D'],
key=lambda a: (a.width * a.height))
a = views_3d[0]
# override
o = {"window" : window,
"screen" : screen,
"area" : a,
"space_data": a.spaces.active,
"region" : a.regions[-1]
}
return o
最终调用:bpy.ops.curve.spirals(get_context(), spiral_type='ARCH', radius = radius, turns = turns, dif_z = dif_z, ...
如何在 Blender 完全加载后自动执行 python 脚本?
上下文
我的脚本根据种子生成场景。我想创建几千个图像,但由于 Blender 在一百代左右后泄漏内存,所以一切都变得非常慢并最终崩溃。我想通过每次会话仅创建 x 个图像并在每次会话后完全重新启动 Blender 来缓解问题。
问题
如果我手动加载 blend 文件并单击脚本编辑器中的播放按钮,一切都会按预期进行。当我尝试在启动后调用脚本时,它在 add_curve_spirals.py
行 184 中崩溃,因为 context.space_data
是 None
。
由于手动启动脚本工作正常,问题是 Blender 处于某种错误状态。使用或不使用 GUI (--background
) 启动它都不会影响这一点。
失败的解决方案
blender myfile.blend --python myscript.py
在上下文完全准备好之前执行脚本,因此产生错误。- 使用处理程序延迟执行 (
bpy.app.handlers.load_post
) 在完全加载文件后调用我的脚本,但上下文仍未准备好并产生错误。 - 将 Blender 中的脚本设置为在启动时自动执行 (Text/Register) 也会产生错误。
- 稍后使用套接字 as suggested here 向 Blender 发送命令。等待输入命令的服务器脚本在启动期间阻止 Blender 并阻止其完全加载,因此效果与直接执行脚本相同。
- 使用定时事件(
bpy.app.timers.register(render_fun, first_interval=10)
。
以上是我发现的自动执行脚本的所有方法。在每种情况下,脚本似乎都执行得太早/处于错误状态,并且都以相同的方式失败。
我想强调的是脚本不是这里的问题。即使我可以绕过特定行,也可能会出现许多类似的问题,我不想重写整个脚本。那么在正确的状态下自动调用它的最佳方法是什么?
事实证明,问题出在执行上下文上。这在手动调用定时事件后变得很清楚,例如场景完全加载后,定时事件仍然在错误的上下文中执行。
由于崩溃发生在 add_curve_spirals
插件中,解决方案是提供一个上下文覆盖运算符调用。我脚本的其余部分对上下文并不同样敏感,但工作得很好。
我不清楚我究竟应该如何覆盖上下文,但这目前有效(从互联网的其他部分收集,所以我不了解所有细节):
def get_context():
# create a context that works when blender is executed from the command line.
idx = bpy.context.window_manager.windows[:].index(bpy.context.window)
window = bpy.context.window_manager.windows[idx]
screen = window.screen
views_3d = sorted(
[a for a in screen.areas if a.type == 'VIEW_3D'],
key=lambda a: (a.width * a.height))
a = views_3d[0]
# override
o = {"window" : window,
"screen" : screen,
"area" : a,
"space_data": a.spaces.active,
"region" : a.regions[-1]
}
return o
最终调用:bpy.ops.curve.spirals(get_context(), spiral_type='ARCH', radius = radius, turns = turns, dif_z = dif_z, ...