VTK②基础功能

基础功能里面有太多需要理解的东西了,从vtkRenderWindowInteractor, vtk Filter, vtkCamera, vtkLight开始吧

vtkRenderWindowInteractor

当对自己的数据做可视化的时候,显然咱得和可视化之后的数据有交互。所以尽管是非核心功能,也得有所了解。基本上,VTK提供了如下几种可选的方式:

  • 使用内建的vtkRenderWindowInteractor
  • 创建自己的交互器绑定相应的事件
  • 如果使用解释型语言,可以在运行时输入命令
  • 从屏幕上选取数据可以用“Picking”

最简单的方法当然就是用内建的vtkRenderWindowInteractor了,这个类已经为一系列预定义的事件和行为提供了响应,并且提供了override默认行为的方式。它允许咱们去控制Camera和Actor, 并且提供两种交互方式:①Position Sensitive,比如游戏操纵杆;②Motion Sensitive,比如轨迹球;下面就是已经定义好的事件响应(这里要特别指出的是,多个renderers可以渲染在同一个renderwindow,每个renderer有自己的viewport,而vtkRenderWindowInteractor支持和同一renderwindow中的多个render交互)

  • j键 和 t键: 在position sensitive(Joystick)和motion sensitive(Trackball)两种模式中切换。在J模式下,只要按鼠标键就可以持续运动;在T模式下,只有按着鼠标键拖动鼠标的时候,运动才会发生。

  • c键 和 a键: c代表Camera, a代表Actor。在C模式下,鼠标事件影响camera的位置和focalpoint;在A模式下,影响被鼠标指着的actor。

  • 鼠标按键1, 2, 3

    按键 模式 说明
    Button 1 Camera 让Camera绕其FocalPoint旋转
    Button 1 Actor 让Actor绕其原点旋转
    Button 2 Camera 平移Camera
    Button 2 Actor 平移Actor
    Button 3 Camera 缩放Camera
    Button 3 Actor 缩放Actor
  • 数字按键3: 切换render window的stereo mode

  • 按键e 或者 q: 退出应用

  • 按键f: 飞到鼠标点中的点,这事实上设置了focal point,然后允许围绕这个点旋转

  • 按键p: 提供 Pick 操作

  • 按键r: 重置camera

  • 按键s: 让所有的actor都有表面

  • 按键u: 进入用户定义的模式,也就是提供一个交互器,允许用户输入命令

  • 按键w: 和s是反向的,显示actor的三维线框模型

默认的交互style是position sensitive也就是J模式。

vtkRenderWindowInteractor还提供了另外一些有用的特性。

  • 比如默认的LightFollowCameraOn()会让light的位置和focal point和camera的位置和focal point保持同步。(当然,这个可以用LightFollowCameraOff()来关闭)
  • 用来响应【按键U模式】的回调,可以AddObserver(UserEvent)
  • 提供数种pick相关的方法,并AddObserver(StartPickEvent和EndPickEvent),还可以通过使用SetPicker()来继承vtkAbstractPicker,从而提供自定义的方法

另外,如果基于这些交互想调整渲染的质量的话,可以通过SetDesiredUpdateRate()来设置希望的帧率。通常情况下,这个是自动处理的(鼠标激活,帧率提升,鼠标释放,帧率恢复)

在VTK中,有两种不同的控制交互的方式:

  • 子类化 vtkInteractorStyle
    1
    2
    my_style = vtkInteractorStyleFlight()
    iren.SetInteractorStyle(my_style) # iren是一个vtkRenderWindowInteractor的实例
  • 在vtkRenderWindowInteractor增加oberservers,然后自定义一系列回调(3D 组件比较复杂, 以后另有专题)
    案例就参考 Examples/GUI/Python/CustomInteraction.py

Filter Data

这个容易理解多了,基本上可以看做Linux下面的管道的概念,继续拿CADPART来做说明:

1
2
3
4
5
6
7
8
9
part = vtk.vtkSTLRead()
part.SetFileName('42400-IDGH.stl')

shrink = vtk.vtkShrinkPolyData()
shrink.SetInputConnection(part.GetOutputPort())
shrink.SetShrinkFactor(0.85)

mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(shrink.GetOutputPort())

示意如下,需要注意的就是需要确保管道前后的数据类型的兼容:

1
2
3
4
graph LR
A[part] --> B(shrink)
B --> C[mapper]
C --> D[Actor]

vtkCamera

