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

Swa*_*oth 7 python render stereo-3d vtk

尝试在我写的Python VTK应用程序中运行多个渲染窗口时,我遇到了一些问题.该应用程序尝试在立体应用程序的两个单独视图中呈现3D模型(即左渲染和右渲染),但我遇到同时更新每个窗口的摄像机的问题.我现在有设置了两个几乎相同的管道,每个都有自己的vtkCamera,vtkRenderWindow,vtkRenderer,和vtkRenderWindowInteractor,在于右照相机在位置上的唯一区别移位30个单元沿X轴.

每个渲染窗口交互器都通过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()
Run Code Online (Sandbox Code Playgroud)

编辑:

进一步查看后,似乎TimerEvents在MouseClickEvent之后连续多次触发并且我不知道为什么.

编辑2:从表格中嵌入的一些测试输出来看,它们肯定会被激活.我修改了代码以接受方法中self.leftCam.SetPosition()调用的用户输入vtkGyroCallback.execute()(因此用三个输入变量替换硬编码的"10,40,100"参数)然后将简单显示三个随机值的脚本输出传送到我的主程序中.这是什么应该已经完成是有一个渲染窗口,将不断改变位置.相反,在我点击屏幕之前没有任何反应,此时预期的功能开始了.整个时间,计时器事件仍在触发,输入仍然被接受,但是在窗口范围内发生鼠标事件之前,摄像机拒绝更新.这笔交易是什么?

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

Swa*_*oth 6

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

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

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

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

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()
Run Code Online (Sandbox Code Playgroud)