gpt4 book ai didi

python - VTK更新多个渲染窗口的位置

转载 作者:太空狗 更新时间:2023-10-29 21:46:21 30 4
gpt4 key购买 nike

尝试在我正在编写的 Python VTK 应用程序中运行多个渲染窗口时,我遇到了一些问题。该应用程序试图在立体应用程序的两个独立 View 中渲染 3D 模型(即左渲染和右渲染),但我在同时更新每个窗口的相机时遇到问题。我目前设置了两个几乎相同的管道,每个管道都有自己的 vtkCameravtkRenderWindowvtkRenderervtkRenderWindowInteractor ,唯一的区别是右侧相机沿 X 轴位置移动了 30 个单位。

每个渲染窗口交互器都通过 vtkRenderWindowInteractor.AddObserver() 方法进行更新,该方法调用一个简单的函数来将相机重置为其原始位置和方向。最大的问题是这似乎一次只发生在一个窗口上,特别是当时处于焦点的窗口。就好像一旦交互器失去焦点,交互器的计时器就会关闭。此外,当我按住鼠标(并因此移动相机)时,渲染图像开始“漂移”,重置到越来越不正确的位置,即使我已将坐标硬编码到函数中也是如此。

显然我是 VTK 的新手,而且发生的大部分事情都相当困惑,因为后端隐藏了太多内容,所以如果能在这方面获得一些帮助,那就太好了。我的代码如下。谢谢大家!

from vtk import*
from parse import *
import os
import time, signal, threading

def ParseSIG(signum, stack):
print signum
return

class vtkGyroCallback():
def __init__(self):
pass
def execute(self, obj, event):
#Modified segment to accept input for leftCam position
gyro = (raw_input())
xyz = parse("{} {} {}", gyro)
#This still prints every 100ms, but camera doesn't update!
print xyz

#These arguments are updated and the call is made.
self.leftCam.SetPosition(float(xyz[0]), float(xyz[1]), float(xyz[2]))
self.leftCam.SetFocalPoint(0,0,0)
self.leftCam.SetViewUp(0,1,0)
self.leftCam.OrthogonalizeViewUp()

self.rightCam.SetPosition(10, 40, 100)
self.rightCam.SetFocalPoint(0,0,0)
self.rightCam.SetViewUp(0,1,0)
self.rightCam.OrthogonalizeViewUp()

#Just a guess
obj.Update()
return

def main():

# create two cameras
cameraR = vtkCamera()
cameraR.SetPosition(0,0,200)
cameraR.SetFocalPoint(0,0,0)

cameraL = vtkCamera()
cameraL.SetPosition(40,0,200)
cameraL.SetFocalPoint(0,0,0)



# create a rendering window and renderer
renR = vtkRenderer()
renR.SetActiveCamera(cameraR)

renL = vtkRenderer()
renL.SetActiveCamera(cameraL)

# create source
reader = vtkPolyDataReader()
path = "/home/compilezone/Documents/3DSlicer/SlicerScenes/LegoModel-6_25/Model_5_blood.vtk"
reader.SetFileName(path)
reader.Update()

# create render window

renWinR = vtkRenderWindow()
renWinR.AddRenderer(renR)
renWinR.SetWindowName("Right")

renWinL = vtkRenderWindow()
renWinL.AddRenderer(renL)
renWinL.SetWindowName("Left")

# create a render window interactor
irenR = vtkRenderWindowInteractor()
irenR.SetRenderWindow(renWinR)

irenL = vtkRenderWindowInteractor()
irenL.SetRenderWindow(renWinL)

# mapper
mapper = vtkPolyDataMapper()
mapper.SetInput(reader.GetOutput())

# actor
actor = vtkActor()
actor.SetMapper(mapper)

# assign actor to the renderer
renR.AddActor(actor)
renL.AddActor(actor)

# enable user interface interactor
renWinR.Render()
renWinL.Render()
irenR.Initialize()
irenL.Initialize()

#Create callback object for camera manipulation
cb = vtkGyroCallback()
cb.rightCam = cameraR
cb.leftCam = cameraL
renWinR.AddObserver('InteractionEvent', cb.execute)
renWinL.AddObserver('InteractionEvent', cb.execute)
irenR.AddObserver('TimerEvent', cb.execute)
irenL.AddObserver('TimerEvent', cb.execute)
timerIDR = irenR.CreateRepeatingTimer(100)
timerIDL = irenL.CreateRepeatingTimer(100)

irenR.Start()
irenL.Start()

if __name__ == '__main__':
main()

编辑:

进一步查看后,似乎 TimerEvents 在 MouseClickEvent 之后没有连续触发一次以上,我不知道为什么。

