了解vtk显示的原理

文章目录

  • 目标:
  • 知识补充:
    • 1.什么是图元?
    • 2.最让我不解的是:官方讲的是:mapper讲polydata转换为可渲染的图元数据,然后actor是将polydata映射为可渲染的图元???既然mapper就已经将其解析为图元数据,为什么actor还要进一步解析呢?
    • 3.那polydata不是也获得了一些数据,这些数据是否和mapper获得的图元数据重合?
  • 第一步,准备stl文件
  • 第二步,Reader
  • 第三步,PolyData(不可渲染)
  • 第四步,Mapper(可渲染)
  • 第五步,Actor
  • 第六步,Render
  • 第七步,Display
  • 最后,再深入了解 vtkPolyData 这个数据结构
    • 前言
    • 继承关系
    • 尝试一,使用vtk代码生成一个三角形,并生成stl文件保存到本地
  • 尝试二,正方形
    • 总结

目标:

  • 了解vtk显示的原理 :

具体来说,就是下面这个过程 :

从stl文件开始读取,到最后显示出三维效果 的过程:

stl -> reader -> polydata -> mapper -> actor -> render

  • 最重要的是深入了解 vtkPolyData 这个数据结构

知识补充:

1.什么是图元?

用一句话来讲 : 图元是计算机图形学中描述和构建图像的基本几何单元,通过绘制和组合不同的图元,可以生成最终的图像。

详细的来讲:

在计算机图形学中,图元(Primitive)是指最基本的几何图形单元,它是构成图像的基本构建块。

图元可以是二维图形,例如点、线段、多边形等,也可以是三维图形,例如点、线、三角形、四边形等。图元是图像的离散表示,它们在屏幕上以像素为单位进行显示。

渲染引擎通过绘制和组合图元来生成最终的图像。例如,多个线段可以组合成一个多边形,多个多边形可以组合成一个复杂的模型。图元是渲染过程中的基本构建单元,通过对它们的绘制和排列,可以得到各种复杂的图像效果。

图元的选择和使用取决于具体的应用场景和需求。不同的图形库和渲染引擎提供了不同类型的图元,以满足各种绘制和渲染需求。常见的图元包括点(Point)、线段(Line)、三角形(Triangle)和多边形(Polygon)等。

2.最让我不解的是:官方讲的是:mapper讲polydata转换为可渲染的图元数据,然后actor是将polydata映射为可渲染的图元???既然mapper就已经将其解析为图元数据,为什么actor还要进一步解析呢?

其实,这是混淆了图元和图元数据这两个概念.

图元数据和图元是两个概念。

图元(Primitive)是指渲染中的基本几何形状,比如点、线、三角形等。这些基本的几何形状是渲染引擎直接处理和渲染的对象。

图元数据(Primitive Data)是描述这些基本几何形状所需的数据集合,包括顶点坐标、法线向量、纹理坐标等。它们提供了构成图元的信息,用于在渲染过程中确定几何形状的位置、朝向和其他属性。

Mapper的任务是将PolyData(或其他数据集)转换为图元数据,即生成描述基本几何形状的数据集合。这些图元数据包含了图元的几何信息和其他必要的属性,以供渲染引擎使用。

Actor的任务是将图元数据映射为可渲染的图元,并负责定义物体的外观和属性。它将图元数据与光照、颜色、透明度等相关属性结合起来,最终呈现出可见的物体。

因此,图元数据是描述图元的数据集合,而图元则是基本几何形状本身。Mapper负责从数据集中生成图元数据,Actor负责将图元数据解析和渲染为可见的物体。它们共同完成了渲染过程中的几何形状转换和可视化。

3.那polydata不是也获得了一些数据,这些数据是否和mapper获得的图元数据重合?

(重点:下面解释了polydata和mapper的区别)

我暂时找不到合适的描述来形容polydata所表的数据,不过接下来关于polydata会再专门写一个章单独列出来,现在先这么理解,目的是对这里流程有了大致的印象.

