我在编写一个Python VTK应用程序时,尝试运行多个渲染窗口时遇到了一些问题。该应用程序旨在为立体应用程序(即左渲染和右渲染)呈现一个3D模型的两个分离视图,但我在同时更新每个窗口的相机时遇到了问题。我目前设置了两个几乎相同的管道,每个管道都有自己的vtkCamera、vtkRenderWindow、vtkRenderer和vtkRenderWindowInteractor,唯一的区别是右侧相机在X轴上位置偏移30个单位。
通过调用一个简单的函数重置相机到它们的原始位置和方向, vtkRenderWindowInteractor.AddObserver()方法更新每个渲染窗口交互器。最大的问题是这似乎只在一个窗口上发生,特别是那个时刻处于焦点的窗口。这就好像交互器的计时器在失去焦点后就关闭了一样。此外,当我按住鼠标(因此移动相机),渲染出的图像开始“漂移”,尽管我已经将坐标硬编码到函数中,但其位置会越来越不正确。
显然我对VTK非常陌生,许多东西都很混乱,因为许多东西都隐藏在后台,所以获取一些关于此事的帮助将是惊人的。我的代码如下。谢谢大家!
通过调用一个简单的函数重置相机到它们的原始位置和方向, 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()
编辑:
经过进一步观察,似乎在鼠标单击事件之后,计时器事件不会连续触发多次,我不知道为什么。
编辑2: 取消上面所说的,根据我嵌入代码中的一些测试输出,它们肯定是在触发。我修改了代码,使其接受用户输入作为vtkGyroCallback.execute()
方法中的self.leftCam.SetPosition()
调用(因此使用三个输入变量替换了硬编码的“10, 40, 100”参数),然后将一个简单显示三个随机值的脚本的输出导入到我的主程序中。这个操作应该让渲染窗口的位置不断改变。但实际上,除非我点击屏幕,否则什么都不会发生,此时期望的功能开始出现。整个时间,计时器事件仍在触发,输入仍在被接受,但相机拒绝更新,直到窗口内发生鼠标事件。是怎么回事呢?
编辑3: 我继续研究发现,在每个交互事件中调用的vtkObject::InvokeEvent()
方法中有一个焦点循环,覆盖了所有与焦点对象无关的观察者。我将调查是否有一种方法可以去除焦点,使其绕过此焦点循环并进入处理非聚焦对象的非聚焦循环。
vtkRenderWindow
的方法很慢且笨重。我改用在单个vtkRenderWindow
中使用两个vtkRenderer
,帧率轻松提高到60FPS。此外,Oculus Rift不需要多个窗口,因为每个眼睛屏幕在技术上都是同一台监视器的一部分,所以您整个应用程序可以在一个窗口中运行。 - SwarthyMantooth