GUI 系统
Taichi 有一个内置的 GUI 系统,用于对 Taichi fields 或 NumPy ndarray 等数据容器内的数据行进视觉模拟 Taichi GUI 同时对基本几何体的绘制提供了简单的支持。
创建并显示窗口
以下代码创建了一个 640x360
窗口,其标题为“Hello World!”,并通过调用 gui.show()
来显示它:
gui = ti.GUI('Hello World!', (640, 360))
while gui.running:
gui.show()
note
请在 while
循环内调用 gui.show()
。 否则,这个窗口将闪烁一次后消失。
关闭窗口
您可以在 while
循环内通过设置 gui.running=False
关闭GUI:
gui = ti.GUI('Window Title', (640, 360))
while gui.running:
if some_events_happend:
gui.running = False
gui.show()
坐标系统
每个窗口都建立在坐标系统上:坐标原点位于左下角, +x
方向向右延伸, +y
方向向上延伸。
显示一个 field 或 ndarray
请调用 gui.set_image()
显示Taichi field 或 NumPy ndarray。 该方法接受这两种类型作为输入。
image = ti.Vector.field(3, ti.f32, shape=(640, 480))
while gui.running:
gui.set_image(image)
gui.show()
因为Taichi field 是一个 全局的 数据容器, 如果向量 field image
在while
循环之间被更新过,GUI 窗口将会刷新以显示最新图像。
IMPORTANT
请确保输入的形状与GUI 窗口的分辨率相匹配。
Zero-copying frame buffer
在 gui.et_image()
方法调用的每个循环内, GUI 系统都会将图像数据转换为可显示的格式,并将结果复制到窗口缓冲区。 当窗口大小较大时,这会造成巨大的超负荷,使得很难实现高 FPS (每秒帧率)。
如果您只需要调用 set_image()
方法而不使用任何绘图命令, 您可以启用 fast_gui
模式以提高性能。 这种模式允许 Taichi GUI 直接将图像数据写入帧缓冲器而不需要额外复制,大幅增加了 FPS。
gui = ti.GUI(res, title, fast_gui=True)
要使这种模式能够正常运行,请确保传入 gui.set_image()
的数据格式与显示器兼容。 换言之,如果它是Taichi field,请确保它是以下之一:
- a vector field
ti.field(3, dtype, shape)
compatible with RGB format. - 向量 field
ti.field(4, dtype, shape)
,兼容 RGBA 格式。
注意 dtype
必须是 ti.f32
, ti.f64
, 或 ti.u8
的其中之一。
在窗口上绘画
Taichi 的 GUI 系统支持绘制简单的几何形状,如线、三角形、长方形、圆圈和文字等。
每个绘图方法的 pos
参数都接受 Taichi field 或 NumPy 数组。 不是 Python 原始数据类型。 field 或数组的每个元素都是一对浮点数,从 0.0
到 1.0
代表几何形状的相对位置。 例如:
(0.0, 0.0)
: 窗口左下角。(1.0, 1.0)
: 窗口右上角。
下面的代码绘制了 50 个半径为 5
的圆圈,共有三种不同的颜色由 一个大小与 pos
相同的整数数组 indices
随机分配, 。
import numpy as np
pos = np.random.random((50, 2))
# Create an array of 50 integer elements whose values are randomly 0, 1, 2
# 0 corresponds to 0x068587
# 1 corresponds to 0xED553B
# 2 corresponds to 0xEEEEF0
indices = np.random.randint(0, 2, size=(50,))
gui = ti.GUI("circles", res=(400, 400))
while gui.running:
gui.circles(pos, radius=5, palette=[0x068587, 0xED553B, 0xEEEEF0], palette_indices=indices)
gui.show()
下面的代码绘制五个蓝色线段,其宽度为2, 其中的 x
和 y
分别代表五个线段的起点和终点。
import numpy as np
X = np.random.random((5, 2))
Y = np.random.random((5, 2))
gui = ti.GUI("lines", res=(400, 400))
while gui.running:
gui.lines(begin=X, end=Y, radius=2, color=0x068587)
gui.show()
以下代码绘制了两个橙色三角形橙色,其中 x
, y
, 和 z
分别代表这三个三角形的三个顶点。
import numpy as np
X = np.random.random((2, 2))
Y = np.random.random((2, 2))
Z = np.random.random((2, 2))
gui = ti.GUI("triangles", res=(400, 400))
while gui.running:
gui.triangles(a=X, b=Y, c=Z, color=0xED553B)
gui.show()
事件处理
Taichi的图形界面系统也提供了一套方法用于鼠标和键盘的控制。 输入事件分为三类:
ti.GUI.RELEASE # key up or mouse button up
ti.GUI.PRESS # key down or mouse button down
ti.GUI.MOTION # mouse motion or mouse wheel
事件键指的是您从键盘或鼠标中按下的键。 可以是以下其中之一
# for ti.GUI.PRESS and ti.GUI.RELEASE event:
ti.GUI.ESCAPE # Esc
ti.GUI.SHIFT # Shift
ti.GUI.LEFT # Left Arrow
'a' # we use lowercase for alphabet
'b'
...
ti.GUI.LMB # Left Mouse Button
ti.GUI.RMB # Right Mouse Button
# for ti.GUI.MOTION event:
ti.GUI.MOVE # Mouse Moved
ti.GUI.WHEEL # Mouse Wheel Scrolling
事件过滤器 可以是 key、 type 或 (type, key) 元组。 例如:
# if ESC pressed or released:
gui.get_event(ti.GUI.ESCAPE)
# if any key is pressed:
gui.get_event(ti.GUI.PRESS)
# if ESC is pressed or SPACE is released:
gui.get_event((ti.GUI.PRESS, ti.GUI.ESCAPE), (ti.GUI.RELEASE, ti.GUI.SPACE))
gui.get_event()
将一个事件从队列中抛出并保存到 gui.event
。 例如:
if gui.get_event():
print('Got event, key =', gui.event.key)
下面的代码定义了 当
循环持续到 ESC 键被按下
gui = ti.GUI('Title', (640, 480))
while not gui.get_event(ti.GUI.ESCAPE):
gui.set_image(img)
gui.show()
gui.is_pressed()
检测到按键。 如下代码片段所示,您必须将它与 gui.get_event()
一起调用。 否则,按键将不会被更新。
例如:
while True:
gui.get_event() # must be called before is_pressed
if gui.is_pressed('a', ti.GUI.LEFT):
print('Go left!')
elif gui.is_pressed('d', ti.GUI.RIGHT):
print('Go right!')
warning
Call gui.get_event()
before calling gui.is_pressed()
. Otherwise, gui.is_pressed()
does not take effect.
获取光标位置
gui.get_cursor_pos()
返回光标在当前窗口的位置。 返回值是范围内 [0.0, 1.0]
的一对浮点数。 例如:
mouse_x, mouse_y = gui.get_cursor_pos()
GUI 窗口部件
Taichi 的 GUI 系统也提供了包括 slider()
, label()
, 和 buton()
在内的窗口部件, 方便您自定义您的控制界面。 请看以下代码片段:
import taichi as ti
gui = ti.GUI('GUI widgets')
radius = gui.slider('Radius', 1, 50, step=1)
xcoor = gui.label('X-coordinate')
okay = gui.button('OK')
xcoor.value = 0.5
radius.value = 10
while gui.running:
for e in gui.get_events(gui.PRESS):
if e.key == gui.ESCAPE:
gui.running = False
elif e.key == 'a':
xcoor.value -= 0.05
elif e.key == 'd':
xcoor.value += 0.05
elif e.key == 's':
radius.value -= 1
elif e.key == 'w':
radius.value += 1
elif e.key == okay:
print('OK clicked')
gui.circle((xcoor.value, 0.5), radius=radius.value)
gui.show()