我尝试在我正在编写的Python VTK应用程序中运行多个渲染窗口时遇到了一些问题。该应用程序试图在立体应用程序的两个单独视图中呈现3D模型(即,左渲染和右渲染),但是我在同时更新每个窗口的摄像机时存在问题。我目前设置了两个几乎相同的管道,每个管道都有自己的vtkCamera
,vtkRenderWindow
,vtkRenderer
和vtkRenderWindowInteractor
,唯一的区别是右摄像头位置偏移沿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:从表格中嵌入的一些测试输出来看,它们肯定会被激活。我修改了代码以接受self.leftCam.SetPosition()
方法中vtkGyroCallback.execute()
调用的用户输入(因此用三个输入变量替换硬编码的" 10,40,100和#34;参数)然后用管道传输输出一个脚本,只显示三个随机值到我的主程序中。这个应该完成的是拥有一个不断改变位置的渲染窗口。相反,在我点击屏幕之前没有任何反应,此时预期的功能开始了。整个时间,计时器事件仍在触发,输入仍然被接受,但是在窗口范围内发生鼠标事件之前,摄像机拒绝更新。这笔交易是什么?
编辑3:我已经挖掘了更多,发现在每个交互事件中调用的vtkObject::InvokeEvent()
方法中,有一个聚焦循环覆盖所有与该对象无关的观察者。焦点。我将调查是否有一种方法可以移除焦点,以便它绕过此焦点循环并转到处理非焦点对象的未聚焦循环。
答案 0 :(得分:6)
因此解决方案非常简单,但由于缺乏VTK提供的高质量文档,我不得不深入挖掘源代码来找到它。实际上,你需要做的就是通过你用来处理Render()
的任何回调方法,来自每个交互者的伪线程TimerEvent
调用。我使用添加到每个交互器的ID属性(在下面提供的代码中看到)来完成此操作。您可以看到每次从TimerEvent
交互器的内部计时器(irenR
处理右眼)触发irenR
时,irenL
的{{1}}功能被称为,反之亦然。
为了解决这个问题,我首先意识到标准的交互功能(鼠标事件等)正常工作。所以我在vtkRenderWindowInteractor.cxx中挖掘了源代码,并意识到这些方法被抽象为各个Render()
实现。在vtkInteractorStyleTrackball.cxx源代码中生根后,我发现vtkInteractorStyle
类中实际上有一个Render()
函数。去搞清楚!文档肯定没有提到!
不幸的是,两次渲染实际上非常慢。如果我只使用一个窗口来执行此方法(此时它就变得不必要了),它运行得非常好。虽然框架坦克与第二个窗口。哦,你能做什么?
这是我更正后的代码(最后我可以开始研究假设正在开发的内容):
vtkRenderWindowInteractor