编辑 2:从头开始,它们绝对是根据我嵌入代码中的一些测试输出触发的。我修改了代码以在 vtkGyroCallback.execute() 方法中接受 self.leftCam.SetPosition() 调用的用户输入(因此替换了硬编码的“10、40、 100"参数和三个输入变量)然后将简单显示三个随机值的脚本的输出通过管道传输到我的主程序中。这应该完成的是拥有一个不断改变位置的渲染窗口。相反,在我单击屏幕之前什么也没有发生,此时预期的功能开始了。在整个过程中,定时器事件仍在触发,输入仍在接受,但相机拒绝更新,直到在其窗口范围内发生鼠标事件。这是怎么回事?

编辑 3:我进一步研究发现,在每个交互事件中调用的 vtkObject::InvokeEvent() 方法中,有一个焦点循环覆盖了所有执行此操作的观察者与焦点对象无关。我将研究是否有一种方法可以移除焦点,以便它绕过这个焦点循环并转到处理非焦点对象的非焦点循环。

最佳答案

所以解决方案出奇地简单,但由于 VTK 提供的高质量文档不足,我不得不深入挖掘源代码来找到它。实际上,您所要做的就是通过您用来处理 TimerEvent 的任何回调方法从每个交互器调用伪线程 Render()。我使用添加到每个交互器的 ID 属性来做到这一点(见下面提供的代码)。您可以看到,每次从 irenR 交互器的内部计时器(irenR 处理右眼)触发 TimerEvent 时,irenL Render() 函数被调用,反之亦然。

为了解决这个问题,我首先意识到标准交互器功能(鼠标事件等)可以正常工作。因此,我深入了解了 vtkRenderWindowInteractor.cxx 中的源代码,并意识到这些方法被抽象为各个 vtkInteractorStyle 实现。在查看 vtkInteractorStyleTrackball.cxx 源代码后,我发现在 vtkRenderWindowInteractor 类中实际上有一个 Render() 函数。去搞清楚!文档肯定没有提到这一点!

不幸的是,同时进行两个渲染实际上非常慢。如果我只用一个窗口执行此方法(此时它变得不必要),它运行得很好。尽管有第二个窗口的帧率坦克。哦,好吧,你能做什么?

这是我更正后的代码(我终于可以开始处理我应该开发的内容了):

from vtk import*
from parse import *
import os
import time, signal, threading

def ParseSIG(signum, stack):
print signum
return

class vtkGyroCallback():
def __init__(self):
pass
def execute(self, obj, event):
#Modified segment to accept input for leftCam position
gyro = (raw_input())
xyz = parse("{} {} {}", gyro)
#print xyz



# "Thread" the renders. Left is called on a right TimerEvent and right is called on a left TimerEvent.
if obj.ID == 1 and event == 'TimerEvent':
self.leftCam.SetPosition(float(xyz[0]), float(xyz[1]), float(xyz[2]))
self.irenL.Render()
#print "Left"
elif obj.ID == 2 and event == 'TimerEvent':
self.rightCam.SetPosition(float(xyz[0]), float(xyz[1]), float(xyz[2]))
self.irenR.Render()
#print "Right"
return

def main():

# create two cameras
cameraR = vtkCamera()
cameraR.SetPosition(0,0,200)
cameraR.SetFocalPoint(0,0,0)

cameraL = vtkCamera()
cameraL.SetPosition(40,0,200)
cameraL.SetFocalPoint(0,0,0)



# create a rendering window and renderer
renR = vtkRenderer()
renR.SetActiveCamera(cameraR)

renL = vtkRenderer()
renL.SetActiveCamera(cameraL)

# create source
reader = vtkPolyDataReader()
path = "/home/compilezone/Documents/3DSlicer/SlicerScenes/LegoModel-6_25/Model_5_blood.vtk"
reader.SetFileName(path)
reader.Update()

# create render window

renWinR = vtkRenderWindow()
renWinR.AddRenderer(renR)
renWinR.SetWindowName("Right")

renWinL = vtkRenderWindow()
renWinL.AddRenderer(renL)
renWinL.SetWindowName("Left")

# create a render window interactor
irenR = vtkRenderWindowInteractor()
irenR.SetRenderWindow(renWinR)

irenL = vtkRenderWindowInteractor()
irenL.SetRenderWindow(renWinL)

# mapper
mapper = vtkPolyDataMapper()
mapper.SetInput(reader.GetOutput())

# actor
actor = vtkActor()
actor.SetMapper(mapper)

# assign actor to the renderer
renR.AddActor(actor)
renL.AddActor(actor)


# enable user interface interactor
renWinR.Render()
renWinL.Render()
irenR.Initialize()
irenL.Initialize()

#Create callback object for camera manipulation
cb = vtkGyroCallback()
cb.rightCam = renR.GetActiveCamera()#cameraR
cb.leftCam = renL.GetActiveCamera()#cameraL
cb.irenR = irenR
cb.irenL = irenL

irenR.ID = 1
irenL.ID = 2
irenR.AddObserver('TimerEvent', cb.execute)
irenL.AddObserver('TimerEvent', cb.execute)
timerIDR = irenR.CreateRepeatingTimer(100)
timerIDL = irenL.CreateRepeatingTimer(100)

irenL.Start()
irenR.Start()

if __name__ == '__main__':

main()

关于python - VTK更新多个渲染窗口的位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24540303/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com