在3D图像处理中,Camera和Light对于渲染对象来说是非常重要的,所以如果程序没有显式声明的话,VTK会默认实例化camera和light。

  • 实例化一个相机,并和渲染实例联系起来

    1
    2
    3
    4
    5
    6
    7
    cam1 = vtk.vtkCamera()    #实例化一个camera
    cam1.SetClippingRange(0.0475572, 2.37786) #设定Clipping的范围,最近和最远,不在这个范围内的物体都自动被清除
    cam1.SetFocalPoint(0052665, -0.129454, -0.0573973) #方向
    cam1.SetPosition(0.327637, -0.116299, -0.256418) #位置
    cam1.ComputeViewPlaneNormal() # 默认的方式-这个需要具体学习一下
    cam1.SetViewUp(-0.0225386, 0.999137, 0.034901) # 相机向上的方向
    ren1.SetActiveCamera(cam1)

    CSDN上有很好的资料

  • 获得当前已经存在的相机实例

    1
    2
    cam1 = ren1.GetActiveCamera()
    cam1.Zoom(1.4) # 通过改变视角来了缩放(也可参考SetViewAngle()),另外还有Dolly()通过移动相机来缩放
  • 其他简单的操纵相机的方法【需要进一步理解】

    1
    2
    3
    4
    cam1.Azimuth(150)    # 相机以Focal Point为中心的球型轨迹移动的经度
    cam1.Elevation(160) # 相机以Focal Point为中心的球型轨迹移动的维度
    """ 要注意的就是一般情况下不会改变view-up vector,但是在南北极点会和view plane平行 """
    """ 为了避免这种情况,需要强制使用OrthogonalizeViewUp()方法(正交),这种情况会改变相机协同轨迹 """
  • 控制View的方向
    相机最基础的功能是产生一个特定方向的视图,在程序上是通过这样的步骤来实现的:

  1. 设置相机的Focal Point cam1.SetFocalPoint(0, 0, 0) #x, y, z
  2. 设置相机的Position cam1.SetPosition(1, 1, 1) #x,y, z
  3. 设置相机的ViewPanel cam1.ComputeViewPlaneNormal()
  4. 设置相机的ViewUp cam1.SetViewUp(1, 0, 0)
  5. 设置相机是否正交 cam1.OrthogonalizeViewUp()
  6. 设置相机为当前相机 ren1.SetActiveCamera(cam1)
  7. 重置相机 ren1.ResetCamera()
    也就是说:
    1
    2
    3
    graph LR
    A[设置相机基本属性] --> B[激活相机为当前相机]
    B --> C[重置舞台渲染的相机]
  • 透视(Perspective)和正交(Orghogonal)
    • 透视视图是通过视角(view angle)来调节角色(Actor)在View Plane上的成像的【点光源】
    • 正交或者平行视图可以想象成【平行光】,物体的成像是不受距离影响的
    *这里的光不是光源,而是从看的角度出发的
    要开启正交视图,首先用 cam1.ParallelProjectionOn()
    在正交视图中,视角不在用来控制缩放,而必须使用cam1.SetParallelScale()
  • 保存和恢复相机状态
    这其实不用多做介绍,保存相机状态,至少需要保存Position、Focal Point、Clipping Range和View Up;恢复的话首先用保存的参数实例化一个相机,然后多一个步骤就是要ren1.SetActiveCamera()
    DN

    vtkLight

    灯光比相机容易控制,最常用的方法就是SetPosition(), SetFocalPoint()SetColor();另外,相机的灯光可以用SwitchOn()SitchOff()开关;用SetIntensity()来控制强度
  • 默认的vtkLight实例是定向灯光,也就是说其位置(position)和焦点(focal point)定义了一个平行于光线行进方向的矢量,并且光源假定在无穷远处。这意味着如果位置和焦点被同样地改变的话,物体上的光照不变。
    通常,我们用如下的定义灯光,比如红色的头灯,位于相机的位置,指向相机的焦点。
    1
    2
    3
    4
    5
    light = vtk.vtkLight()
    light.SetColor(1, 0, 0)
    light.SetFocalPoint(cam1.GetFocalPoint())
    light.SetPosition(cam1.GetPosition())
    ren1.AddLight(light)
  • 定点光源Positional Lights【需要进一步理解】
    使用PositionalOn()可以创建一个定点光源,可以和SetConeAngle()一起使用来控制聚光的面积,如果是180度的锥角的话,表明没有聚光效果而只有位置效果。