VTK随笔三:坐标系统、空间变换、VTK管线、VTK智能指针

一、坐标系统 

  • Model坐标系统:定义模型时所采用的坐标系统,通常是局部的笛卡尔坐标系。
  • World坐标系统:是放置Actor的三维空间坐标系,Actor(vtkActor类)其中的一个功能就是负责将模型从Model坐标系统变换到World坐标系统。每一个模型可以定义自己的Model坐标系统,但World坐标系只有一个,每一个Actor必须通过放缩、旋转、平移等操作将Model坐标系变换到World坐标系。World坐标系同时也是相机和灯光所在的坐标系统。
  • View坐标系统:表示的是相机所看见的坐标系统。X、Y、Z轴取值为[-1, 1],X、Y值表示像平面上的位置,Z值表示到相机的距离。相机负责将World坐标系变换到View坐标系。
  • Display坐标系统:与View坐标系统类似,但是各坐标轴的取值不是[-1, 1],而是使用屏幕的像素值。屏幕上显示的不同窗口的大小会影响View坐标系的坐标值[-1, 1]到Display坐标系的映射。可以把不同的渲染场景放在同一个窗口进行显示,例如,在一个窗口里,分为左右两个渲染场景,这左右的渲染场景(vtkRenderer)就是不同的视口(Viewport)。

示例Viewport实现将一个窗口分为4个视口:

#include <QApplication>
#include <QVTKOpenGLNativeWidget.h>
#include <vtkActor.h>
#include <vtkNew.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderer.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkConeSource.h>
#include <vtkCubeSource.h>
#include <vtkCylinderSource.h>
#include <vtkSphereSource.h>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // 创建四个不同形状的源对象
    vtkNew<vtkConeSource> cone;
    vtkNew<vtkCubeSource> cube;
    vtkNew<vtkCylinderSource> cylinder;
    vtkNew<vtkSphereSource> sphere;

    // 创建四个Mapper对象,将源对象连接到Mapper上
    vtkNew<vtkPolyDataMapper> coneMapper;
    coneMapper->SetInputConnection(cone->GetOutputPort());
    vtkNew<vtkPolyDataMapper> cubeMapper;
    cubeMapper->SetInputConnection(cube->GetOutputPort());
    vtkNew<vtkPolyDataMapper> cylinderMapper;
    cylinderMapper->SetInputConnection(cylinder->GetOutputPort());
    vtkNew<vtkPolyDataMapper> sphereMapper;
    sphereMapper->SetInputConnection(sphere->GetOutputPort());

    // 创建四个Actor对象,并将Mapper连接到Actor上
    vtkNew<vtkActor> coneActor;
    coneActor->SetMapper(coneMapper);
    vtkNew<vtkActor> cubeActor;
    cubeActor->SetMapper(cubeMapper);
    vtkNew<vtkActor> cylinderActor;
    cylinderActor->SetMapper(cylinderMapper);
    vtkNew<vtkActor> sphereActor;
    sphereActor->SetMapper(sphereMapper);

    // 创建四个Renderer对象,并设置每个Renderer的背景颜色和视口
    vtkNew<vtkRenderer> renderer1;
    renderer1->AddActor(coneActor);
    renderer1->SetBackground(1.0,0.0,0.0);
    renderer1->SetViewport(0.0,0.0,0.5,0.5);
    vtkNew<vtkRenderer> renderer2;
    renderer2->AddActor(cubeActor);
    renderer2->SetBackground(0.0,1.0,0.0);
    renderer2->SetViewport(0.5,0.0,1.0,0.5);
    vtkNew<vtkRenderer> renderer3;
    renderer3->AddActor(cylinderActor);
    renderer3->SetBackground(0.0,0.0,1.0);
    renderer3->SetViewport(0.0,0.5,0.5,1.0);
    vtkNew<vtkRenderer> renderer4;
    renderer4->AddActor(sphereActor);
    renderer4->SetBackground(1.0,1.0,0.0);
    renderer4->SetViewport(0.5,0.5,1.0,1.0);

    // 创建RenderWindow对象,并将四个Renderer添加到RenderWindow中
    vtkNew<vtkGenericOpenGLRenderWindow> renderWindow;
    renderWindow->AddRenderer(renderer1);
    renderWindow->AddRenderer(renderer2);
    renderWindow->AddRenderer(renderer3);
    renderWindow->AddRenderer(renderer4);
    QVTKOpenGLNativeWidget w;
    w.setRenderWindow(renderWindow);

    w.show();
    return a.exec();
}

效果如下:

vtkCoordinate可以用来表示坐标系统,其内部提供了函数接口来定义坐标系统: 

SetCoordinateSystemToDisplay()
SetCoordinateSystemToNormalizedDisplay()
SetCoordinateSystemToViewport()
SetCoordinateSystemToNormalizedViewport()
SetCoordinateSystemToView()
SetCoordinateSystemToWorld()

另外,该类还实现这些坐标系统之间的转换,例如下述代码实现了归一化窗口坐标与窗口坐标之间的转换: 

