文章目录
- 目标:
- 知识补充:
- 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 <vtkSmartPointer.h>
#include <vtkSTLReader.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
/*******************************************************************************/
//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();//允许评委动手尝一尝
上面这个是stl文件原图,我们试着渲染一下:
#include <vtkSmartPointer.h>
#include <vtkSTLReader.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
// 创建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();
最后,再深入了解 vtkPolyData 这个数据结构
前言
在上面已经讲了:vtkPolyData 是一种高层次的图元数据 , 有多高呢? 以至于渲染器都无法直接对其进行解析,还需要Mapper进一步解析来得到渲染器可解析的图元数据
这是官方关于vtkPolyData Class Reference的讲解,虽然我看不太懂,但是建议看看
这个是#include <vtkPolyData.h>里面的内容,不过我们在编译器中,我们加入#include <vtkPolyData.h>这个头文件,然后按下ctrl+鼠标左键的内容完全一样,只不过最上面多了60行的注释
这个文件记录了vtkPolyData这类的所有方法和一些inline函数
继承关系
然后,更新详细一点:
vtkPolyData-> vtkPointSet->vtkDataSet->vtkDataObject->vtkObject->vtkObjectBase(基类)
尝试一,使用vtk代码生成一个三角形,并生成stl文件保存到本地
#include <QMainWindow>
#include <vtkGenericOpenGLRenderWindow.h>
#include <QVTKInteractor.h>
#include <vtkInteractorStyle.h>
#include <QDebug>
#include <vtkSmartPointer.h>
#include <vtkSTLReader.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
#include <vtkPolyData.h>
#include <vtkDoubleArray.h>
#include <vtkPointData.h>
#include <vtkSTLWriter.h>
/***************************************************/
// 创建点坐标
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
尝试二,正方形
// 创建一个 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();
总结
vtkPolyData是Visualization Toolkit(VTK)中用于表示离散几何对象的数据结构之一。它是由一系列点、线和面组成的几何图元集合。
以下是vtkPolyData的一些关键特点和组成部分:
- Points(点):vtkPolyData包含一组点,每个点由三维坐标(x, y, z)表示。这些点可以代表几何对象的顶点或离散的数据点。
- Vertices(顶点):顶点是vtkPolyData的一种图元类型,它表示单个点。顶点可以用于表示离散的点或用于绘制具有点属性的几何对象。
- Lines(线):线是一种由连接顶点的线段组成的图元类型。vtkPolyData可以包含多条线,每条线由一系列有序的顶点组成。
- Polygons(多边形):多边形是由连接顶点的线段组成的封闭图元类型。多边形可以是三角形、四边形或更复杂的多边形。vtkPolyData可以包含多个多边形。
- Triangle Strips(三角形带):三角形带是一种特殊的图元类型,其中相邻的三角形共享一个共边,形成一个连续的三角形序列。使用三角形带可以有效地表示连续的曲面。
- Cell Data和Point Data:vtkPolyData可以关联Cell Data和Point Data。Cell Data是与整个图元相关联的数据,例如每个多边形的颜色。Point Data是与每个点相关联的数据,例如每个点的法线向量。这些数据可以用于在渲染和分析过程中对图元进行着色、标记或其他操作。