本系列會使用 vispy 做 3D 的視覺化,因此本文讓讀者熟悉使用 vispy 簡單的畫出各種圖形,方便配合之後的實作。
vispy 是一個 interactive 視覺化的工具,提供了很多 2D/3D 視覺化相關的高階與底層 API,並且可以支援不同的 GUI 程式庫,因此使用起來很方便。
安裝套件,這裡使用 Qt6 為 GUI 的 backend,實際上 vispy 支援其他的例如 tkinter, glfw等:
pip install vispy
# 安裝 pyQt6 作為 GUI backend
pip install PyQt6
根據 API 層級層級的設計,分為幾種:
其中 gloo 和 visuals 屬於較為底層的 API ,需要對於 OpenGL / GLSL 有基本的認識,才會比較好上手。而 scene 和 plot 就隱藏了寫 shading language 的需要,由於 GLSL 不是我們想了解重點,且我們只是為了有3D的視覺化,幫助我們理解程式的結果,並不是要產生美美的電腦圖學渲染結果,因此本系列主要會講述和使用 vispy.scene。
首先第一步是建立 canvas 和 canvas 裡的 view:
import sys
from vispy import app, scene
# Create canvas
canvas = scene.SceneCanvas(title="vispy tutorial", keys="interactive", show=True)
# Make color white
canvas.bgcolor = "white"
# Create view and set the viewing camera
view = canvas.central_widget.add_view()
view.camera = "turntable"
view.camera.fov = 50
view.camera.distance = 10
# TODO: Add objects to the view
if __name__ == "__main__":
if sys.flags.interactive != 1:
app.run()
執行的話會得到一個空白的框,基本上之後的工作都會依照這樣的 template ,變得只是中間 TODO 的那個部分。
view.camera 代表了 GUI 視窗看場景的相機設定,可以設定不同的模式,例如 turntable, panzoom, fly ,這裡我們使用 turntable(可以旋轉、放大、移動) ,並且設定 fov (視角大小) 和 distance(遠近):
view.camera = "turntable"
view.camera.fov = 50
view.camera.distance = 10
然後我們可以加入物體,例如透過 scene.visuals.Cube
產生一個正方體
import sys
from vispy import app, scene
# Create canvas
canvas = scene.SceneCanvas(title="vispy tutorial", keys="interactive", show=True)
# Make color white
canvas.bgcolor = "white"
# Create view and set the viewing camera
view = canvas.central_widget.add_view()
view.camera = "turntable"
view.camera.fov = 50
view.camera.distance = 10
# Add a red cube
scene.visuals.Cube(color="red", parent=view.scene)
if __name__ == "__main__":
if sys.flags.interactive != 1:
app.run()
這裡我們透過 parent=view.scene
來把建立的正方體放到場景裡面,我們也可以換成以下方式:
# scene.visuals.Cube(color="red", parent=view.scene)
cube = scene.visuals.Cube(color="blue", edge_color="black")
view.add(cube)
並且因為前面設置 view.camera = "turntable"
,我們是可以透過滑鼠旋轉,滾輪放大縮小,shift+左鍵移動物體的。
接下來,我們改成建立一個 3D 球,並且在 3D 中移動他的位置。最後,在原點放一個座標 R, G, B 分別代表 X, Y, Z 軸:
# Create sphere
sphere = scene.visuals.Sphere(radius=0.5, color="red", parent=view.scene, shading="smooth")
# Create transform
transform = scene.transforms.MatrixTransform()
transform.translate((1, 1, 1))
# Assign transform to the sphere
sphere.transform = transform
# Create a 3D axis at the origin
scene.visuals.XYZAxis(parent=view.scene)
夠過新增一個 timer 我們還可讓球體動起來,在原本的 code 下面新增這段:
def update(event):
# Rotate the sphere a bit along the y-axis
sphere.transform.rotate(1, (0, 1, 0))
timer = app.Timer()
timer.connect(update)
timer.start(0)
就可以得到一個沿著 y 軸旋轉的球體了