VTK_Learning_交互與拾取_點拾取

1.拾取

選擇拾取是人機交互過程的一個重要功能。
一個最經典的例子就是,在玩3D遊戲時,場景中可能會存在多個角色,有時需要用鼠標來選擇所要控制的角色,這就要用到拾取功能。
另外,在某些三維圖形的編輯軟件中,經常需要編輯其中的一個點、一個面片或者一個局部區域,這也需要通過拾取功能來完成。
VTK中定義了多個拾取功能的類,具體的繼承關係如下:

VTK中所有的拾取類都繼承自vtkAbstractPicker類,在這些類的基礎之上可以實現非常複雜的功能。

 

2.點拾取 

從上圖中能夠知曉,完成點拾取功能的類是vtkPointPicker。
vtk中的消息是通過vtkRenderWindowInteractor類處理的,在類vtkRenderWindowInteractor中,定義如下函數:
virtual void SetPicker(vtkAbstractPicker*  );
該函數用來設置具體的VTKAbstractPicker對象,並執行相應的拾取操作。因此對於點拾取,實際就是設置VTKPointPicker的過程。
之前,曾經細緻的研究過,vtkRenderWindowInteractor內部定義了一個vtkInteractorStyle對象。vtkInteractorStyle類是一個虛基類,其子類定義了多種鼠標和鍵盤消息的處理方法,在實現拾取操作是,需要定製相應的鼠標消息處理函數。比如拾取某個點時,應該響應鼠標的左鍵按下消息,並在響應該消息的函數中根據鼠標的當前窗口座標來完成拾取操作。
點拾取的示例代碼如下:
 

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL)
VTK_MODULE_INIT(vtkRenderingFreeType)
VTK_MODULE_INIT(vtkInteractionStyle)
 
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
 
#include <vtkPointPicker.h>
//this->Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()
#include <vtkRendererCollection.h> 
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkObjectFactory.h>  //vtkStandardNewMacro();
#include <vtkProperty.h>
 
#include <vtkAxesActor.h>
#include <vtkOrientationMarkerWidget.h>
/**************************************************************************************************/
class PointPickerInteractorStyle : public vtkInteractorStyleTrackballCamera
{
public:
	static PointPickerInteractorStyle* New();
	vtkTypeMacro(PointPickerInteractorStyle, vtkInteractorStyleTrackballCamera);
 
	virtual void OnLeftButtonDown()
	{
		//打印鼠標左鍵像素位置
		std::cout << "Picking pixel: " << this->Interactor->GetEventPosition()[0] 
			<< " " << this->Interactor->GetEventPosition()[1] << std::endl;
		//註冊拾取點函數
		this->Interactor->GetPicker()->Pick(
			this->Interactor->GetEventPosition()[0],
			this->Interactor->GetEventPosition()[1], 0,  // always zero.
			this->Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()
			);
		//打印拾取點空間位置
		double picked[3];
		this->Interactor->GetPicker()->GetPickPosition(picked);
		std::cout << "Picked value: " << picked[0] << " " << picked[1] << " " << picked[2] << std::endl;
		//對拾取點進行標記
		vtkSmartPointer<vtkSphereSource> sphereSource =
			vtkSmartPointer<vtkSphereSource>::New();
		sphereSource->Update();
 
		vtkSmartPointer<vtkPolyDataMapper> mapper =
			vtkSmartPointer<vtkPolyDataMapper>::New();
		mapper->SetInputConnection(sphereSource->GetOutputPort());
 
		vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
		actor->SetMapper(mapper);
		actor->SetPosition(picked);
		actor->SetScale(0.05);
		actor->GetProperty()->SetColor(1.0, 0.0, 0.0);
		this->Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()->AddActor(actor);
 
		vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
	}
};
/**************************************************************************************************/
 
vtkStandardNewMacro(PointPickerInteractorStyle);
 
int main()
{
	vtkSmartPointer<vtkSphereSource> sphereSource =
		vtkSmartPointer<vtkSphereSource>::New();
	sphereSource->Update();
 
	vtkSmartPointer<vtkPolyDataMapper> mapper =
		vtkSmartPointer<vtkPolyDataMapper>::New();
	mapper->SetInputConnection(sphereSource->GetOutputPort());
	vtkSmartPointer<vtkActor> actor =
		vtkSmartPointer<vtkActor>::New();
	actor->SetMapper(mapper);
 
	vtkSmartPointer<vtkRenderer> renderer =
		vtkSmartPointer<vtkRenderer>::New();
	renderer->AddActor(actor);
	renderer->SetBackground(1, 1, 1);
 
	vtkSmartPointer<vtkRenderWindow> renderWindow =
		vtkSmartPointer<vtkRenderWindow>::New();
	renderWindow->Render();
	renderWindow->SetWindowName("PointPicker");
	renderWindow->AddRenderer(renderer);
 
	vtkSmartPointer<vtkPointPicker> pointPicker =
		vtkSmartPointer<vtkPointPicker>::New();
 
	vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	renderWindowInteractor->SetPicker(pointPicker);
	renderWindowInteractor->SetRenderWindow(renderWindow);
 
	vtkSmartPointer<PointPickerInteractorStyle> style =
		vtkSmartPointer<PointPickerInteractorStyle>::New();
	renderWindowInteractor->SetInteractorStyle(style);
	/////////////////////////////////////////////////////////
	vtkSmartPointer<vtkAxesActor>  Axes = vtkSmartPointer<vtkAxesActor>::New();
	vtkSmartPointer<vtkOrientationMarkerWidget>  widget =
		vtkSmartPointer<vtkOrientationMarkerWidget>::New();
	widget->SetInteractor(renderWindowInteractor);
	widget->SetOrientationMarker(Axes);
	widget->SetOutlineColor(1, 1, 1);
	widget->SetViewport(0, 0, 0.2, 0.2);
	widget->SetEnabled(1);
	widget->InteractiveOn();
	////////////////////////////////////////////////////////////
	renderWindow->Render();
	renderWindowInteractor->Start();
 
	return 0;
}

實際操作細節分析:

  • vtkInteractorStyleTrackballCemera派生類設計

PointPickerInteractorStyle類從vtkInteractorStyleTrackballCemera派生,並覆蓋了該類OnLeftButtonDown()函數。在該函數中,調用了vtkRenderWindowInteractor的GetEventPosition()函數輸出鼠標點擊的屏幕座標。

  • 拾取函數Pick()設計

int Pick(double selectionX, double selectionY, double selectionZ, vtkRender* renderer);
該函數需要接受四個參數,前三個爲(selectionX,selectionY,selectionZ),即鼠標的當前窗口座標,其中selectionZ通常爲零。最後一個是vtkRenderer對象。

  • GetPackPosition()是指世界座標系下拾取點的座標
  • mian()函數中設計拾取調用流程
    vtkSmartPointer<vtkPointPicker> pointPicker =
    	vtkSmartPointer<vtkPointPicker>::New();
     
    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
    	vtkSmartPointer<vtkRenderWindowInteractor>::New();
    renderWindowInteractor->SetPicker(pointPicker);
    renderWindowInteractor->SetRenderWindow(renderWindow);
     
    vtkSmartPointer<PointPickerInteractorStyle> style =
    	vtkSmartPointer<PointPickerInteractorStyle>::New();
    renderWindowInteractor->SetInteractorStyle(style);

    實例化vtkPointPicker對象以後,調用vtkRenderWindowInteractor::SetPicker()函數將其設置到渲染窗口交互器中。PointPickerInteractorStyle類與vtkInteractorStyleImage等交互器樣式使用方法一致。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章