VTK 的可视化方法:Glyph
- VTK 的可视化方法:Glyph
- 标量、向量、张量
- 将多边形数据的采集点法向量标记成锥形符号
- 参考
VTK 的可视化方法:Glyph
模型的法向量数据是向量数据,因此法向量不能像前面讲到的通过颜色映射来显示。但是可以通过符号化(Glyphing)技术将法向量图形化显示。
Glyphing是一种基于图形的可视化技术,这些图像可以是简单的基本图形,如具有方向的椎体,也可以是更加复杂的图像。VTK中就是应用vtkGlyph3D类实现该功能的,并且可以支持Glyphing图形的缩放、着色、设置空间姿态等。使用该类时,需要接受两个输入:一个是需要显示的几何数据点集合;另一个是Glyph图形数据,为vtkPolyData数据。
标量、向量、张量
标量、向量、张量是可视化数据处理的 3 种数据类型。
- 标量(scalar):只有一个数字的张量叫标量(也叫标量张量、零维张量、0D 张量)
- 向量(vector):数字组成的数组叫作向量(vector)或一维张量(1D 张量)。一维张量只有一个轴。
- 张量(Tensor):张量是一个多维数组,它是标量,向量,矩阵的高维扩展,是一个数据容器,张量是矩阵向任意维度的推广。
将多边形数据的采集点法向量标记成锥形符号
在读取和使用文件过程中,我们经常要用到法向量。这个例子展示了我们应该如何计算多边形数据的法向量并用vtkGlyph3D绘制圆锥型状将其标记出来。详细过程如下:
- 读取vtk文件构建多边形数据集;
- 使用vtkPolyDataNormals类计算多边形数据的 points 和 cell 的法向量,并将法向量由内侧翻转到外侧;
- 使用vtkMaskPoints类采样部分数据,为总数的十分之一, 保留输入数据中的点数据及其属性;
- 构建vtkGlyph3D对象,绘制形状设置为圆锥,将圆锥用一个过滤器做一个简单的偏移,数据源为采样点数据;
- 绘制法向量数据和符号数据。
完整代码:
#include "VTKGlyph.h"
#include <vtkConeSource.h>
#include <vtkPolyDataReader.h>
#include <vtkPolyDataNormals.h>
#include <vtkMaskPoints.h>
#include <vtkTransform.h>
#include <vtkTransformPolyDataFilter.h>
#include <vtkGlyph3D.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
VTKGlyph::VTKGlyph(QWidget* parent)
: QMainWindow(parent)
{
ui.setupUi(this);
_pVTKWidget = new QVTKOpenGLNativeWidget();
this->setCentralWidget(_pVTKWidget);
// this->showMaximized();
// 1. generate data
// 创建法向量的符号:圆锥形
vtkSmartPointer<vtkConeSource> cone = vtkSmartPointer<vtkConeSource>::New();
cone->SetResolution(6);
// or, read data
vtkSmartPointer<vtkPolyDataReader> reader = vtkSmartPointer<vtkPolyDataReader>::New();
reader->SetFileName("fran_cut.vtk");
// 计算 poly data 中 points 和 cell 的法向量
vtkSmartPointer<vtkPolyDataNormals> normals = vtkSmartPointer<vtkPolyDataNormals>::New();
// 将多边形数据集作为法向量对象的数据输入
normals->SetInputConnection(reader->GetOutputPort());
// 将法线翻转,默认的法线方向指向内侧
normals->FlipNormalsOn();
// 由于读入的模型数据比较大,点比较多,因此使用 vtkMaskPoints 类采样部分数据,该类保留输入数据中的点数据及其属性,并支持点数据的采样
vtkSmartPointer<vtkMaskPoints> maskPt = vtkSmartPointer<vtkMaskPoints>::New();
maskPt->SetInputConnection(normals->GetOutputPort());
// 设置采样率为 1/10
maskPt->SetOnRatio(10);
// 打开随机采样模式
maskPt->RandomModeOn();
// 偏移
vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
transform->Translate(0.5, 0, 0);
// 2. filter
vtkSmartPointer<vtkTransformPolyDataFilter> filter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
// 将法向量的符号:圆锥形设置偏移
filter->SetInputConnection(cone->GetOutputPort());
filter->SetTransform(transform);
vtkSmartPointer<vtkGlyph3D> glyph = vtkSmartPointer<vtkGlyph3D>::New();
// 设置被标识的点
glyph->SetInputConnection(maskPt->GetOutputPort());
// 设置被偏移的符号
glyph->SetSourceConnection(filter->GetOutputPort());
// 设置向量为法线方向
glyph->SetVectorModeToUseNormal();
glyph->SetScaleModeToScaleByVector();
// 设置比例,缩小法向量的大小
glyph->SetScaleFactor(0.004);
// 3. mapper
vtkSmartPointer<vtkPolyDataMapper> franMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
vtkSmartPointer<vtkPolyDataMapper> spikeMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
// 4. actor
vtkSmartPointer<vtkActor> franActor = vtkSmartPointer<vtkActor>::New();
vtkSmartPointer<vtkActor> spikeActor = vtkSmartPointer<vtkActor>::New();
// 5. renderer
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
renderer->SetBackground(0.3, 0.6, 0.3);
// 6. connect
franMapper->SetInputConnection(normals->GetOutputPort());
spikeMapper->SetInputConnection(glyph->GetOutputPort());
franActor->SetMapper(franMapper);
spikeActor->SetMapper(spikeMapper);
renderer->AddActor(franActor);
renderer->AddActor(spikeActor);
this->_pVTKWidget->renderWindow()->AddRenderer(renderer);
this->_pVTKWidget->renderWindow()->Render();
}
VTKGlyph::~VTKGlyph()
{}
运行结果:
拉近摄像头,按W键切换成线框模式:
可以看出一个个小锥体都长在点上,代表网格的法向量。
参考
- https://www.bilibili.com/video/BV1sY41197GT
- https://blog.csdn.net/weixin_52194015/article/details/135698359