2. VTK的流水线设计以及三维场景的基本要素

这个专栏是用于记录我在学习VTK过程中的一些心得体会。参考的资料主要有以下三个:

1. 张晓东 罗火灵《VTK图形图像开发进阶》
2. https://examples.vtk.org/site/
3. 沈子恒 《VTK 三维数据渲染进阶》

遇到的一个大问题就是由于版本更新,这些资料中很多代码无法正常运行,需要进行一定的修改,所以这个专栏会记录下来我修改后的程序代码,以便于我之后温习。也希望能给和我有同样困扰的小伙伴们一些帮助。

我使用的版本:VTK9 + VS2022
 

在上一篇中我介绍了一个绘制棱柱的程序代码,并通过这个程序代码引出了VTK的流水线设计。在这一篇文章中,我将详细介绍VTK的流水线设计。

先复习一下上一篇的程序:

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
///
#include "vtkCylinderSource.h"
#include "vtkPolyDataMapper.h"
#include "vtkActor.h"
#include "vtkProperty.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkCamera.h"

int main()
{
	//Visualize Pipeline : Source->Mapper->Actor
		//
	vtkCylinderSource * cylinder = vtkCylinderSource::New();
	cylinder->SetHeight(3.0);
	cylinder->SetRadius(1.0);
	cylinder->SetResolution(8);

	vtkPolyDataMapper* cylinderMapper = vtkPolyDataMapper::New();
	cylinderMapper->SetInputConnection(cylinder->GetOutputPort());

	vtkActor* cylinderActor = vtkActor::New();
	cylinderActor->SetMapper(cylinderMapper);
	///Actor property
	cylinderActor->GetProperty()->SetColor(1.0, 0.32, 0.27);
	cylinderActor->RotateX(30.0);
	cylinderActor->RotateY(-45);

	//Render Engine:Renderer->RenderWindow->RenderWindowInteractor
	//
	vtkRenderer* cylinderRenderer = vtkRenderer::New();
	vtkRenderWindow* cylinderRenderWindow = vtkRenderWindow::New();
	vtkRenderWindowInteractor* iren = vtkRenderWindowInteractor::New();
	cylinderRenderWindow->AddRenderer(cylinderRenderer);
	iren->SetRenderWindow(cylinderRenderWindow);

	//Visualize Pipeline -> Render Engine
	//
	cylinderRenderer->AddActor(cylinderActor);
	cylinderRenderer->SetBackground(0.1, 0.2, 0.4); // render background property
	cylinderRenderWindow->SetSize(400, 400);  //render window size

	//Camera
	// The renderer renders into the
		// render window. The render window interactor captures mouse events
		// and will perform appropriate camera or actor manipulation
		// depending on the nature of the events.
	cylinderRenderer->ResetCamera();
	cylinderRenderer->GetActiveCamera()->Zoom(1.5);  //focus

	//Window Hold On
	iren->Start();

	//Clear Memory
	iren->Delete();
	cylinderRenderWindow->Delete();
	cylinderRenderer->Delete();
	cylinderActor->Delete();
	cylinderMapper->Delete();
	cylinder->Delete();
	return 0;
}

1.VTK的流水线设计

一般来说,VTK的流水线是这样子的:

Source->Filter->Mapper->Actor

而我们在VTK的绘制代码可以大概分为以下10部分:

1. create procedural geometry; (构造数据源)

2. create a mapper;

3. give the geometry to the mapper; (生成VTK数据结构)

4. create an actor;(构造演员)

5. give the mapper to the actor; (给演员化妆)

6. create a renderer;(布置舞台)

7. create a window; (装饰剧院)

8. give the renderer to  the window;(搭建舞台)

9. give the actor to the renderer; (演员上台)

10. window->render(); 

看上去好像步骤挺多的,实际上每一部分都是固定的套路,先定义,然后设置相关参数。比如create procedural geometry这里,首先

vtkCylinderSource* cylinder = vtkCylinderSource::New();

然后修改相关参数

cylinder->SetHeight(3.0);
cylinder->SetRadius(1.0);
cylinder->SetResolution(8);

2. 三维场景的基本要素

光照和相机是三维渲染场景必备的因素,如果没有指定,vtkRenderer会自动地创建默认的光照和相机。

灯光

