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

时间:2014-07-02 20:17:34

标签: python render vtk stereo-3d

我尝试在我正在编写的Python VTK应用程序中运行多个渲染窗口时遇到了一些问题。该应用程序试图在立体应用程序的两个单独视图中呈现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:从表格中嵌入的一些测试输出来看,它们肯定会被激活。我修改了代码以接受self.leftCam.SetPosition()方法中vtkGyroCallback.execute()调用的用户输入(因此用三个输入变量替换硬编码的" 10,40,100和#34;参数)然后用管道传输输出一个脚本,只显示三个随机值到我的主程序中。这个应该完成的是拥有一个不断改变位置的渲染窗口。相反,在我点击屏幕之前没有任何反应,此时预期的功能开始了。整个时间,计时器事件仍在触发,输入仍然被接受,但是在窗口范围内发生鼠标事件之前,摄像机拒绝更新。这笔交易是什么?

编辑3:我已经挖掘了更多,发现在每个交互事件中调用的vtkObject::InvokeEvent()方法中,有一个聚焦循环覆盖所有与该对象无关的观察者。焦点。我将调查是否有一种方法可以移除焦点,以便它绕过此焦点循环并转到处理非焦点对象的未聚焦循环。

1 个答案:

答案 0 :(得分:6)

因此解决方案非常简单,但由于缺乏VTK提供的高质量文档,我不得不深入挖掘源代码来找到它。实际上,你需要做的就是通过你用来处理Render()的任何回调方法,来自每个交互者的伪线程TimerEvent调用。我使用添加到每个交互器的ID属性(在下面提供的代码中看到)来完成此操作。您可以看到每次从TimerEvent交互器的内部计时器(irenR处理右眼)触发irenR时,irenL的{​​{1}}功能被称为,反之亦然。

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

不幸的是,两次渲染实际上非常慢。如果我只使用一个窗口来执行此方法(此时它就变得不必要了),它运行得非常好。虽然框架坦克与第二个窗口。哦,你能做什么?

这是我更正后的代码(最后我可以开始研究假设正在开发的内容):

vtkRenderWindowInteractor