VTK Tutorial
VTK Tutorial
官方教程:https://examples.vtk.org/site/Cxx/#tutorial
关于如何编译运行,我使用官方的方法无法运行,下面介绍我使用的方法。我的配置是windows10 + vs2017 + vtk9.1 + cmake3.30。
第一步:使用cmake gui编译
第二步:
点击一次configure,会弹出一个对话框,选择你的vs版本,以及x64.
第三步:
点击一次后,gui中间可能是红的,不必管他,保证gui最下面出现Configuring done 即可。此时再点击一次Configure,应该就不报红了,然后点击generate。
第四步:
去build文件夹下,用vs打开.sln
改成release,再右键all_build,点击生成。
生成成功。
第五步:
去release文件夹下,执行exe
Step1
此示例创建了一个圆锥体的多边形模型,然后将其渲染到屏幕上。它将圆锥体旋转 360 度,然后退出。大多数VTK程序的基本流程都是source -> mapper -> actor -> renderer -> renderwindow
代码流程
- 创建并设置圆锥源(source): 生成几何数据(例如,圆锥体的几何形状)。创建了一个
vtkConeSource
对象,设置了圆锥的高度、半径和分辨率。这个源对象负责生成圆锥体的几何数据。 - 创建
vtkPolyDataMapper
映射器(mapper):将几何数据映射到图形原语(如三角形)。vtkPolyDataMapper
用于将几何数据(在本例中是圆锥的多边形数据)映射到图形原语(例如三角形)上,使得数据可以被渲染。通过SetInputConnection
方法将圆锥的数据连接到映射器。 - 创建并设置演员 (
vtkActor
)(actor):负责在场景中呈现物体(管理位置、颜色等属性)。vtkActor
代表一个可渲染的对象。它是实际显示在场景中的对象,包含了映射器、颜色等信息。将圆锥的映射器设置到演员中,并且通过GetProperty()->SetColor
设置了演员的颜色为 “Tomato”(番茄红)。 - 创建渲染器和渲染窗口(renderer):负责管理场景中的所有演员,执行渲染操作。
vtkRenderer
是负责渲染场景的对象,我们将渲染器添加到渲染窗口 (vtkRenderWindow
) 中。渲染窗口是实际显示 3D 场景的窗口。 - 创建并设置渲染窗口交互器(renderwindow):展示渲染结果的窗口。
vtkRenderWindowInteractor
允许用户与渲染窗口进行交互,例如旋转、缩放或平移视图。
示例代码
1 | // 创建一个 vtkNamedColors 的实例,使用它来为对象和背景选择颜色。 |
vtkNamedColors
是一个类,提供了对常见颜色名称的访问。例如,它可以让我们用"Tomato"
、"CadetBlue"
等预定义的颜色名称,而不是手动指定 RGB 值。这里创建了一个colors
对象,方便我们在后续代码中选择颜色。
1 | // 现在我们创建一个 vtkConeSource 的实例,并设置它的一些属性。 |
vtkConeSource
是一个源对象,用于生成一个圆锥体的几何数据。通过设置以下参数来控制圆锥的属性:SetHeight(3.0)
:设置圆锥的高度为 3.0 单位。SetRadius(1.0)
:设置圆锥的底面半径为 1.0 单位。SetResolution(10)
:设置圆锥底面的分辨率,即底面多边形的边数。较高的分辨率会使圆锥底面更平滑。
1 | // 在这个例子中,我们通过一个映射器处理对象来终结管道。 |
vtkPolyDataMapper
是一个用于将多边形数据(例如圆锥的几何数据)转换为图形原语的对象。它是 VTK 渲染管线中的重要组件。SetInputConnection(cone->GetOutputPort())
:将圆锥源的输出数据连接到映射器的输入端,表示映射器将使用圆锥的数据进行渲染。
1 | // 创建一个演员来表示圆锥体。演员协调映射器的图形原语的渲染。 |
vtkActor
是一个表示可视化对象的核心组件,它将多边形数据通过映射器传递给渲染器。演员将负责场景中对象的可视化表示。SetMapper(coneMapper)
:将映射器coneMapper
与演员coneActor
绑定,使得演员可以使用映射器渲染的数据。- 每个演员都有一个
vtkProperty
对象,用于管理它的可视化属性(例如颜色、透明度等)。GetProperty()
获取演员的属性对象。SetColor(colors->GetColor3d("MistyRose").GetData())
设置演员的颜色为MistyRose
(雾玫瑰色)。colors->GetColor3d("MistyRose")
返回一个vtkColor3d
对象,它表示 MistyRose 颜色的 RGB 值。通过.GetData()
方法,实际的 RGB 数据被提取出来并应用到演员的属性上。
1 | // 创建渲染器并将演员分配给它。渲染器像一个视口。 |
vtkNew<vtkRenderer> ren1;
:使用vtkNew
创建了一个新的渲染器对象ren1
。渲染器是 VTK 中的核心组件之一,负责控制场景的绘制,类似于一个视口(viewport)。渲染器会管理显示在窗口中的所有对象,并决定如何绘制它们。ren1->AddActor(coneActor);
:将之前创建的演员coneActor
添加到渲染器ren1
中。演员是负责渲染可视化对象的组件。在这个例子中,演员代表了一个圆锥体对象。渲染器将会根据演员的属性(如颜色、位置等)来绘制它。ren1->SetBackground(colors->GetColor3d("MidnightBlue").GetData());
:设置渲染器的背景颜色为 MidnightBlue(午夜蓝)。colors->GetColor3d("MidnightBlue")
返回一个vtkColor3d
对象,该对象包含 RGB 颜色值,.GetData()
方法用于提取实际的 RGB 数据并传递给SetBackground()
方法。这使得渲染窗口的背景色变为午夜蓝。
1 | // 最后,我们创建一个渲染窗口,渲染窗口将显示在屏幕上。 |
vtkNew<vtkRenderWindow> renWin;
:创建了一个新的渲染窗口renWin
。渲染窗口是一个图形界面窗口,负责显示渲染器中所有的对象。它通常对应于用户看到的图形输出窗口。renWin->AddRenderer(ren1);
:将之前创建的渲染器ren1
添加到渲染窗口renWin
中。通过这个设置,渲染窗口renWin
就能够显示渲染器ren1
中的图形内容(如圆锥体及其背景色)。renWin->SetSize(300, 300);
:设置渲染窗口的大小为 300 像素 x 300 像素。renWin->SetWindowName("Tutorial_Step1");
:设置渲染窗口的标题为"Tutorial_Step1"
。
1 | // 现在我们循环 360 度,每次渲染圆锥体。 |
renWin->Render();
:负责触发渲染窗口的绘制操作。每次调用Render()
方法时,渲染窗口会根据渲染器中的内容更新图形显示。ren1->GetActiveCamera()->Azimuth(1);
:通过ren1->GetActiveCamera()
获取当前渲染器中正在使用的相机,并调用Azimuth(1)
方法让相机绕其垂直轴旋转 1 度。Azimuth()
方法用于使相机沿水平方向(围绕 z 轴)旋转指定的角度。
效果
Step2
VTK 使用命令/观察者设计模式。也就是说,观察者会监视任何vtkObject(或子类)可能对其自身调用的特定事件。例如,vtkRenderer在开始渲染时会调用“StartEvent”。这里我们添加了一个观察者,当观察到此事件时,它会调用命令。
与step1的区别主要在于随着圆锥体的旋转,回调函数会打印出当前活动摄像机的三维位置。
示例代码
1 | // 首先包含我们正在使用的 VTK 类所需的头文件。 |
- 命名空间: 使用匿名命名空间(
namespace {}
)封装回调函数,确保它仅在当前文件中可见。这是一种避免全局变量命名冲突的好方法。 - vtkMyCallback 类:
vtkMyCallback
类继承自vtkCommand
,这是 VTK 中处理事件和回调的基类。Execute()
方法是回调函数的核心。当事件触发时,该方法会被调用。在这里,它从vtkRenderer
获取活动相机的位置并将其打印出来。
reinterpret_cast
: 使用reinterpret_cast
将传递给回调函数的caller
对象转换为vtkRenderer*
类型。caller
是触发回调的对象(在此为vtkRenderer
),通过这种方式获取相机位置。- 打印相机位置: 使用
renderer->GetActiveCamera()->GetPosition()
获取相机的 3D 坐标(x, y, z),并打印到控制台。
1 | vtkNew<vtkNamedColors> colors; |
- 这部分代码和step1中的完全相同,除了多了一行
ren1->ResetCamera();
,用于重置相机的位置,使得圆锥体正确显示在视口中。ResetCamera()
会根据场景中的对象自动调整摄像机位置,确保它们可以被清晰地看到。
1 | // Here is where we setup the observer. |
vtkNew<vtkMyCallback> mo1;
:创建一个vtkMyCallback
类型的回调函数对象mo1
。ren1->AddObserver(vtkCommand::StartEvent, mo1);
:将回调函数mo1
添加到渲染器ren1
上,并监听StartEvent
事件。vtkCommand::StartEvent
是 VTK 的一个事件类型,当渲染开始时会触发该事件,从而调用mo1
中的Execute()
方法。
1 | // 现在我们循环 360 度,每次渲染圆锥体。 |
- 与step1类似
效果
与step1不同的是,多进行了一段屏幕输出(回调函数),共计输出了360行。
step3
此示例演示如何在渲染窗口内使用多个渲染器。(创建了两个不同的渲染器,显示相同的圆锥体对象在不同的视口中)
示例代码
1 | vtkNew<vtkNamedColors> colors; |
- 和之前完全一致。
1 | // 创建两个渲染器并将演员添加到其中。渲染器将演员渲染到 vtkRenderWindow 内的一个视口中。 |
创建一个渲染器
ren1
,并将圆锥体的演员coneActor
添加到其中。设置背景颜色为
RoyalBlue
。SetViewport(0.0, 0.0, 0.5, 1.0)
:设置渲染器的视口(即渲染区域)。这里,视口的范围是(0.0, 0.0)
到(0.5, 1.0)
,即占据窗口的左半部分。
创建另一个渲染器
ren2
,并添加相同的演员coneActor
。- 设置背景颜色为
DodgerBlue
。 SetViewport(0.5, 0.0, 1.0, 1.0)
:设置第二个渲染器的视口为右半部分,覆盖窗口的右半部分。
- 设置背景颜色为
1 | vtkNew<vtkRenderWindow> renWin; |
- 与之前类似
效果
step4
此示例演示了如何创建多个参与者以及如何操纵他们的属性和转换。
示例代码
1 | vtkNew<vtkNamedColors> colors; |
- 与之前相同
1 | // 创建一个演员来表示第一个圆锥。演员的属性被修改,以赋予它不同的表面属性。 |
创建一个
vtkActor
对象,并将圆锥的映射器coneMapper
设置为该演员的映射器。coneActor->GetProperty()->SetColor(0.2, 0.63, 0.79)
设置演员的颜色(RGB 值为 0.2, 0.63, 0.79)。设置演员的材质属性:漫反射强度为 0.7,镜面反射强度为 0.4,镜面反射高光强度为 20。这些属性影响演员在渲染时的外观效果。
创建了一个新的
vtkProperty
对象,设置其颜色为"Tomato"
,漫反射强度为 0.7,镜面反射强度为 0.4,镜面反射高光强度为 20。创建第二个演员
coneActor2
,并为其设置与第一个演员相同的映射器coneMapper
。设置
coneActor2
的颜色为"LightSeaGreen"
,并将之前创建的property
设置为该演员的材质属性。将第二个演员
coneActor2
的位置设置为(0, 2, 0)
,即在 Y 轴上将其上移 2 个单位。
两个问题:
1.示例代码中对actor2的颜色设置部分存在冗余代码
1 | property->SetColor(colors->GetColor3d("Tomato").GetData()); |
最终的颜色是Tomato,第二行代码冗余。
2.只设置actor2的位置,没有设置actor的位置。
coneActor2->SetPosition(0, 2, 0);
: 这行代码设置了coneActor2
的位置。SetPosition
会将该演员的几何位置设置为 (0, 2, 0),即沿 Y 轴偏移 2 单位。- 默认情况下,如果没有特别设置位置,演员会处于原点
(0, 0, 0)
。因此,coneActor
没有调用SetPosition
,它会保持在默认位置。 - 在 VTK 中,演员的坐标是相对于渲染器的原点的。通常,如果你有多个演员,并且希望它们不重叠,可以为每个演员设置不同的位置。在这段代码中,
coneActor2
被显式地放置到(0, 2, 0)
,而coneActor
使用默认位置(0, 0, 0)
。
step5
引入交互的概念,定义了一种不同于默认的交互风格。(通过 vtkInteractorStyleTrackballCamera
实现)
示例代码
1 | vtkNew<vtkNamedColors> colors; |
- 与之前一样
1 | // vtkRenderWindowInteractor 类用于监视 vtkRenderWindow 中的事件(例如,按键、鼠标事件)。 |
- 创建了一个
vtkRenderWindowInteractor
对象iren
,它使得用户能够与渲染窗口进行交互。SetRenderWindow()
将窗口与交互器关联。 - 创建了一个
vtkInteractorStyleTrackballCamera
对象style
,这是一个常用的交互样式,可以通过鼠标拖动来旋转、平移和缩放视图。并将交互器样式设置为style
,使得用户可以通过鼠标控制视角。 iren->Initialize()
初始化交互器。iren->Start()
启动交互,程序将在此处等待用户交互。
效果
用户可以通过鼠标拖动查看不同视角下的模型。
step6
此示例介绍了 3D 小部件。3D 小部件利用了前面介绍的事件/观察者设计模式。它们通常在场景中具有特定的表示,可以使用鼠标和键盘进行交互选择和操作。当操作小部件时,它们依次调用 StartInteractionEvent、InteractionEvent 和 EndInteractionEvent 等事件,这些事件可用于操作小部件所嵌入的场景。3D 小部件在上一个示例中设置的事件循环上下文中工作。
示例代码
1 | namespace { |
void Execute(vtkObject* caller, unsigned long, void*)
Execute
是重写自vtkCommand
的虚函数。当事件触发时,这个方法会被调用。在这个回调函数中,具体的操作是对vtkBoxWidget
进行变换的获取和设置。vtkObject* caller
:caller
是触发事件的对象。在这个回调中,它将被转换为vtkBoxWidget*
类型。vtkBoxWidget
是一个交互式的控件,通常用于控制对象的变换(例如移动、旋转、缩放等)。
unsigned long
和void*
:- 这两个参数通常用于处理事件的 ID 和附加数据,但在这个回调函数中并没有被使用。
vtkNew<vtkTransform> t;
- 创建了一个新的
vtkTransform
对象t
,该对象用于存储 3D 变换(如位置、旋转、缩放)。vtkTransform
是 VTK 用于表示几何变换(如平移、旋转、缩放等)的类。
- 创建了一个新的
auto widget = reinterpret_cast<vtkBoxWidget*>(caller);
- 通过
reinterpret_cast
将caller
转换为vtkBoxWidget*
类型。caller
是触发事件的对象,我们期望它是一个vtkBoxWidget
,因此需要进行类型转换。
- 通过
widget->GetTransform(t);
- 调用
vtkBoxWidget
的GetTransform
方法,将当前vtkBoxWidget
的变换信息(例如位置、旋转、缩放)存储到t
变量中。
- 调用
widget->GetProp3D()->SetUserTransform(t);
- 获取
vtkBoxWidget
对象的 3D 属性(GetProp3D()
),然后调用SetUserTransform(t)
,将之前获取的变换应用到控件的 3D 属性上。 SetUserTransform
方法允许用户在现有的控件基础上应用额外的变换。
- 获取
vtkBoxWidget
是一个用于交互式操作的 VTK 小部件,它允许用户通过鼠标拖动和操作一个 3D 的盒子(或矩形区域),来进行模型的变换。vtkBoxWidget
具有与这些操作相关的事件和回调机制,通过监听这些事件并响应,可以在vtkActor
上实现这些变换。vtkTransform
是 VTK 中用于存储和应用变换(如平移、旋转、缩放等)的类。在代码中,我们使用vtkTransform
来存储和应用vtkBoxWidget
获取到的变换。widget->GetTransform(t);
这行代码获取
vtkBoxWidget
当前的变换,并将其存储到vtkTransform
对象t
中。vtkBoxWidget
内部会跟踪用户通过交互对物体所做的变换(平移、缩放、旋转等)。GetTransform
会将这些变换信息提取出来。widget->GetProp3D()->SetUserTransform(t);
最后,通过
widget->GetProp3D()
获取与vtkBoxWidget
关联的vtkProp3D
对象(即需要变换的 3D 图形对象)。然后调用SetUserTransform(t)
方法,应用之前从vtkBoxWidget
中获取到的变换。SetUserTransform
允许将vtkTransform
应用到 3D 对象上,使得对象的变换(平移、旋转、缩放)生效。
1 | vtkNew<vtkNamedColors> colors; |
- 与之前一样
1 | vtkNew<vtkBoxWidget> boxWidget; |
vtkBoxWidget
是 VTK 中一个交互式小部件,允许用户通过拖动一个 3D 方框来变换场景中的对象。用户可以通过拖动盒子的边、角来平移、旋转和缩放物体。boxWidget->SetInteractor(iren);
使得vtkBoxWidget
能够与交互器iren
关联,从而能够响应用户的鼠标输入。boxWidget->SetPlaceFactor(1.25);
设置盒子小部件的缩放因子。这个因子影响了盒子的尺寸,通常是通过调整vtkBoxWidget
形成的盒子与场景中物体的相对比例来控制。1.25
的值表示盒子在默认情况下稍微大于物体本身。boxWidget->GetOutlineProperty()->SetColor(colors->GetColor3d("Gold").GetData());
设置盒子轮廓的颜色为 “Gold”(金色)。GetOutlineProperty()
获取盒子的属性,之后设置颜色。boxWidget->SetProp3D(coneActor);
将coneActor
设置为vtkBoxWidget
的目标物体,意味着用户将通过拖动盒子来变换这个圆锥体 (coneActor
)。boxWidget->PlaceWidget();
调用此方法后,vtkBoxWidget
会根据coneActor
的边界自动设置盒子的位置和大小,使得盒子能够完全包围住物体。这样,用户就可以通过调整盒子的大小和位置来操作圆锥体。vtkMyCallback
是前面我们分析过的自定义回调类,它会在用户与vtkBoxWidget
交互时被触发。回调函数Execute
会在盒子的小部件与用户交互时被调用,用于处理变换(平移、旋转、缩放)。boxWidget->AddObserver(vtkCommand::InteractionEvent, callback);
将回调函数callback
注册到vtkBoxWidget
上。当用户进行交互时(如拖动、缩放、旋转盒子),vtkCommand::InteractionEvent
事件会触发,进而调用vtkMyCallback::Execute
方法,更新coneActor
的变换。boxWidget->On();
启用vtkBoxWidget
,使得它可以响应用户的交互。此时用户可以通过鼠标操作盒子,改变coneActor
的变换。