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()在每个交互事件中调用的方法中都有一个聚焦循环,它覆盖所有与焦点对象无关的观察者.我将研究是否有一种方法可以移除焦点,以便它绕过此焦点循环并转到处理非焦点对象的未聚焦循环.
因此解决方案非常简单,但由于缺乏VTK提供的高质量文档,我不得不深入挖掘源代码来找到它.实际上,您需要做的就是Render()通过您用来处理TimerEvents的任何回调方法从每个交互者进行伪线程调用.我使用添加到每个交互器的ID属性(在下面提供的代码中看到)来完成此操作.你可以看到,每一次TimerEvent从发射irenR交互件的内部定时器(irenR处理右眼)的irenL的Render()函数被调用,反之亦然.
为了解决这个问题,我首先意识到标准的交互器功能(鼠标事件等)正常工作.所以我在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)
| 归档时间: |
|
| 查看次数: |
3328 次 |
| 最近记录: |