无头Arcade#
对于某些应用程序,我们可能想要运行Arade,而不是打开一个窗口。我们可能希望绘制到缓冲区并保存图像,以便在服务器或数据科学可视化中使用。在远程云操作中,我们甚至可能没有用于计算机的显示器。以这种方式运行Arade被称为无头模式。
Arade可以在 headless mode 在Linux服务器上使用 EGL 安装完毕。这应该可以在桌面环境和服务器上工作,甚至在虚拟机上工作。根据您的用例,软件和硬件渲染都应该是可接受的。
我们正在利用侏儒中的无头模式。如果你想了解无头机器人的内部工作原理,那是个不错的选择。
启用无头模式#
需要配置无头模式 before Arade是导入的。这可以通过以下方式完成:
# Before arcade is imported
import os
os.environ["ARCADE_HEADLESS"] = "True"
# The above is a shortcut for
import pyglet
pyglet.options["headless"] = True
当然,这也意味着您可以在外部配置Headless。
$ export ARCADE_HEADLESS=True
要快速检查环境,如渲染器和版本::
$ python -m arcade
Arcade 2.6.12
-------------
vendor: AMD
renderer: AMD Radeon(TM) Vega 11 Graphics (RAVEN, DRM 3.41.0, 5.13.0-37-generic, LLVM 12.0.0)
version: (4, 6)
python: 3.9.9 (main, Dec 20 2021, 08:19:16)
[GCC 9.3.0]
platform: linux
这对我的代码有什么影响?#
在无头模式下,我们没有任何窗口事件或输入事件。这意味着像这样的事件 on_key_press
和 on_mouse_motion
永远不会被召唤。不是为无头设置创建的项目需要进行一些调整。
在无头模式下,Arcade Window
将改为扩展侏儒的无头窗口。我们已经添加了一个属性 arcade.Window.headless
(布尔)可以用来分离无头逻辑的。
请注意,窗口本身仍然有一个帧缓冲区,您可以对其进行渲染并从中读取像素。该帧缓冲区的大小是您在创建窗口时指定的大小。可以创建更多的帧缓冲区 ArcadeContext
如果需要的话。
警告
如果您要创建和销毁大量的街机对象,您可能需要查看 arcade.ArcadeContext.gc_mode
。在Arade中,我们通常每帧对OpenGL对象进行一次垃圾回收,方法是调用 gc()
。
警告
如果要加载越来越多的纹理,可能需要清理纹理缓存。这仅用于缓存 arcade.Texture
物体。看见 cleanup_texture_cache()
。如果您在精灵上使用这些纹理,这也可能涉及将它们从全局纹理图集中移除。
实例#
有两种推荐的方法: 简单无头模式 和 扩展Arade窗口时的无头模式 。
简单无头模式#
对于更简单的应用程序,我们不需要对窗口进行子类化。
# Configure headless before importing arcade
import os
os.environ["ARCADE_HEADLESS"] = "true"
import arcade
# Create a 100 x 100 headless window
window = arcade.open_window(100, 100)
# Draw a quick rectangle
arcade.draw_rectangle_filled(50, 50, 50, 50, color=arcade.color.AMAZON)
# Dump the framebuffer to a png
image = arcade.get_image(0, 0, *window.get_size())
image.save(f"framebuffer.png")
你可以自由地 clear()
窗口并随时呈现新内容。
扩展Arade窗口时的无头模式#
对于扩展窗口的Arade用户来说,这种方法更有意义。这个 run()
方法支持无头模式,并将通过调用 on_update
, on_draw
和 flip()
(交换缓冲区)循环,直到关闭窗口。
import os
os.environ["ARCADE_HEADLESS"] = "true"
import arcade
class App(arcade.Window):
def __init__(self):
super().__init__(200, 200)
self.frame = 0
self.sprite = arcade.Sprite(
":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png",
center_x=self.width / 2,
center_y=self.height / 2,
)
def on_draw(self):
self.clear()
self.sprite.draw()
# Dump the window framebuffer to disk
image = arcade.get_image(0, 0, *self.get_size())
image.save("framebuffer.png")
def on_update(self, delta_time: float):
# Close the window on the second frame
if self.frame == 2:
self.close()
self.frame += 1
App().run()
您还可以将代码拆分为 arcade.View
类,如果需要的话。这样做可能会使在开发过程中使用无头和无头模式变得更简单。您只需以编程方式关闭窗口并切换视图。我们可以轻松地将逻辑与 arcade.Window.headless
旗帜。当呼叫时 run()
我们还对每一帧的OpenGL资源进行垃圾收集。
进阶#
当然,更低级别的呈现API仍然可以通过 arcade.Window.ctx
。它公开了在OpenGL类型上创建帧缓冲区、纹理、着色器(包括计算着色器)和其他高级包装的方法。
在多GPU环境中工作时,您还可以选择特定的设备ID。默认情况下为0,必须在创建窗口之前进行设置。这些设备ID通常指的是物理设备(显卡)或虚拟卡/设备。
# Default setting
pyglet.options['headless_device'] = 0
# Use the second gpu/device
pyglet.options['headless_device'] = 1
有问题吗?#
如果您遇到问题或有问题,请在GitHub上创建问题或加入我们的不一致服务器。