7.IO
VTK综合实战Demo:简易模型查看器
把前面学过的全部知识点串起来:文件读取Source → Filter预处理 → 渲染管线 → 鼠标拾取回调 → IO导出保存。
功能清单:
- 读取stl模型(Reader属于Source)
- Filter做网格清理
- 完整渲染交互
- 鼠标左键拾取面片,打印面片ID、交点坐标(Observer拾取回调)
- 把处理之后的网格保存为vtp文件(Writer)
逻辑链路:
stl文件 → vtkSTLReader(Source) → vtkCleanPolyData(Filter) → PolyDataMapper → Actor → Renderer拾取:鼠标事件 → Observer回调 → vtkCellPicker射线拾取 输出:把处理后的PolyData保存为vtp
#include <vtkSmartPointer.h>
#include <vtkSTLReader.h>
#include <vtkCleanPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkCellPicker.h>
#include <vtkCommand.h>
#include <vtkXMLPolyDataWriter.h>
#include <iostream>
// 拾取回调类,观察者模式
class PickCallback : public vtkCommand
{
public:
static PickCallback* New()
{
return new PickCallback;
}
virtual void Execute(vtkObject* caller, unsigned long vtkNotUsed(eventId), void*) override
{
vtkRenderWindowInteractor* interactor = static_cast<vtkRenderWindowInteractor*>(caller);
int x, y;
interactor->GetEventPosition(x, y);
vtkSmartPointer<vtkCellPicker> picker = vtkSmartPointer<vtkCellPicker>::New();
picker->SetTolerance(0.0001);
auto renderer = interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer();
picker->Pick(x, y, 0, renderer);
int cellId = picker->GetCellId();
if(cellId >= 0)
{
double pos[3];
picker->GetPickPosition(pos);
std::cout << "【拾取成功】CellId=" << cellId
<< " 交点(" << pos[0] << "," << pos[1] << "," << pos[2] << ")\n";
}
else
{
std::cout << "【未命中模型】\n";
}
}
};
int main()
{
// ==========1.读取stl文件(Reader,属于Source)==========
vtkSmartPointer<vtkSTLReader> stlReader = vtkSmartPointer<vtkSTLReader>::New();
stlReader->SetFileName("model.stl"); //替换成你的stl路径
stlReader->Update(); //读取解析文件,得到vtkPolyData
// ==========2.Filter预处理:清理重复点==========
vtkSmartPointer<vtkCleanPolyData> cleanFilter = vtkSmartPointer<vtkCleanPolyData>::New();
cleanFilter->SetInputData(stlReader->GetOutput());
cleanFilter->SetTolerance(1e-4);
cleanFilter->Update();
//拿到处理完成后的数据集
vtkPolyData* outPoly = cleanFilter->GetOutput();
// ==========3.把处理完的数据保存为vtp文件(Writer)==========
vtkSmartPointer<vtkXMLPolyDataWriter> vtpWriter = vtkSmartPointer<vtkXMLPolyDataWriter>::New();
vtpWriter->SetFileName("output.vtp");
vtpWriter->SetInputData(outPoly);
vtpWriter->Write(); //Writer用Write,不是Update
std::cout << "已导出 output.vtp\n";
// ==========4.渲染管线==========
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData(outPoly);
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper.Get());
actor->GetProperty()->SetColor(0.4,0.6,0.9);
actor->GetProperty()->SetEdgeVisibility(true); //打开边线,看三角面片轮廓
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor(actor);
renderer->SetBackground(0.1,0.1,0.1);
vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
renderWindow->SetSize(800,600);
vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
interactor->SetRenderWindow(renderWindow);
vtkSmartPointer<vtkInteractorStyleTrackballCamera> style = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
interactor->SetInteractorStyle(style);
// ==========5.绑定鼠标左键拾取回调(Observer)==========
vtkSmartPointer<PickCallback> pickCb = vtkSmartPointer<PickCallback>::New();
interactor->AddObserver(vtkCommand::LeftButtonPressEvent, pickCb);
interactor->Initialize();
interactor->Start();
return 0;
}
逐段复盘,对应前面全部知识点
-
Source(vtkSTLReader)
SetFileName设置参数 →Update()执行解析,生成vtkPolyData。Reader就是读文件的Source,没有输入,输出数据集。
-
Filter(vtkCleanPolyData) 输入是reader输出,做网格清理;
Update()执行算法,输出新PolyData。Filter不会修改原始reader的数据,输出全新一份。
-
IO Writer
vtkXMLPolyDataWriter,SetInputData()传入内存网格,Write()写磁盘。注意区分:Source/Filter调用
Update();Writer调用Write()。 -
Mapper + Actor + Renderer Mapper把数据集送给Actor;Actor的Property只控制渲染外观,不改内存网格;打开边线方便观察三角面片。
-
交互Interactor + InteractorStyle TrackballCamera,旋转缩放本质是相机变化,PolyData点坐标完全不变。
-
Observer观察者 + vtkCellPicker拾取 AddObserver监听鼠标左键事件;回调内部做射线拾取;射线起点是相机位置,拿到CellId与交点。
cellId=-1代表没有命中物体。
运行之后你可以观察到的现象
- 程序启动,窗口显示stl模型,能旋转缩放平移;
- 控制台打印“已导出 output.vtp”,可以用ParaView打开这个vtp查看网格;
- 鼠标左键点击模型,控制台打印面片ID和三维交点;点空白输出未命中;
- stl里面只有几何,导出vtp之后,如果你给PolyData加上PointData/CellData属性,vtp会完整保存这些数组,stl做不到。
工业软件视角下,这个Demo缺什么?
这是纯VTK程序,还没有接入OCCT。 真实工业软件流程:
stp(STEP)文件 → OCCT读取BRep实体 → OCCT三角化 tessellate → 产出vtkPolyData → 送入VTK这套管线
VTK只负责后面这一整套渲染、拾取、Filter处理、网格IO;STEP实体读写交给OCCT。
VTK基础全部核心概念总览(快速复盘)
- 数据层:vtkDataSet(vtkPolyData重点),Points、Cell、PointData、CellData;
- 管线层:Source → Filter → Mapper → Actor → Renderer → RenderWindow;
- 延迟计算:SetXXX改参数,Update()触发算法;Filter链式会向上更新上游;
- 渲染外观:vtkProperty,只改显示,不改内存数据;和Filter做区分;
- 交互拾取:Interactor、InteractorStyle;拾取射线从相机出发;CellPicker拿面片ID;
- IO:Reader(Source)、Writer;stl只存几何,vtp存几何+属性;VTK不处理stp;
- 事件:vtkCommand观察者模式,鼠标事件、进度事件。

浙公网安备 33010602011771号