vtk.js 实战之多交互器

893 阅读2分钟

VTK中的vtkFullScreenRenderWindow默认交互器Style是InteractorStyleTrackballCamera

但是这个交互器默认只能处理以下的events:

  • Left Mouse: Rotate
  • Left Mouse + Shift: Pan
  • Left Mouse + Ctrl/Alt: Spin
  • Left Mouse + Shift + Ctrl/Alt: Dolly
  • Mouse Wheel: Dolly
  • Multi-Touch Rotate: Rotate
  • Multi-Touch Pinch: Dolly
  • Multi-Touch Pan: Pan
  • 3D Events: Camera Pose

由于现在的需求是左键平移 滚轮放大 右键来进行旋转 ,这就导致当前的右键事件缺失以及相应的功能事件无法完成。

所以这个时候需要进行多交互器的设计。

本章你将会学到以下知识:

  1. vtkFullScreenRenderWindow的源码中是用了哪一种Interactor和interactorStyle.
  2. 如何使用多交互器操纵器来进行有效的事件分发来处理不同的事件
  3. 实现移动 缩放和旋转功能

1:查看vtkFullScreenRenderWindow中的代码:

model.interactor = vtkRenderWindowInteractor.newInstance();
model.interactor.setInteractorStyle(vtkInteractorStyleTrackballCamera.newInstance());

发现这个interactor 是用的RenderWindowInteractor,interactorStyle 是用的InteractorStyleTrackballCamera

vtkRenderWindowInteractor用于获取渲染窗口上发生的鼠标,键盘,事件事件。该类提供了独立于平台的与渲染窗口进行交互的机制,包括picking 和帧速率控制。当vtkRenderWindowInteractor(事实上是他的一个子类)观察到平台的某个事件发生时,他就通过InvokeEvent()方法把该事件转换为VTK事件,而interactorStyle 就是处理这些事件的类。

2:添加多交互器收集不同的事件来做相应的处理

去interaction下面的Manipulators 下面去看有那些对应鼠标的交互器

编辑

添加图片注释,不超过 140 字(可选)

根据这些名字应该找包含CameraTrackBall中的,发现

MouseCameraTrackballPanManipulator 这个里面有个Pan 去对应的API文档看看

好家伙,直接是源码。

其他二个也是类似:

MouseCameraTrackballRotateManipulator和MouseCameraTrackballZoomManipulator

但是光有这3个交互器 如何和窗口绑定呢?继续看

这个interactorStyle 中带有Manipulator 说明是否和它有关系呢?

看源码中

function applyDefinitions(definitions, manipulatorStyle) {
  manipulatorStyle.removeAllManipulators();
  for (let idx = 0; idx < definitions.length; idx++) {
    const definition = definitions[idx];
    const instance = MANIPULTOR_TYPES[definition.type].newInstance(
      definition.options
    );
    if (instance.isA('vtkCompositeVRManipulator')) {
      manipulatorStyle.addVRManipulator(instance);
    } else if (instance.isA('vtkCompositeGestureManipulator')) {
      manipulatorStyle.addGestureManipulator(instance);
    } else if (instance.isA('vtkCompositeKeyboardManipulator')) {
      manipulatorStyle.addKeyboardManipulator(instance);
    } else {
      manipulatorStyle.addMouseManipulator(instance);
    }
  }

  return true;
}

manipulatorStyle.addMouseManipulator这句话不就是可以增加其他的交互器,如是乎我有个大胆的猜测就是它了。为了验证,下面代码来实现:

本实例是介入上次的实例继续添加代码的

导入vtk 需要的类

import vtkInteractorStyleManipulator from "@/vtk.js/Interaction/Style/InteractorStyleManipulator";
import vtkMouseCameraTrackballPanManipulator from "@/vtk.js/Interaction/Manipulators/MouseCameraTrackballPanManipulator";
import vtkMouseCameraTrackballRotateManipulator from "@/vtk.js/Interaction/Manipulators/MouseCameraTrackballRotateManipulator";
import vtkMouseCameraTrackballZoomManipulator from "@/vtk.js/Interaction/Manipulators/MouseCameraTrackballZoomManipulator";

获取对应的interactor 以及设置Style

 const interactorStyle = vtkInteractorStyleManipulator.newInstance();
 const interator = fullScreenRenderWindow.getInteractor();
 interator.setInteractorStyle(interactorStyle);

声明对应的变量和初始化

const uiComponents = {};
uiComponents["leftButton"] = {
 manipName: "Pan",
};
uiComponents["rightButton"] = {
 manipName: "Rotate",
};
uiComponents["scrollMiddleButton"] = {
 manipName: "Zoom",
};
const selectMap = {
 leftButton: { button: 1 },
 middleButton: { button: 2 },
 rightButton: { button: 3 },
 scrollMiddleButton: { scrollEnabled: true, dragEnabled: false },
};

const manipulatorFactory = {
 Pan: vtkMouseCameraTrackballPanManipulator,
 Zoom: vtkMouseCameraTrackballZoomManipulator,
 Rotate: vtkMouseCameraTrackballRotateManipulator,
};

注册对应的manipulator,在注册前先要remove所有的Manipulators ,防止多添加了。

function reassignManipulators(interactorStyle) {
 interactorStyle.removeAllMouseManipulators();
 Object.keys(uiComponents).forEach((keyName) => {
 const klass = manipulatorFactory[uiComponents[keyName].manipName];
 if (klass) {
 const manipulator = klass.newInstance();
 manipulator.setButton(selectMap[keyName].button);

 if (selectMap[keyName].scrollEnabled !== undefined) {
 manipulator.setScrollEnabled(selectMap[keyName].scrollEnabled);
      }
 if (selectMap[keyName].dragEnabled !== undefined) {
 manipulator.setDragEnabled(selectMap[keyName].dragEnabled);
      }
 interactorStyle.addMouseManipulator(manipulator);
    }
  });
}

将以上函数放入以下代码前即可

 reassignManipulators(interactorStyle);
 const renderer = fullScreenRenderWindow.getRenderer();