・vtkTextActorを使って表示する文字列を作成。日本語は使えない(?)ので注意
・Actorの三次元座標を画面上のピクセル座標に変換するにはvtkCoordinateを使用する。
・再描画が行われるたびにテキストの位置の再計算が必要。AddObserverでイベントリスナを追加する
//VTK_MODULE_INITに必要 #include <vtkAutoInit.h> #include <vtkSmartPointer.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> //円筒とその表示に必要 #include <vtkCylinderSource.h> #include <vtkConeSource.h> #include <vtkPolyDataMapper.h> #include <vtkProperty.h> #include <vtkTextActor.h> #include <vtkTextProperty.h> #include <vtkCamera.h> #pragma comment(lib,"opengl32.lib") #pragma comment(lib,"psapi.lib") #pragma comment(lib,"dbghelp.lib") #pragma comment(lib,"ws2_32.lib") //必須 VTK_MODULE_INIT(vtkRenderingOpenGL2); VTK_MODULE_INIT(vtkInteractionStyle); VTK_MODULE_INIT(vtkRenderingFreeType); // テキスト表示に必要
// テキストの位置をアクタの中心に合わせる void UpdateTextActorPosition(vtkSmartPointer<vtkRenderer> renderer, vtkSmartPointer<vtkActor> actor, vtkSmartPointer<vtkTextActor> textActor) { double* c = actor->GetPosition(); // アクターの中心座標を取得 // cの三次元座標をクライアント領域のピクセル座標に変換 vtkSmartPointer<vtkCoordinate> coordinate = vtkSmartPointer<vtkCoordinate>::New(); coordinate->SetCoordinateSystemToWorld(); coordinate->SetValue(c); int* xy = coordinate->GetComputedDisplayValue(renderer); int x = static_cast<int>(xy[0]); int y = static_cast<int>(xy[1]); // テキストの位置を設定 textActor->SetPosition(x, y); }
vtkSmartPointer<vtkTextActor> CreateTextActorFromActor(vtkSmartPointer<vtkRenderer> renderer, vtkSmartPointer<vtkActor> actor, const std::string& title) { auto textActor = vtkSmartPointer<vtkTextActor>::New(); textActor->SetInput(title.c_str()); // テキストプロパティを取得 vtkTextProperty* textProperty2 = textActor->GetTextProperty(); // テキストサイズ(フォントサイズ)を設定 textProperty2->SetFontSize(24); // テキストの色を設定(オプション、例えば白色) textProperty2->SetColor(1.0, 1.0, 1.0); UpdateTextActorPosition(renderer, actor, textActor); return textActor; }
////////////////////////////////////////////////////////////// // VTK内のアクションに応じて呼び出すためのコールバッククラス ////////////////////////////////////////////////////////////// class CameraModifiedCallback : public vtkCommand { vtkSmartPointer<vtkActor> _actor; vtkSmartPointer<vtkTextActor> _textActor; vtkSmartPointer<vtkRenderer> _renderer; public: static CameraModifiedCallback* New() { return new CameraModifiedCallback; } void SetRenderer(vtkSmartPointer<vtkRenderer> renderer, vtkSmartPointer<vtkActor> actor, vtkSmartPointer<vtkTextActor> textActor) { _renderer = renderer; _actor = actor; _textActor = textActor; } void Execute(vtkObject* caller, unsigned long eventId, void* callData) override { // イベントに応じて処理を分岐 if (eventId == vtkCommand::ModifiedEvent) { vtkCamera* camera = dynamic_cast<vtkCamera*>(caller); if (!camera) return; // callerがvtkCameraでない場合は何もしない UpdateTextActorPosition(_renderer, _actor, _textActor); } else if (eventId == vtkCommand::ConfigureEvent) { // ウィンドウサイズ変更イベントの処理 UpdateTextActorPosition(_renderer, _actor, _textActor); } } };
int main(int /*argc*/, char** /*argv*/) { ////////////////////////////////////// auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); ////////////////////////////////////// auto renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); renderWindow->SetInteractor(interactor); renderWindow->Render(); ////////////////////////////////////// ////////////////////////////////////// auto renderer_1st = vtkSmartPointer<vtkRenderer>::New(); auto renderer_2nd = vtkSmartPointer<vtkRenderer>::New(); // レイヤー番号の指定 // 番号が若いほど背面に描画される renderer_1st->SetLayer(0); renderer_2nd->SetLayer(1); renderWindow->SetNumberOfLayers(2);// レイヤー数を指定しておいたほうが行儀がいいらしい renderWindow->AddRenderer(renderer_1st); renderWindow->AddRenderer(renderer_2nd); renderer_1st->ResetCamera(); // カメラの共有 renderer_2nd->SetActiveCamera(renderer_1st->GetActiveCamera()); ////////////////////////////////////// ////////////////////////////////////// ////////////////////////////////////// // レイヤー1にCylinderを表示 vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New(); { vtkSmartPointer<vtkCylinderSource> cylinderSource = vtkSmartPointer<vtkCylinderSource>::New(); cylinderSource->SetCenter(0.0, 0.0, 0.0); cylinderSource->SetRadius(5.0); cylinderSource->SetHeight(7.0); cylinderSource->SetResolution(100); vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); mapper->SetInputConnection(cylinderSource->GetOutputPort()); actor->SetMapper(mapper); actor->GetProperty()->SetColor(1.0, 0.0, 0.0); // レイヤー1にアクタを追加 renderer_1st->AddActor(actor); } // 表示用の文字列オブジェクトを作成 vtkSmartPointer<vtkTextActor> text = CreateTextActorFromActor(renderer_2nd, actor, "The Cylinder"); renderer_2nd->AddActor(text);
// カメラの変更時に呼び出すコールバックを作成 vtkSmartPointer<CameraModifiedCallback> camera_callback = CameraModifiedCallback::New(); camera_callback->SetRenderer(renderer_2nd,actor,text); // カメラの変更を検知したときにcamera_callbackを呼び出す renderer_2nd->GetActiveCamera()->AddObserver(vtkCommand::ModifiedEvent, camera_callback); // ウィンドウサイズが変更されたときにもcamera_callbackを呼び出したい interactor->AddObserver(vtkCommand::ConfigureEvent, camera_callback);
// イベントループ interactor->Start(); return 0; }