VTK的可视化流水线(渲染管线)

2022年1月12日 5214点热度 2人点赞 1条评论

数据可视化是以图形的形式描述数据的一种方式,这其中包括三个步骤:

  1. 将数据转换为图形元素
  2. 将图形元素转换为计算机可绘制的图形
  3. 绘制图形

VTK将这个前两个步骤分解成了一些固定的过程,每个过程由不同的对象负责,将这些过程对象链接起来就是VTK的可视化流水线。

如图是一个数据到图形的最简单的可视化流水线。

Source

Source代表数据源,源数据类型可以是多边形数据、网格数据、点数据等等,构造元数据的方式也多种多样,列如使用vtkCylinderSource类构造一个圆柱的数据,或者使用VTK提供的各种读取文件的类,从文件种生成源数据,甚至你可以通过代码手动构造一个DataSet。

总而言之,Source的作用就是将各种形式的数据输入类型,转换为Filter所需要的数据类型。

Filter

Filter在流水线中的至关重要,它的主要作用是对数据进行处理,以满足各种各样的需求。所以所有的过滤器都至少有一个输入与输出,有的过滤器根据功能需求会有多个输入与输出。

像是vtkContourFilter这样的过滤器,就只需要一个DataSet作为输入然后输出等值面或者等值线数据。但是像vtkLoopBooleanPolyDataFilter因为执行布尔运算必须要两个输入。

VTK种提供了很多种过滤器,有处理网格的,处理平滑度的,剪切数据的,等等等等,这些过滤器可以组合使用,也就是说一个流水线中可以存在多个过滤器,将他们的输入输出连接到一起使用。

Mapper

Mapper是映射器,它有输入没有输出,是可视化流水线的终点,主要功能是将数据映射到图形系统或以文件的形式存储数据。

 shut up,show your code!

#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkCylinderSource.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>

#include <array>

int main(int, char*[])
{
  vtkNew<vtkNamedColors> colors;

  // Set the background color.
  std::array<unsigned char, 4> bkg{{26, 51, 102, 255}};
  colors->SetColor("BkgColor", bkg.data());

  // This creates a polygonal cylinder model with eight circumferential facets
  // (i.e, in practice an octagonal prism).
  vtkNew<vtkCylinderSource> cylinder;
  cylinder->SetResolution(8);

  // The mapper is responsible for pushing the geometry into the graphics
  // library. It may also do color mapping, if scalars or other attributes are
  // defined.
  vtkNew<vtkPolyDataMapper> cylinderMapper;
  cylinderMapper->SetInputConnection(cylinder->GetOutputPort());

  // The actor is a grouping mechanism: besides the geometry (mapper), it
  // also has a property, transformation matrix, and/or texture map.
  // Here we set its color and rotate it around the X and Y axes.
  vtkNew<vtkActor> cylinderActor;
  cylinderActor->SetMapper(cylinderMapper);
  cylinderActor->GetProperty()->SetColor(
      colors->GetColor4d("Tomato").GetData());
  cylinderActor->RotateX(30.0);
  cylinderActor->RotateY(-45.0);

  // The renderer generates the image
  // which is then displayed on the render window.
  // It can be thought of as a scene to which the actor is added
  vtkNew<vtkRenderer> renderer;
  renderer->AddActor(cylinderActor);
  renderer->SetBackground(colors->GetColor3d("BkgColor").GetData());
  // Zoom in a little by accessing the camera and invoking its "Zoom" method.
  renderer->ResetCamera();
  renderer->GetActiveCamera()->Zoom(1.5);

  // The render window is the actual GUI window
  // that appears on the computer screen
  vtkNew<vtkRenderWindow> renderWindow;
  renderWindow->SetSize(300, 300);
  renderWindow->AddRenderer(renderer);
  renderWindow->SetWindowName("Cylinder");

  // The render window interactor captures mouse events
  // and will perform appropriate camera or actor manipulation
  // depending on the nature of the events.
  vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
  renderWindowInteractor->SetRenderWindow(renderWindow);

  // This starts the event loop and as a side effect causes an initial render.
  renderWindow->Render();
  renderWindowInteractor->Start();

  return EXIT_SUCCESS;
}

这是一个VTK提供的示例,这里使用了vtkCylinderSource创建了一个圆柱的源数据,然后将数据放入映射器中,后面是固定流程 Actor-->Renderer-->RenderWindow,就可以在窗口中显示了,不过这个示例中没有使用到过滤器(屮,这才是最简单的流水线)。

示例链接:https://kitware.github.io/vtk-examples/site/Cxx/GeometricObjects/CylinderExample/

尝试在流程中增加了一个过滤器

vtkNew<vtkExtractEdges> extactEdges;
extactEdges->SetInputConnection(cylinder->GetOutputPort());
    
vtkNew<vtkPolyDataMapper> cylinderMapper;
cylinderMapper->SetInputConnection(extactEdges->GetOutputPort());

这个过滤器获取了圆柱的轮廓线,这是最后的显示效果。

 

流水线中过程对象之间的连接

VTK提供两种连接的方式:

  1. 显示连接,显示的更新数据,当过程对象的输入数据或者参数改变时,由使用者对这些信息进行判断是否更新流水线的执行。
  2. 隐式连接,过程对象之间建立隐式连接之后,当流水线中的过程对象的输入数据或者参数发生改变时会自动更新流水线的执行。

显示连接使用SetInputData() 和GetOutputData() 这两个函数为过程对象交换数据,但是在交换数据之前必须调用过程对象的update()函数,否则GetOutputData()函数会获取到一个空白的数据对象。

隐式连接使用SetInputConnection()和GetOutputPort()这两个函数进行连接,连接之后流水线中的数据是惰性更新的,只有在Actor被显示时才会调用updata生成数据。当然在流水线中的某个过程对象的输入数据或者参数被改变时也会自动调用update()更新数据。

大脸猫

这个人虽然很勤快,但什么也没有留下!

文章评论

  • yingfeng

    2022年1月17日