VTK里用类vtkLight来表示渲染场景中的光照。VTK中的vtkLight实例可以打开、关闭,设置光照的颜色,照射位置(即焦点),光照所在的位置,强度等等。vtkLight可以分为位置光照(Positional Light,即聚光灯)和方向光照(Direction Light)。位置光照是光源位置在渲染场景中的某个位置,可以指定光照的衰减值、锥角等;方向光照即光源位置在无穷远,光线可以认为是平行的,比如自然界中的太阳光。光源的位置和焦点的连线定义光线的方向,默认的vtkLight即为方向光照。


vtkLight常的方法有:
SetColor() — 设置光照的颜色,以RGB的形式指定颜色。
SetPosition() — 设置光照位置。
SetFocalPoint() — 设置光照焦点。
SetIntensity() — 设置光照的强度。
SetSwitch() / SwitchOn()/ SwitchOff()— 打开或关闭对应的光照。

下面的示例简单展示了vtkLight的使用方法。这里定义了两个vtkLight对象,一个是绿色光,,位置在(0,0,1)一个是蓝色光,位置在(0,0,-1)。两个对象的焦点都是对着相机的焦点。

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);

#include <vtkSmartPointer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkCylinderSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkLight.h>
#include <vtkCamera.h>
#include <vtkProperty.h>


/*
( - 6, 0, 0)blue light(6, 0, 0)green light--> X Axis
	(0, -6, 0)blue light(0, 6, 0)green light--> Y Axis
	(0, 0, -6)blue light(0, 0, 6)green light-->Z Axis
	*/

int main()
{
	vtkSmartPointer<vtkCylinderSource> cylinder =
		vtkSmartPointer<vtkCylinderSource>::New();
	cylinder->SetHeight(3.0);
	cylinder->SetRadius(1.0);
	cylinder->SetResolution(10);

	vtkSmartPointer<vtkPolyDataMapper> cylinderMapper =
		vtkSmartPointer<vtkPolyDataMapper>::New();
	cylinderMapper->SetInputConnection(cylinder->GetOutputPort());

	vtkSmartPointer<vtkActor> cylinderActor =
		vtkSmartPointer<vtkActor>::New();
	cylinderActor->SetMapper(cylinderMapper);

	vtkSmartPointer<vtkRenderer> renderer =
		vtkSmartPointer<vtkRenderer>::New();
	renderer->AddActor(cylinderActor);
	renderer->SetBackground(1.0, 0, 0);

	vtkSmartPointer<vtkRenderWindow> renWin =
		vtkSmartPointer<vtkRenderWindow>::New();
	renWin->AddRenderer(renderer);
	renWin->SetSize(640, 480);
	renWin->Render();
	renWin->SetWindowName("RenderCylinder-Lights");

	vtkSmartPointer<vtkRenderWindowInteractor> iren =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	iren->SetRenderWindow(renWin);

	vtkSmartPointer<vtkInteractorStyleTrackballCamera> style =
		vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
	iren->SetInteractorStyle(style);

	vtkSmartPointer<vtkLight> myLight =
		vtkSmartPointer<vtkLight>::New();
	myLight->SetColor(0, 1, 0);
	myLight->SetPosition(0, 0, 6);
	myLight->SetFocalPoint(
		renderer->GetActiveCamera()->GetFocalPoint());
	renderer->AddLight(myLight);

	vtkSmartPointer<vtkLight> myLight2 =
		vtkSmartPointer<vtkLight>::New();
	myLight2->SetColor(0, 0, 1);
	myLight2->SetPosition(0, 0, -6);
	myLight2->SetFocalPoint(
		renderer->GetActiveCamera()->GetFocalPoint());
	renderer->AddLight(myLight2);

	//camera setting
	//vtkSmartPointer<vtkCamera> mycamera =
	//	vtkSmartPointer<vtkCamera>::New();
	//mycamera->SetFocalPoint(0, 0, 0);
	//mycamera->SetPosition(-5, 0, 0);
	//mycamera->SetClippingRange(5.5, 6.5);
	//mycamera->ComputeViewPlaneNormal();
	//mycamera->SetViewUp(0, 1, 0);
	//renderer->SetActiveCamera(mycamera);

	//vtkSmartPointer<vtkCamera> mycamera =
	//	vtkSmartPointer<vtkCamera>::New();
	//mycamera->SetFocalPoint(0, 0, 0);
	//mycamera->SetPosition(-10, 0, 0);
	//mycamera->SetClippingRange(10.5, 11.5);
	//mycamera->ComputeViewPlaneNormal();
	//mycamera->SetViewUp(0, 1, 0);
	//renderer->SetActiveCamera(mycamera);

	vtkSmartPointer<vtkCamera> mycamera =
		vtkSmartPointer<vtkCamera>::New();
	mycamera->SetFocalPoint(0, 0, 0);
	mycamera->SetPosition(-10, 0, 0);
	mycamera->SetClippingRange(5.0, 9.0);
	mycamera->ComputeViewPlaneNormal();
	mycamera->SetViewUp(0, 1, 0);
	renderer->SetActiveCamera(mycamera);

	iren->Initialize();
	iren->Start();

	return EXIT_SUCCESS;

}

