在 Python 中使用 VTK 制作序列动画

using vtk for a sequence animation in python

提问人:Peter Lindhøj Tuxen 提问时间:10/21/2023 更新时间:10/21/2023 访问量:22

问:

我成功地使用以下代码制作了一个托盘的 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()

我无法弄清楚我是否做错了什么,或者我试图做的事情是否根本不可能。

Python 动画 序列 VTK

评论


答: 暂无答案