可以先这么理解:Polydata可以被看作是一种更高层次的图元数据,也就是说polydata所掌握的图元数据,远远要比mapper的图元数据要复杂,也就可以理解为:mapper是Polydata的一个子集.

polydata不仅拥有mapper的图元数据,还可以附加额外的属性,比如:法线向量,纹理坐标等.

因为Polydata对于渲染器来说太过复杂,以至于渲染器无法进行解析,所以我们才需要使用mapper拿到Polydata的一些简要数据,简要到渲染器可以接受的底层图元信息,比如:顶点坐标,索引数组等,这些底层图元数据将用于实际的渲染过程.

然后,再提一嘴actor : 现在我们使用mapper拿到了渲染器可用的数据 , actor则是将底层图元数据与其他属性(如,颜色,透明度,材质)结合起来(也就是说,我们可以调用actor的一些方法,比如actor->GetProperty()->SetColor(1.0,0.0,0.0)或者actor->GetProperty()->SetOpacity(0.5)再或者actor->GetProperty()->SetAmbient(0.2)还有环境反射系数,漫反射系数,镜面反射系数等等),最终就是可见的物体了!

As far as I’m concerned, PolyData is 描述几何形状和属性的高层次的图元数据(此时渲染无法识别),然后Mapper is 将PolyData 转换为底层图元数据 , 而 Actor 则 is responsible for进一步解析和渲染设置 . 他们合作共赢 , 共同协作 , 完成了 从 stl 读取数据 到最终渲染后进行可视化的过程.

再总结一下:polydata和mapper的区别:

  • polydata不可渲染 , mapper可渲染
  • 两者都是数据,但是Polydata比Mapper多一些 , 且mapper是Polydata的一个子集

第一步,准备stl文件

第二步,Reader

Reader:在VTK中,我们使用相应的Reader来读取STL文件。对于STL文件,可以使用== v t k S T L R e a d e r vtkSTLReader vtkSTLReader来读取文件并将其转换为VTK数据对象==。

第三步,PolyData(不可渲染)

v t k S T L R e a d e r vtkSTLReader vtkSTLReader读取 S T L STL STL文件后,将其转换 V T K VTK VTK P o l y D a t a PolyData PolyData数据对象。 P o l y D a t a PolyData PolyData是VTK中用于表示表面网格的数据结构,包含顶点、线和面等几何信息

第四步,Mapper(可渲染)

Mapper的作用是将PolyData数据对象转换为可供渲染引擎使用的图元数据。对于 P o l y D a t a PolyData PolyData,可以使用 v t k P o l y D a t a M a p p e r vtkPolyDataMapper vtkPolyDataMapper来进行映射。

PolyData和Mapper都是数据,但是如果要进行渲染的话,还需要将PolyData进一步转化为Mapper

第五步,Actor

A c t o r Actor Actor V T K VTK VTK中的可视化实体,代表了一个可渲染的对象。在这一步,我们将 M a p p e r Mapper Mapper的输出连接到 A c t o r Actor Actor,将 P o l y D a t a PolyData PolyData映射为可渲染的图元

第六步,Render

R e n d e r Render Render V T K VTK VTK中用于渲染的对象,它提供了渲染场景和生成图像的功能。在渲染过程中,我们 A c t o r Actor Actor添加到 R e n d e r Render Render,以便在渲染时显示Actor代表的对象。

第七步,Display

最后,通过在窗口系统中创建一个渲染窗口,将Render的图像显示出来。渲染窗口可以提供用户交互,如缩放、旋转、平移等操作,以便查看和分析三维效果。

eg:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

/*******************************************************************************/
//1.准备stl文件  test1_amend.stl=======================>可以理解为:相当于原料,但是有包装

//2.使用vtkSTLReader读取stl文件========================>可以理解为:撕开了包装,拿到了原料
// 创建STL文件的读取器
vtkSmartPointer<vtkSTLReader> reader = vtkSmartPointer<vtkSTLReader>::New();
reader->SetFileName("test1_amend.stl");
reader->Update();