运行结果:

 

light

相机

观众的眼睛就好比三维渲染场景中的相机,VTK则是用vtkCamera类来表示三维渲染场景中的相机。vtkCamera负责把三维场景投影到二维平面,如屏幕、图像等。

从上图可以看出,与相机投影相关的因素主要有:
相机位置:即相机所在的位置,用方法vtkCamera::SetPosition()设置。
相机焦点:用方法vtkCamera::SetFocusPoint()设置, 默认的焦点位置在世界坐标系的原点。
朝上方向:即哪个方向为相机朝上的方向。就好比我们直立看东西,方向为头朝上,看到的东西也是直立的,如果我们倒立看某个东西,这时方向为头朝下,看到的东西当然就是倒立的。相机位置、相机焦点和朝上方向三个因素确定了相机的实际方向,即确定相机的视图。
投影方向:相机位置到相机焦点的向量方向即为投影方向。
投影方法:确定Actor是如何映射到像平面的。vtkCamera定义了两种投影方法,一种是正交投影(OrthographicProjection),也叫平行投影(Parallel Projection),即进入相机的光线与投影方向是平行的。另一种是透视投影(PerspectiveProjection),即所有的光线相交于一点。
视角:透视投影时需要指定相机的视角(View Angle),默认的视角大小为30º,可以用方法vtkCamera::SetViewAngle()设置。
前后裁剪平面:裁剪平面与投影方向相交,一般与投影方向也是垂直的。裁剪平面主要用于评估Actor与相机距离的远近,只有在前后裁剪平面之间的Actor才是可见的。裁剪平面的位置可以用方法vtkCamera::SetClippingRange()设置。

在前文灯光章节的代码中,我已经加入了camera的生成与设置:

vtkSmartPointer<vtkCamera> mycamera =
		vtkSmartPointer<vtkCamera>::New();
	mycamera->SetFocalPoint(0, 0, 0);
	mycamera->SetPosition(-10, 0, 0);
	mycamera->SetClippingRange(5.0, 9.0);
	mycamera->ComputeViewPlaneNormal();
	mycamera->SetViewUp(0, 1, 0);
	renderer->SetActiveCamera(mycamera);

大家可以根据自己的需求调整相应的参数并进行试验。

颜色

颜色是Actor的重要属性之一。VTK主要采用RGB和HSV两种颜色系统来描述颜色。

RGB 颜色系统由三个颜色分量:红色(R)、绿色(G)和蓝色(B)的组合表示,在VTK 里,这三个分量的取值范围都是 0~1,(0,0,0)表示黑色,(,1,1)表示白色。vtkProperty:SeColor(r, g,b)采用的就是 RGB 颜色系统设置颜色属性值。


HSV颜色系统同样也是由三个分量来决定颜色,它们分别是:色相(Fue),表示颜色的基本属性,就是迺常所说的颜色名称,如红色、黄色等;饱和度 (Saturation),是指颜色的纯度,其值越高则越纯;值(Value),也就是强度 Intensity 或者亮度 Bright,值为0通常表示的是黑色,值为 1表示的是最亮的颜色。这三个分量的取值范围 0~1。类vtkLookupTable提供了 HSV颜色系统设置的方法。

常见的颜色RGB和HSV值对照表:
颜色RGBHSV
黑色0,0,0*,*,0
白色1,1,1*,0,1
红色1,0,00,1,1
绿色0,1,01/3,1,1
蓝色0,0,12/3,1,1
黄色1,1,01/6,1,1
蓝绿色0,1,11/2,1,1
品红色1,0,15/6,1,1
天蓝色1/2,1/2,12/3,1/2,1

 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值