提问人:Peter Lindhøj Tuxen 提问时间:10/21/2023 更新时间:10/21/2023 访问量:22
在 Python 中使用 VTK 制作序列动画
using vtk for a sequence animation in python
问:
我成功地使用以下代码制作了一个托盘的 3d 图像,该托盘托盘上有多个箱子。
import vtkmodules.all as vtk
#Create a renderer
renderer = vtk.vtkRenderer()
renderer.SetBackground(1, 1, 1)
# Create a render window
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
render_window.SetWindowName("Pallet Visualization")
# Create an interactor
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
# create the pallet
pallet_elements = [
(1200, 145, 22, 0, 0, 0),
(1200, 100, 22, 351, 0, 0),
(1200, 100, 22, -351, 0, 0),
(145, 100, 78, 351, 528, 50),
(145, 100, 78, -351, 528, 50),
(145, 100, 78, 351, -528, 50),
(145, 100, 78, -351, -528, 50),
(145, 100, 78, 351, 0, 50),
(145, 100, 78, -351, 0, 50),
(145, 145, 78, 0, 0, 50),
(145, 145, 78, 0, 528, 50),
(145, 145, 78, 0, -528, 50),
(145, 800, 22, 0, 0, 101),
(145, 800, 22, 0, 528, 101),
(145, 800, 22, 0, -528, 101),
(1200, 145, 22, 0, 0, 123),
(1200, 145, 22, 328, 0, 123),
(1200, 145, 22, -328, 0, 123),
(1200, 100, 22, 328 / 2, 0, 123),
(1200, 100, 22, -328 / 2, 0, 123)
]
for i, (width, length, height, x, y, z) in enumerate(pallet_elements):
pallet = vtk.vtkCubeSource()
pallet.SetXLength(length)
pallet.SetYLength(width)
pallet.SetZLength(height)
pallet_mapper = vtk.vtkPolyDataMapper()
pallet_mapper.SetInputConnection(pallet.GetOutputPort())
pallet_actor = vtk.vtkActor()
pallet_actor.SetMapper(pallet_mapper)
pallet_actor.SetPosition(x, y, z)
pallet_actor.GetProperty().SetColor(198 / 255, 99 / 255, 60 / 255)
renderer.AddActor(pallet_actor)
pallet_overlay = vtk.vtkCubeSource()
pallet_overlay.SetXLength(780)
pallet_overlay.SetYLength(1180)
pallet_overlay.SetZLength(2)
pallet_overlay_mapper = vtk.vtkPolyDataMapper()
pallet_overlay_mapper.SetInputConnection(pallet_overlay.GetOutputPort())
pallet_overlay_actor = vtk.vtkActor()
pallet_overlay_actor.SetMapper(pallet_overlay_mapper)
pallet_overlay_actor.SetPosition(0, 0, 136)
pallet_overlay_actor.GetProperty().SetColor(0.7, 0.7, 0.7)
renderer.AddActor(pallet_overlay_actor)
box_data = [
# First Tier
(1, 200, 400, 200, 0, 0, 0),
(1, 200, 400, 200, 0, 201, 0),
(1, 200, 400, 200, 0, 402, 0),
(1, 200, 400, 200, 0, 603, 0),
(1, 200, 400, 200, 401, 0, 0),
(1, 200, 400, 200, 401, 201, 0),
(1, 200, 400, 200, 401, 402, 0),
(1, 200, 400, 200, 401, 603, 0),
(1, 200, 400, 200, 802, 0, 0),
(1, 200, 400, 200, 802, 201, 0),
(1, 200, 400, 200, 802, 402, 0),
(1, 200, 400, 200, 802, 603, 0),
# Second Tier
(2, 400, 200, 200, 0, 0, 201),
(2, 400, 200, 200, 401, 0, 201),
(1, 200, 400, 200, 201, 0, 201),
(1, 200, 400, 200, 201, 201, 201),
(1, 200, 400, 200, 201, 402, 201),
(1, 200, 400, 200, 201, 603, 201),
(1, 200, 400, 200, 602, 0, 201),
(1, 200, 400, 200, 602, 201, 201),
(1, 200, 400, 200, 602, 402, 201),
(1, 200, 400, 200, 602, 603, 201),
(2, 400, 200, 200, 0, 1003, 201),
(2, 400, 200, 200, 401, 1003, 201),
# Third Tier
(1, 200, 400, 200, 0, 0, 403),
(1, 200, 400, 200, 0, 201, 403),
(1, 200, 400, 200, 0, 402, 403),
(1, 200, 400, 200, 0, 603, 403),
(1, 200, 400, 200, 401, 0, 403),
(1, 200, 400, 200, 401, 201, 403),
(1, 200, 400, 200, 401, 402, 403),
(1, 200, 400, 200, 401, 603, 403),
(1, 200, 400, 200, 802, 0, 403),
(1, 200, 400, 200, 802, 201, 403),
(1, 200, 400, 200, 802, 402, 403),
(1, 200, 400, 200, 802, 603, 403),
# Forth Tier
(2, 400, 200, 200, 0, 0, 604),
(2, 400, 200, 200, 401, 0, 604),
(1, 200, 400, 200, 201, 0, 604),
(1, 200, 400, 200, 201, 201, 604),
(1, 200, 400, 200, 201, 402, 604),
(1, 200, 400, 200, 201, 603, 604),
(1, 200, 400, 200, 602, 0, 604),
(1, 200, 400, 200, 602, 201, 604),
(1, 200, 400, 200, 602, 402, 604),
(1, 200, 400, 200, 602, 603, 604),
(2, 400, 200, 200, 0, 1003, 604),
(2, 400, 200, 200, 401, 1003, 604),
# Fifth Tier
(1, 200, 400, 200, 0, 0, 805),
(1, 200, 400, 200, 0, 201, 805),
(1, 200, 400, 200, 0, 402, 805),
(1, 200, 400, 200, 0, 603, 805),
(1, 200, 400, 200, 401, 0, 805),
(1, 200, 400, 200, 401, 201, 805),
(1, 200, 400, 200, 401, 402, 805),
(1, 200, 400, 200, 401, 603, 805),
(1, 200, 400, 200, 802, 0, 805),
(1, 200, 400, 200, 802, 201, 805),
(1, 200, 400, 200, 802, 402, 805),
(1, 200, 400, 200, 802, 603, 805)
]
# correction for position on the pallet, for right corner being Pos(0, 0, 0) for Tier 1, 3, 5
correctionXPos = - 400
correctionYPos = - 300
correctionZPos = 238
# correction for position on the pallet, right corner being Pos (0, 0, 0) for Tier 2, 4, 6
correctionXPos2 = -200
correctionYPos2 = -500
for i, (tier, width, length, height, x, y, z) in enumerate(box_data):
box = vtk.vtkCubeSource()
box.SetXLength(width)
box.SetYLength(length)
box.SetZLength(height)
box_mapper = vtk.vtkPolyDataMapper()
box_mapper.SetInputConnection(box.GetOutputPort())
if tier == 1:
x_pos = x + correctionXPos
y_pos = y + correctionYPos
z_pos = z + correctionZPos
else:
x_pos = y + correctionYPos2
y_pos = x + correctionXPos2
z_pos = z + correctionZPos
box_actor = vtk.vtkActor()
box_actor.SetMapper(box_mapper)
box_actor.SetPosition(y_pos, x_pos, z_pos)
box_actor.GetProperty().SetColor(0.2 + (i % 4) * 0.2, 0.4, 0.2 + (i % 3) * 0.2) # Color each box differently
renderer.AddActor(box_actor)
# Set up the camera
camera = vtk.vtkCamera()
camera.SetPosition(0, -3000, 4000)
camera.SetFocalPoint(0, 0, 0)
renderer.SetActiveCamera(camera)
# Start the rendering loop
render_window.Render()
interactor.Start()
然后我想做的是显示箱子被放置在托盘上的顺序。我找到了一个正方形动画的示例,该动画在屏幕上移动,使用以下代码
import time
import vtkmodules.all
class vtkTimerCallback():
def __init__(self, steps: int, actor: vtk.vtkActor, interactor: vtk.vtkRenderWindowInteractor):
self.timer_count = 0
self.steps = steps
self.actor = actor
self.interactor = interactor
self.timerID = None
def execute(self, obj: vtk.vtkRenderWindowInteractor, event):
step = 0
while step < self.steps:
print(self.timer_count)
self.actor.SetPosition(self.timer_count / 100, self.timer_count / 100, 0)
interactor = obj
interactor.GetRenderWindow().Render()
self.timer_count += 1
step += 1
if self.timerID:
interactor.DestroyTimer(self.timerID)
def main():
# Create the box
box = vtk.vtkCubeSource()
box.SetXLength(5)
box.SetYLength(5)
box.SetZLength(5)
# sphere = vtk.vtkSphereSource()
# sphere.SetCenter(0.0, 0.0, 0.0)
# sphere.SetRadius(100)
# sphere.SetPhiResolution(30)
# sphere.SetThetaResolution(30)
# Create mapper and actor
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(box.GetOutputPort())
actor = vtk.vtkActor()
actor.GetProperty().SetColor(0.5, 0.5, 0.5)
actor.SetMapper(mapper)
# actor.SetPosition(0, 0, 0)
# setup renderer and interactor
renderer = vtk.vtkRenderer()
renderer.SetBackground(0.1, 0.1, 0.1)
render_window = vtk.vtkRenderWindow()
render_window.SetWindowName("Animation test")
render_window.SetSize(600, 600)
render_window.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
# Add actor to the scene
renderer.AddActor(actor)
# Render and interact
render_window.Render()
renderer.GetActiveCamera().Zoom(0.5)
render_window.Render()
# initialize - prior to creating timer event
interactor.Initialize()
# sign up to timer event
cb = vtkTimerCallback(200, actor, interactor)
interactor.AddObserver('TimerEvent', cb.execute)
cb.timerID = interactor.CreateRepeatingTimer(3000)
# start the interaction and timer
render_window.Render()
interactor.Start()
if __name__ == '__main__':
main()
这工作正常。
然后,我尝试修改代码以按顺序在屏幕上显示 5 个框。这意味着在第一次迭代中,屏幕上应该有 1 个方块,在第二次迭代中,屏幕上应该有 2 个方块,依此类推。但此代码在每次迭代中仅显示 1 个方块,遵循顺序。此外,只有第一个方块具有设定的颜色。其余的都是黑色的。
修改后的代码如下:
import time
import vtkmodules.all
class vtkTimerCallback():
def __init__(self, box_data: [int, int, int, int, int, int], box_actor: vtk.vtkActor, mapper: vtk.vtkPolyDataMapper,
renderer: vtk.vtkRenderer, interactor: vtk.vtkRenderWindowInteractor):
self.timer_count = 0
self.box_data = box_data
self.box_actor = box_actor
self.mapper = mapper
self.renderer = renderer
self.interactor = interactor
self.timerID = None
def execute(self, obj, event):
step = 0
boxes = []
for i, (box_length, box_width, box_height, x, y, z) in enumerate(self.box_data):
print(i)
current_box = [box_length, box_width, box_height, x, y, z]
print(current_box)
boxes.append(current_box)
print(boxes)
for j, (box_length2, box_width2, box_height2, x2, y2, z2) in enumerate(boxes):
print(j)
box = vtk.vtkCubeSource()
box.SetXLength(box_length2)
box.SetYLength(box_width2)
box.SetZLength(box_height2)
self.mapper.SetInputConnection(box.GetOutputPort())
self.box_actor.SetMapper(self.mapper)
self.box_actor.GetProperty().SetColor(0.5, 0.5, 0.5)
self.box_actor.SetPosition(x2, y2, z2)
self.renderer.AddActor(self.box_actor)
print(self.box_actor.GetProperty().GetColor())
interactor = obj
interactor.GetRenderWindow().Render()
time.sleep(2)
if self.timerID:
interactor.DestroyTimer(self.timerID)
def main():
# Create the box
box = vtk.vtkCubeSource()
box.SetXLength(5)
box.SetYLength(5)
box.SetZLength(5)
# sphere = vtk.vtkSphereSource()
# sphere.SetCenter(0.0, 0.0, 0.0)
# sphere.SetRadius(100)
# sphere.SetPhiResolution(30)
# sphere.SetThetaResolution(30)
# Create mapper and actor
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(box.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
# actor.SetPosition(0, 0, 0)
actor.GetProperty().SetColor(0.5, 0.5, 0.5)
# setup renderer and interactor
renderer = vtk.vtkRenderer()
renderer.SetBackground(0.1, 0.1, 0.1)
render_window = vtk.vtkRenderWindow()
render_window.SetWindowName("Animation test")
render_window.SetSize(600, 600)
render_window.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
# renderer.AddActor(actor)
# render and interact
# camera = vtk.vtkCamera()
# camera.SetPosition(0, -6000, 1000)
# camera.SetFocalPoint(0, 0, 0)
# renderer.SetActiveCamera(camera)
render_window.Render()
renderer.GetActiveCamera().Zoom(0.2)
render_window.Render()
# initialize - prior to creating timer event
interactor.Initialize()
box_data = [(5, 5, 5, 0, 0, 0),
(5, 5, 5, 10, 10, 0),
(5, 5, 5, -10, -10, 0),
(5, 5, 5, -10, 10, 0),
(5, 5, 5, 10, -10, 0)
]
# sign up to timer event
cb = vtkTimerCallback(box_data, actor, mapper, renderer, interactor)
interactor.AddObserver('TimerEvent', cb.execute)
# This timer sets the time before the animation starts in
# milliseconds
cb.timerID = interactor.CreateRepeatingTimer(3000)
# start the interaction and timer
render_window.Render()
interactor.Start()
if __name__ == '__main__':
main()
我无法弄清楚我是否做错了什么,或者我试图做的事情是否根本不可能。
答: 暂无答案
评论