//3.从vtkSTLReader对象中获取PolyData对象==========>可以理解为:然后因为此次要做的食材需要的原料居多,所以我们先初步拿到了原料的信息:一个品类的先放在一起,但是还没有$细分$(此时,渲染器无法解析这些大型数据)
// 获取PolyData对象
vtkSmartPointer<vtkPolyData> polydata = reader->GetOutput();

//4.mapper=======================>可以理解为:相当于你现在还不能做饭,因为原材料还需要进一步细分,比如水果类中有苹果和菠萝,然后你要做菠萝烤肉,那苹果就没什么用,我们只需要保留菠萝即可,然后Mapper就是细分之后我们真正需要的"原料",现在:原料是"可做的"(对应:可渲染)
//Mapper的作用是将PolyData转换为可供渲染引擎使用的图元数据。(也就是说现在还是数据形式)
// 创建Mapper并设置输入数据对象
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData(polydata);

//5.我们将Mapper的输出连接到Actor,将PolyData映射为可渲染的图元(也就是说,这个不是数据了,现在是可显示的几何图元了)
// 创建Actor====================>可以理解为:至此,原料已经完全准备好了,现在我们拿出笔记本来记录一下一会,放多少醋,放多少盐...(这个步骤由actor来完成)
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);

//6.Render表示渲染对象===================>可以理解为:准备厨房和锅,将锅(对应渲染器)放到厨房(对应渲染窗口)里
//vtkRenderer->渲染器,vtkRenderWindow->渲染窗口
//创建渲染器和渲染窗口
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);//将渲染器放入渲染窗口;

//2)vtkRenderWindowInteractor->窗口交互器;===================>相当于装饰一下厨房,让厨房与外界有交流:(那么多油烟,你烟囱搞了没有),(客户等了半天想要问你饭啥时候做好,你要知道客户在和你交流)===>总之,有了这个,你就可以进行人机交互了,也可以理解为"厨房和客厅打通了",你不仅要做饭,你还要关注一下吃饭客户的感受
//窗口交互器用于处理用户与窗口进行交互的事件,例如鼠标操作、键盘操作等。
// 创建窗口交互器
vtkSmartPointer<vtkRenderWindowInteractor> interactor =
    vtkSmartPointer<vtkRenderWindowInteractor>::New();
interactor->SetRenderWindow(renderWindow);//再将"装有渲染器的渲染窗口"放入窗口交互器

// 将Actor添加到渲染器//将菜,姜,粗,盐,辅料倒入锅中翻炒
renderer->AddActor(actor);

// 开启交互器并显示窗口
renderWindow->Render();//做好的菜展示给评委
interactor->Start();//允许评委动手尝一尝

了解vtk显示的原理_第1张图片

上面这个是stl文件原图,我们试着渲染一下:
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 



 // 创建STL文件的读取器
 vtkSmartPointer<vtkSTLReader> reader = vtkSmartPointer<vtkSTLReader>::New();
 reader->SetFileName("test1_amend.stl");
 reader->Update();

 // 获取PolyData对象
 vtkSmartPointer<vtkPolyData> polydata = reader->GetOutput();

 // 创建Mapper并设置输入数据对象
 vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
 mapper->SetInputData(polydata);

 // 创建Actor
 vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
 actor->SetMapper(mapper);
 actor->GetProperty()->SetColor(1.0, 0.0, 0.0);//设置颜色
 actor->GetProperty()->SetOpacity(0.5);//设置透明度
 actor->GetProperty()->SetAmbient(0.2);//环境光反射系数
 actor->GetProperty()->SetDiffuse(0.8);//漫反射系数
 actor->GetProperty()->SetSpecular(0.5);//镜面反射系数
 

 // 创建渲染器和渲染窗口
 vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
 vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
 renderWindow->AddRenderer(renderer);

 // 创建交互器和窗口交互器
 vtkSmartPointer<vtkRenderWindowInteractor> interactor =
     vtkSmartPointer<vtkRenderWindowInteractor>::New();
 interactor->SetRenderWindow(renderWindow);

 // 将Actor添加到渲染器
 renderer->AddActor(actor);

 // 开启交互器并显示窗口
 renderWindow->Render();
 interactor->Start();