vtkNew<vtkCoordinate> coordinate;
coordinate->SetCoordinateSystemToNormalizedDisplay();
coordinate->SetValue(.5, .5, 0);	// 屏幕中心

int* val = coordinate->GetComputedDisplayValue(renderer);	// 窗口坐标转换

二、空间变换 

        在三维空间里定义的三维模型,最后显示时都是投影到二维平面,比如在屏幕上显示三维到二维的投影包括透视投影(PerspectiveProjection)和正交投影(Orthogonal Projection)。正交投影也叫平行投影。

        VTK里与空间变换有关的类有vtkTransform2D,vtkTransform,vtkPerspectiveTransform,vtkGeneralTransform,vtkTransformFilter,vtkMatrix4×4等。例如下面代码实现了vtkActor对象的空间变换: 

vtkNew<vtkTransform> transform;
transform->PostMultiply();	// 设置右乘计算变换矩阵。
transform->RotateZ(40);	//旋转
transform->Translate(10, 0, 0);	// 平移
cylinderActor->SetUserTransform(transform);

 三、VTK管线

        vtkProp、vtkAbstractMapper、vtkProperty、vtkCamera、vtkLight、vtkRenderer、vtkRendererWindow、vtkRenderWindowInteractor、vtkTransform、vtkLookupTable等等类都是与数据显示或渲染相关的,它们构成了VTK的渲染引擎(Rendering Engine)。渲染引擎主要负责数据的可视化表达,是VTK里的两个重要概念之一,而另一个重要概念就是可视化管线(Visualization Pipeline)

        可视化管线是指用于获取或创建数据、处理数据以及把数据写入文件或者把数据传递给渲染引擎进行显示,这样的一种结构在VTK里就称为可视化管线。数据对象(Data Object)、处理对象(Process Object)和数据流方向(Direction of Data Flow)是可视化管线的三个要素。每个VTK程序都会有可视化管线存在。

        Source是指用于创建数据(如vtkCylinderSource)或者读取数据(如vtkBMPReader、vtkStructuredPointsReader等)类的统称,即VTK的数据源。Source输出的数据作为Filter的输入,经Filter处理以后(可以经过多个Filter处理),生成新的数据。Filter的输出可以直接写入文件,或者经Mapper变换后传入渲染引擎进行渲染、显示,结束可视化管线。上图的箭头方向即为VTK里数据流流动的方向。

        可视化管线的三要素分别为数据对象、处理对象和数据流方向,Source、Filter和Mapper一起构成了处理对象,它们的区别是基于数据流的初始化、维持和终止。根据数据的生成方式,Source可以分为程序源对象(Procedural,如vtkCylinderSource,通过程序代码生成相关的数据)和读取源对象(Reader,如vtkBMPReader,从外部文件中导入数据)。

四、智能指针

   智能指针会自动管理引用计数的增加与减少。

c++中智能指针:

1:unique_ptr :这是一种独占式的智能指针;确保在其使用的生命周期内只有一个指针可以指向被

分配的对象;当其被销毁的时候,其管理的对象也被销毁。

2:share_ptr : 允许多个智能指针共享对同一资源的所有权。它使用引用计数来跟踪资源的引用次数,当最后一个std::shared_ptr离开作用域时,资源会被释放

3:weak_ptr:是为了配合share_ptr而引入的一种智能指针,它指向一个由shared_ptr管理的对象而不影响所指对象的生命周期,即就是将一个weak_ptr绑定到shared_ptr不会改变shared_ptr的引用计数。

        VTK中智能指针类为vtkSmartPointer。VTKSmartPointer是一个模板类,继承自VTKSmartPointerBase类。VTKSmartPointerBase中定义了一个vtkObjectBase类型的指针对象Object,用于存储智能指针中实际生成的对象。智能指针定义为:

vtkSmartPointer<vtkCamera> camera =  vtkSmartPointer<vtkCamera>::New();   //引用计数为1

        VTKSmartPointer中定义了静态函数New()来生成一个智能指针对象。该函数的核心在于:会根据模板参数类型来生成一个对象,并将其保存在基类VTKSmartPointerBase的成员变量Object中。

        VTKSmartPointer中重载了“->”操作符,返回实际模板参数类型的对象,因此可以方便地访问对象的成员函数,如camera->setFocusPosition(0,0,0)。

        VTKSmartPointer重载了“=”操作符,可以在VTKSmartPointer对象之间进行赋值。在赋值过程中,VTKSmartPointer会自动控制其内部对象指针Object的引用计数加1。

例如:

vktSmartPointer<vtkCamera> camera1 =vtkSmartPointer<vtkCamera>::New();
vtkSmartPointer<vtkCamera> camera2 = camera1;

        需要注意的是,此时camera1和camera2的引用计数都等于2。
        过程为:首先camera1的vtkCamera对象Object调用Register()函数,自动将引用计数加1,然后将camera2的Object指向camera1的Object对象。
        当一个智能指针对象的生命周期结束时,会自动调用其析构函数释放内存。在析构函数中会调用其内部对象Object的UnRegister()函数修改引用计数。如果此时的引用计数为0,Object对象会自动释放内存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值