VTK实现三视图显示及交互STL模型

VTK实现STL模型的三视图显示及交互

最近收到需求,要实现多视图显示同一个STL模型,并且控制主窗口要其他试图窗口也跟着交互,花了点时间去尝试一下,把这个效果给实现出来了,而且实现也挺简单。


效果演示


要点

  1. 用同一个vtkRenderer传三次给vtkRenderWindow是不行的,要创建三个vtkRenderer来显示用一个vtkActor,分别传给vtkRenderWindow才行。
  2. 用同一个vtkCamera同时控制三个vtkRenderer是不行的,因为vtkCamera的参数发生改变,会同步影响,要实现不同的视角,还是需要准备三个vtkCamera分别传给三个vtkRenderer。
  3. 既然要实现控制一个主vtkCamera,影响另外两个辅vtkCamera也要同步更新,那最直接的方法就是用回调函数。

代码实现

cpp 复制代码
#include <iostream>
#include <vtkAutoInit.h>
#include <vtkSTLReader.h>
#include <vtkPLYReader.h>
#include <vtkPolyDataMapper.h>
#include <vtkSmartPointer.h>
#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkTransform.h>

#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkCommand.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);

class vtkUpdateCamera : public vtkCommand
{
public:
	static vtkUpdateCamera* New()
	{
		return new vtkUpdateCamera;
	}

	void Execute(vtkObject* caller, unsigned long vtkNotUsed(event), void* callData)
	{
		//获取主camera
		vtkRenderer* renderer = dynamic_cast<vtkRenderer*>(caller);
		auto camera = renderer->GetActiveCamera();
		//更新两个辅助camera的参数
		camera1->SetPosition(camera->GetPosition());
		camera1->SetFocalPoint(camera->GetFocalPoint());
		camera1->SetViewUp(camera->GetViewUp());
		camera1->Azimuth(90);
		camera1->Modified();
		//通过调整摄像头的viewup的旋转角度,为辅助摄像头实现上试图,左视图的朝向
		camera2->SetPosition(camera->GetPosition());
		camera2->SetFocalPoint(camera->GetFocalPoint());
		double* viewUp = camera->GetViewUp();
		double* direction = camera->GetDirectionOfProjection();
		double view[3];
		vtkMath::Cross(direction, viewUp, view);
		camera2->SetViewUp(view);
		camera2->Azimuth(-90);
		camera2->Modified();
	}

	void SetCamera1(vtkCamera* c)
	{
		camera1 = c;
	}

	void SetCamera2(vtkCamera* c)
	{
		camera2 = c;
	}

private:
	vtkCamera* camera1;
	vtkCamera* camera2;
};

int main()
{
	vtkSmartPointer<vtkSTLReader> reader = vtkSmartPointer<vtkSTLReader>::New();
	reader->SetFileName("D://Bunny.stl");
	reader->Update();

	vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
	mapper->SetInputData(reader->GetOutput());

	vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
	actor->SetMapper(mapper);

	double* bounds = reader->GetOutput()->GetBounds();
	
	vtkSmartPointer<vtkCamera> camera = vtkSmartPointer<vtkCamera>::New();
	camera->SetPosition(0, bounds[2]- 200, 0);
	camera->SetFocalPoint(reader->GetOutput()->GetCenter());
	camera->SetViewUp(0, 0, 1);

	vtkSmartPointer<vtkCamera> camera1 = vtkSmartPointer<vtkCamera>::New();
	vtkSmartPointer<vtkCamera> camera2 = vtkSmartPointer<vtkCamera>::New();

	//为主渲染器准备更新摄像头的回调函数
	vtkSmartPointer<vtkUpdateCamera> callback = vtkSmartPointer<vtkUpdateCamera>::New();
	callback->SetCamera1(camera1);
	callback->SetCamera2(camera2);

	//---------设置主渲染器----------
	vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
	renderer->AddActor(actor);
	renderer->SetActiveCamera(camera);
	renderer->SetBackground(1, 1, 1);
	renderer->SetViewport(0, 0, 0.33, 1);
	//为主渲染器绑定回调函数,使用AnyEvent为了使任何交互都影响两个辅助摄像头
	renderer->AddObserver(vtkCommand::AnyEvent, callback);
	
	//---------设置第一个辅助渲染器----------
	vtkSmartPointer<vtkRenderer> renderer1 = vtkSmartPointer<vtkRenderer>::New();
	
	auto actors = renderer->GetActors();
	actors->InitTraversal();
	for (int i = 0; i < actors->GetNumberOfItems(); i++)
	{
		renderer1->AddActor(actors->GetNextActor());
	}
	renderer1->SetActiveCamera(camera1);
	renderer1->SetViewport(0.33, 0, 0.66, 1);
	renderer1->SetBackground(1, 1, 1);

	//---------设置第二个辅助渲染器----------
	vtkSmartPointer<vtkRenderer> renderer2 = vtkSmartPointer<vtkRenderer>::New();
	renderer2->SetActiveCamera(camera2);
	renderer2->SetViewport(0.66, 0, 1, 1);
	renderer2->SetBackground(1, 1, 1);
	actors->InitTraversal();
	for (int i = 0; i < actors->GetNumberOfItems(); i++)
	{
		renderer2->AddActor(actors->GetNextActor());
	}
	
	vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
	renderWindow->AddRenderer(renderer);
	renderWindow->AddRenderer(renderer1);
	renderWindow->AddRenderer(renderer2);
	renderWindow->SetSize(1200, 400);

	vtkSmartPointer<vtkInteractorStyleTrackballCamera> style = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();

	vtkSmartPointer<vtkRenderWindowInteractor> rwi = vtkSmartPointer<vtkRenderWindowInteractor>::New();
	rwi->SetRenderWindow(renderWindow);
	rwi->SetInteractorStyle(style);
	rwi->Start();
}
相关推荐
2501_941237531 分钟前
基于C++的游戏引擎开发
开发语言·c++·算法
_OP_CHEN7 分钟前
算法基础篇:(十)贪心算法拓展之哈夫曼编码:从 “合并最优” 到数据压缩的传奇
c++·算法·贪心算法·蓝桥杯·哈夫曼编码·算法竞赛·acm/icpc
枫叶丹410 分钟前
【Qt开发】Qt窗口(二) -> QToolBar工具栏
开发语言·数据库·c++·qt
熙客18 分钟前
Java集合框架概述
java·开发语言
高山有多高27 分钟前
堆应用一键通关: 堆排序 +TOPk问题的实战解析
c语言·数据结构·c++·算法
我命由我1234529 分钟前
Java 开发 - 简单消息队列实现、主题消息队列实现
java·开发语言·后端·算法·java-ee·消息队列·intellij-idea
chilavert31829 分钟前
技术演进中的开发沉思-194 JavaScript: Prototype 框架
开发语言·javascript·原型模式
2501_9412374530 分钟前
高性能计算通信库
开发语言·c++·算法
1白天的黑夜136 分钟前
递归-二叉树中的剪枝-814.二叉树剪枝-力扣(LeetCode)
c++·leetcode·剪枝·递归
杜子不疼.36 分钟前
【C++】红黑树为什么比AVL快?用C++亲手实现告诉你答案
开发语言·c++