了解vtk显示的原理_第2张图片

最后,再深入了解 vtkPolyData 这个数据结构

前言

在上面已经讲了:vtkPolyData 是一种高层次的图元数据 , 有多高呢? 以至于渲染器都无法直接对其进行解析,还需要Mapper进一步解析来得到渲染器可解析的图元数据

这是官方关于vtkPolyData Class Reference的讲解,虽然我看不太懂,但是建议看看

这个是#include 里面的内容,不过我们在编译器中,我们加入#include 这个头文件,然后按下ctrl+鼠标左键的内容完全一样,只不过最上面多了60行的注释

这个文件记录了vtkPolyData这类的所有方法和一些inline函数

继承关系

了解vtk显示的原理_第3张图片

然后,更新详细一点:

vtkPolyData-> vtkPointSet->vtkDataSet->vtkDataObject->vtkObject->vtkObjectBase(基类)

尝试一,使用vtk代码生成一个三角形,并生成stl文件保存到本地

#include 
#include 
#include 
#include 

#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 

#include 
#include 
#include 
#include 


/***************************************************/
 // 创建点坐标
 vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
 points->InsertNextPoint(0.0, 0.0, 0.0);
 points->InsertNextPoint(1.0, 0.0, 0.0);
 points->InsertNextPoint(0.0, 1.0, 0.0);

 // 创建三角形拓扑
 vtkSmartPointer<vtkCellArray> triangles = vtkSmartPointer<vtkCellArray>::New();
 vtkIdType triangle[3];
 triangle[0] = 0;
 triangle[1] = 1;
 triangle[2] = 2;
 triangles->InsertNextCell(3, triangle);

 // 创建vtkPolyData对象并设置点和三角形拓扑
 vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
 polyData->SetPoints(points);
 polyData->SetPolys(triangles);

 // 创建mapper并设置输入的vtkPolyData对象
 vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
 mapper->SetInputData(polyData);

 // 创建actor并设置mapper
 vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
 actor->SetMapper(mapper);

 // 创建渲染器、渲染窗口和交互器
 vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
 vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
 renderWindow->AddRenderer(renderer);
 vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
 interactor->SetRenderWindow(renderWindow);

 // 将actor添加到渲染器
 renderer->AddActor(actor);

 // 渲染并启动交互器
 renderWindow->Render();
 interactor->Start();

/***************************************/
 // 保存为STL文件
 vtkSmartPointer<vtkSTLWriter> stlWriter = vtkSmartPointer<vtkSTLWriter>::New();
 stlWriter->SetFileName("output.stl");
 //stlWriter->SetFileTypeToBinary();  // 指定为二进制格式
 //如果您想将其设置为ASCII格式,可以使用SetFileTypeToASCII()方法。
 stlWriter->SetFileTypeToASCII();
 stlWriter->SetInputData(polyData);
 stlWriter->Write();
生成的stl文件的内容:

solid Visualization Toolkit generated SLA File
 facet normal 0 0 1
  outer loop
   vertex 0 0 0
   vertex 1 0 0
   vertex 0 1 0
  endloop
 endfacet
endsolid

注意看生成的stl文件的第一行 : Visualization Toolkit generated SLA File ,

意思是: 可视化工具包生成的SLA文件,

这个生成的stl文件并不能直接在meshlab这软件中运行,

而本身这个文件的格式也是有问题的,我们需要进行一下修改:

solid name             //也就是修改第一行和最后一行,给这个3D图像起个名字即可
 facet normal 0 0 1
  outer loop
   vertex 0 0 0
   vertex 1 0 0
   vertex 0 1 0
  endloop
 endfacet
endsolid name

了解vtk显示的原理_第4张图片

尝试二,正方形

