今天毕设代码暂时算告一段落了,在上次中期的基础上加入了Phantom desktop的接入,提供触力觉反馈。其中触力觉反馈使用的是OpenHaptic的HDAPI
为了提供Haptic的支持主要解决2个问题
- Phantom设备的ServoLoop 1khz的力渲染与VTK15~30帧的图形渲染
- Phantom设备坐标系与VTK世界坐标系的匹配
关于问题1有两种解决的方法:
- 由于VTK的对象实现了subject/observer的模式,所以可以添加一个observer
- 使用Timer每间隔一段时间同步设备状态,渲染图形
由于UI是用QT实现的,所以VTK并不能自己处理重绘事件,所以这里选择了第2种方法,设置timer。在此之前曾尝试使用单独的绘制线程,但是由于VTK和OpenHaptic单独管理各自线程并且机制不同,无法在合适的时间同步设备状态,所以便用timer,这样使得图形渲染在同意线程中执行,也符合逻辑。
关于问题2
通过HDAPI可以获得探针姿态变换矩阵,利用HDU里的
void hduMapWorkspaceModel(const HDdouble *modelMatrix,
const HDdouble *projMatrix,
HDdouble *wsModelMatrix);
可以获得设备坐标系到世界坐标的变换,唯一要注意的是VTK内部矩阵是左乘,而OpenHaptic和OpenGL一样是右乘。
下面的代码片段描述了获得变换矩阵的方法
// get current render window vtkRenderer *ren = this->renderer_ ; // calculate the aspect from render window double aspect[2]; ren->ComputeAspect(); ren->GetAspect(aspect); double aspect2[2]; ren->vtkViewport::ComputeAspect(); ren->vtkViewport::GetAspect(aspect2); double aspectModification = aspect[0]*aspect2[1]/(aspect[1]*aspect2[0]); // get view port int viewport[4] ; ren->GetTiledSizeAndOrigin( // width viewport + 2, // height viewport + 3, // lower left x viewport, // lower left y viewport+1 ) ; // get the projection matrix vtkSmartPointer projection = vtkSmartPointer::New(); projection->DeepCopy(this->renderer_->GetActiveCamera() ->GetProjectionTransformMatrix( aspectModification*(viewport[2]/viewport[3]), -1.0, 1.0)) ; projection->Transpose() ; // get model view matrix vtkSmartPointer modelview = vtkSmartPointer::New(); modelview->DeepCopy(this->renderer_->GetActiveCamera() ->GetViewTransformMatrix()) ; modelview->Transpose() ; // Compute the transform for going from device coordinates to world // coordinates based on the current viewing transforms. ::hduMapWorkspaceModel(modelview->Element[0], projection->Element[0], this->workspace_model_) ;
下面的片段描述了如何利用获得的矩阵调整绘制视图中指针的姿态和位置。需要注意的是,变换之后会包换缩放的信息,如果不希望指针被莫名奇妙的缩放的话,需要去除缩放分量,可以使用vtkTransform类完成。
IHapticDevice::IHapticDeviceState *state =
this->device_in_graphic_->getCurrentState() ;
vtkSmartPointer workspace_model = vtkSmartPointer::New() ;
workspace_model->DeepCopy(state->getParentCumulativeTransform()) ;
workspace_model->Transpose() ;
vtkSmartPointer device_transform = vtkSmartPointer::New() ;
device_transform->DeepCopy(state->getTransform()) ;
device_transform->Transpose() ;
vtkSmartPointer device2view = vtkSmartPointer::New() ;
// set to the post multiply
device2view->PostMultiply() ;
// transform in work space
device2view->Concatenate(device_transform) ;
// transform to VTK view
device2view->Concatenate(workspace_model) ;
// set user transform
this->cursor_->SetPosition(device2view->GetPosition()) ;
this->cursor_->SetOrientation(device2view->GetOrientation()) ;
(完)