// 创建一个 vtkPolyData 对象
vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();

// 创建一个 vtkPoints 对象,用于存储点的坐标
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();

// 添加四个点,分别位于 (0, 0, 0), (1, 0, 0), (1, 1, 0) 和 (0, 1, 0)
points->InsertNextPoint(0.0, 0.0, 0.0);
points->InsertNextPoint(1.0, 0.0, 0.0);
points->InsertNextPoint(1.0, 1.0, 0.0);
points->InsertNextPoint(0.0, 1.0, 0.0);

// 创建一个 vtkCellArray 对象,用于存储单元的类型和顶点索引
vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();

// 添加一个多边形单元,由四个点组成,顶点索引为 0, 1, 2 和 3
vtkIdType polygon[4] = { 0, 1, 2, 3 };
cells->InsertNextCell(4, polygon);

// 将点的坐标设置给 vtkPolyData 对象
polyData->SetPoints(points);///
// 将单元的类型和顶点索引设置给 vtkPolyData 对象
polyData->SetPolys(cells);/

/*******************************************************************************************/
// 创建一个 vtkDoubleArray 对象,用于存储点的属性数据,例如标量
vtkSmartPointer<vtkDoubleArray> scalars = vtkSmartPointer<vtkDoubleArray>::New();
// 设置标量的名称,用于标识属性数据的含义
scalars->SetName("Temperature");
// 添加四个标量值,分别为 10.0, 20.0, 30.0 和 40.0
scalars->InsertNextValue(10.0);//四个点对应四个标量
scalars->InsertNextValue(20.0);
scalars->InsertNextValue(30.0);
scalars->InsertNextValue(40.0);
// 将标量值设置给 vtkPolyData 对象
polyData->GetPointData()->SetScalars(scalars);
// 打印 vtkPolyData 对象的信息,包括结构、内存、单元、点和属性等
polyData->Print(std::cout);
/*******************************************************************************************/


// 创建Mapper并设置输入数据对象
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData(polyData);

// 创建Actor
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);


// 创建渲染器和渲染窗口
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);

// 创建交互器和窗口交互器
vtkSmartPointer<vtkRenderWindowInteractor> interactor =
    vtkSmartPointer<vtkRenderWindowInteractor>::New();
interactor->SetRenderWindow(renderWindow);

// 将Actor添加到渲染器
renderer->AddActor(actor);

// 开启交互器并显示窗口
renderWindow->Render();
interactor->Start();

了解vtk显示的原理_第5张图片

总结

vtkPolyData是Visualization Toolkit(VTK)中用于表示离散几何对象的数据结构之一。它是由一系列点、线和面组成的几何图元集合。

以下是vtkPolyData的一些关键特点和组成部分:

  1. Points(点):vtkPolyData包含一组点,每个点由三维坐标(x, y, z)表示。这些点可以代表几何对象的顶点或离散的数据点。
  2. Vertices(顶点):顶点是vtkPolyData的一种图元类型,它表示单个点。顶点可以用于表示离散的点或用于绘制具有点属性的几何对象。
  3. Lines(线):线是一种由连接顶点的线段组成的图元类型。vtkPolyData可以包含多条线,每条线由一系列有序的顶点组成。
  4. Polygons(多边形):多边形是由连接顶点的线段组成的封闭图元类型。多边形可以是三角形、四边形或更复杂的多边形。vtkPolyData可以包含多个多边形。
  5. Triangle Strips(三角形带):三角形带是一种特殊的图元类型,其中相邻的三角形共享一个共边,形成一个连续的三角形序列。使用三角形带可以有效地表示连续的曲面。
  6. Cell Data和Point Data:vtkPolyData可以关联Cell Data和Point Data。Cell Data是与整个图元相关联的数据,例如每个多边形的颜色。Point Data是与每个点相关联的数据,例如每个点的法线向量。这些数据可以用于在渲染和分析过程中对图元进行着色、标记或其他操作。

你可能感兴趣的:(vtk,Qt,人工智能,计算机视觉)