VTK 动画:框架、流程与实现

本文详细介绍了VTK库中的动画功能,包括vtkAnimationCue和vtkAnimationScene类的原理、关键方法以及一个简单的VTK动画实例,展示了如何创建和控制动画效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


VTK是一个非常强大的图形处理库,它不仅可以用于科学计算和可视化,还可以用于创建各种有趣的动画。

VTK 动画:框架、流程与实现

参考:https://www.bilibili.com/video/BV1wM411K7wV

vtkAnimationCue 和 vtkAnimationScene 简介

VTK提供了一个由vtkAnimationCue和vtkAnimationScene等类所组成的框架,支持动画场景的创建和回放。

在这里插入图片描述

vtkAnimationScene表示一个场景或者是动画场景的建立。动画场景通常是通过渲染一系列的帧,在渲染每一帧时改变某些可视化参数来建立的。所渲染的每一帧都关联一个动画时间,这个时间用来确定动画中每一帧的位置。基于不同的播放模式,动画时间在动画播放过程中是一个计数不断添加的简单变量。

vtkAnimationCue代表一个随时间变化/动画的实体。vtkAnimationCue实例本身并不知道与动画相关的参数是假设改变的。因此,用户必须从vtkAnimationCue中派生出子类或者使用观察者模式监听事件。来改变动画过程中须要改变的参数。

动画场景中的Cue实体都有一个开始时间(start-time)和结束时间(end-time)。动画回放时,当场景的动画时间是处于所指定的开始时间与结束时间的范围内时,Cue实体就会被激活。Cue实体一旦激活后,它本身会发出vtkCommand::StartAnimationCueEvent事件。而对于动画系列中的每一帧。则发出vtkCommand::AnimationCueTickEvent事件,当动画时间递增至Cue实体的结束时间时,会发出vtkCommand::EndAnimationCueEvent事件。

vtkAnimationScene 类的重要方法

下面列出了类vtkAnimationScene中一些比较重要的方法:

  1. SetStartTime()/SetEndTime():设置动画场景的开始时间和结束时间,它们就是动画回放时的时间范围。
  2. SetPlayMode():用于控制动画回放的模式,也就是动画时间是怎样改变的。有两种模式能够设置:
    • SequenceMode(PLAYMODE_SEQUENCE):这样的模式下,每帧的动画时间添加(1/framerate)的间隔。直至达到所设置的EndTime。因此。所渲染的总帧数是固定的,与渲染每一帧时所用的时间的长短无关。
    • RealTimeMode(PLAYMODE_REALTIME):这样的模式下,整个动画的执行时间大约是(EndTime-StartTime)秒,当中第n帧的执行时间是:第n-1帧的执行时间+渲染第n-1帧所用的时间。因此。所渲染的总帧数随着渲染每一帧所用时间的不同而不同。
  3. SetFrameRate():帧率是指单位时间内渲染的帧数。主要用于Sequence模式。
  4. AddCue():将一个vtkAnimationCue实例加入到场景中。
  5. RemoveCue():从场景中移除vtkAnimationCue实例。
  6. RemoveAllCue():从场景中移除所有的vtkAnimationCue实例。
  7. SetAnimationTime():指定某一帧的动画时间。
  8. GetAnimationTime():动画回放时,获取动画的时钟时间。
  9. SetLoop():设为true,动画循环播放。
  10. Play()/Stop():开始/结束动画。

vtkAnimationCue 类的重要方法

下面是vtkAnimationCue类中一些比较重要的方法:

  1. SetTimeMode():TimeMode定义了Cue实体的起始时间和结束时间是怎样指定的,有两种模式可选。
    • Relative(TIMEMODE_RELATIVE):这样的模式下,动画场景中的Cue实体的时间是相对动画场景的开始时间来指定的。
    • Normalized(TIMEMODE_NORMALIZED):这样的模式下,Cue实体的开始时间和结束时间的取值范围为[0, 1],其中0对应动画场景的开始,1对应结束。
  2. SetStartTime()/SetEndTime():这两个方法主要是当Cue实体被激活时,标识动画时间的范围。
    • 当TimeMode取值为TIMEMODE_RELATIVE时,与动画场景的开始和结束时间有同样的单位。
    • 当TimeMode取值为TIMEMODE_NORMALIZED时,Cue实体的开始时间和结束时间的取值范围为[0, 1],其中0对应动画场景的开始,1对应结束。
  3. GetAnimationTime():用于vtkCommand::AnimationCueTickEvent事件的处理。处理事件时。可用来确定动画场景中的当前帧。其值依赖于TimeMode。
    • 当TimeMode取值为TIMEMODE_RELATIVE时,其值是Cue实体激活后的时间单位的倍数。
    • 当TimeMode取值为TIMEMODE_NORMALIZED时,Cue实体的开始时间和结束时间的取值范围为[0, 1],其中0对应动画场景的开始,1对应结束。
  4. GetClockTime():该方法与vtkAnimationScene::GetAnimationTime()中的动画时钟时间相似,仅当处理vtkCommand::AnimationCueTickEvent事件时才有效。
  5. TickInternal (double currenttime, double deltatime, double clocktime):正如前面所提的。我们能够派生一个vtkAnimationCue子类来取代编写处理动画事件的函数。子类派生时,必须要重载该函数。当中该函数的参数分别相应GetAnimationTime(),GetDeltaTime()和GetClockTime()的返回值。
  6. StartCueInternal()/EndCueInternal():这两个方法可在子类中重载,主要做一些创建、清除等工作以及动画回放时控制Cue实体的开始和结束。用户也能够加入事件观察者,通过监听vtkCommand::StartAnimationCueEvent和vtkCommand::EndAnimationCueEvent事件来实现相似的功能。

VTK 动画的基本流程

  1. 公有继承 vtkAnimationCue 实现一个自己的 vtkAnimationCue 子类,实现动画功能
  2. 创建一个 vtkAnimationScene 渲染场景
  3. 创建一个或多个 vtkAnimationCue 自定义子类实例,对于类中需要操作的对象进行赋值
  4. 添加动画实例到动画场景中:scene->AddCue(cue)
  5. 开始动画:scene->Play()
  6. 结束动画:scene->Stop()

实例:一个简单的 VTK 动画演示程序

VTK 对象都是通过内部定义静态函数 New() 来生成,用 Delete() 方法删除,因此构造函数、析构函数都要定义为 protected 类型,而对与赋值运算符和拷贝构造函数定义为 private 类型,只做声明不用实现。

两个宏:

vtkTypeMacro 是 VTK 的一个父子继承类型宏,用来追踪父子关系。借助该宏,不需要重新实现 vtkAnimationCue 的基本函数(虚函数)。

vtkStandardNewMacro 是 VTK 的一个宏,作用是定义一个通用的 New() 函数,使用时需要将实际的类名传递给它,确保你创建的对象是实际类的实例,而不是基类的实例。

完整程序:

#include <vtkSmartPointer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkSphereSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkProperty.h>

#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);

#include <vtkAnimationScene.h>
#include <vtkAnimationCue.h>

class vtkCustomAnimationCue : public vtkAnimationCue
{
protected:
	vtkCustomAnimationCue() : RenWin(nullptr), Sphere(nullptr) {}
	virtual void TickInternal(double currenttime, double deltatime, double clocktime)
	{
		double new_st = currenttime * 180;
		this->Sphere->SetStartTheta(new_st);
		this->RenWin->Render();
	}

public:
	static vtkCustomAnimationCue* New();
	vtkTypeMacro(vtkCustomAnimationCue, vtkAnimationCue);
	vtkRenderWindow* RenWin;
	vtkSphereSource* Sphere;
};
vtkStandardNewMacro(vtkCustomAnimationCue);

int main()
{
	// 新建一个 Source 数据源对象
	vtkSmartPointer<vtkSphereSource> sphere = nullptr;
	sphere = vtkSmartPointer<vtkSphereSource>::New();
	// 设置属性
	sphere->SetPhiResolution(30); // 设置纬度方向上的点数,默认值为 8
	sphere->SetThetaResolution(30); // 设置经度方向上的点数,默认值为 8
	// 新建一个 Mapper 映射器对象
	vtkSmartPointer<vtkPolyDataMapper> sphereMapper = nullptr;
	sphereMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
	// 接受 cylinder 的输出,将数据映射为几何元素
	sphereMapper->SetInputConnection(sphere->GetOutputPort());
	// 新建一个 Actor 演示对象
	vtkSmartPointer<vtkActor> sphereActor = nullptr;
	sphereActor = vtkSmartPointer<vtkActor>::New();
	// vtkActor 派生自 vtkProp 类,渲染场景中数据的可视化表达是通过 vtkProp 的子类负责的
	// vtkProp 子类负责确定渲染场景中对象的位置、大小和方向信息
	sphereActor->SetMapper(sphereMapper);
	sphereActor->GetProperty()->SetColor(0.0, 0.0, 1.0);
	// 创建一个 Renderer 渲染器对象,负责管理场景的渲染过程
	vtkSmartPointer<vtkRenderer> renderer = nullptr;
	renderer = vtkSmartPointer<vtkRenderer>::New();
	// 添加 vtkProp 类型的对象到渲染场景中
	renderer->AddActor(sphereActor);
	// 设置渲染场景的背景颜色
	renderer->SetBackground(1.0, 1.0, 1.0); // R、G、B,全 0 为黑色,全 1 为白色
	// 创建一个 Window 窗口对象,负责本地计算机系统中窗口创建和渲染过程管理
	vtkSmartPointer<vtkRenderWindow> window = nullptr;
	window = vtkSmartPointer<vtkRenderWindow>::New();
	window->AddRenderer(renderer);
	window->SetSize(640, 480); // 设置窗口大小
	window->Render();
	window->SetWindowName("Sphere");

	/*
	// 新建一个 Interactor 交互器对象,提供平台独立的响应鼠标、键盘和时钟事件的交互机制
	vtkSmartPointer<vtkRenderWindowInteractor> interactor = nullptr;
	interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
	// 设置渲染窗口,消息是通过渲染窗口捕获到的,所以必须要给交互器对象设置渲染窗口
	interactor->SetRenderWindow(window);
	// 新建一个交互器样式对象,该样式下,用户通过控制相机对物体作旋转、放大、缩小等操作
	vtkSmartPointer<vtkInteractorStyleTrackballCamera> style = nullptr;
	style = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
	// 定义交互器样式,默认的交互样式为 vtkInteractorStyleSwitch
	interactor->SetInteractorStyle(style);

	interactor->Initialize();
	interactor->Start();
	*/

	vtkAnimationScene* scene = vtkAnimationScene::New(); // 创建动画场景
	//scene->SetModeToRealTime(); // 设置实时播放模式
	scene->SetModeToSequence(); // 设置顺序播放模式
	scene->SetFrameRate(30); // 设置帧率,单位时间内渲染的帧数
	scene->SetStartTime(0); // 动画开始时间
	scene->SetEndTime(60); // 动画结束时间

	vtkCustomAnimationCue* cue = vtkCustomAnimationCue::New(); // 创建动画实例
	// 对于类中需要操作的对象进行赋值
	cue->Sphere = sphere;
	cue->RenWin = window;
	cue->SetTimeModeToNormalized(); // 按照场景时间标准化实例的动画时间,0 对应动画场景的开始,1 对应结束
	cue->SetStartTime(.0);
	cue->SetEndTime(1.0);

	scene->AddCue(cue); // 添加动画实例到动画场景中
	//scene->SetLoop(1); // 设置循环播放模式
	scene->Play(); // 动画场景开始播放
	scene->Stop(); // 结束播放

	// 使用了智能指针,不需要手动释放内存
	//style->Delete();
	//interactor->Delete();
	//window->Delete();
	//renderer->Delete();
	//cylinderActor->Delete();
	//cylinderMapper->Delete();
	//cylinder->Delete();
	scene->Delete();
	cue->Delete();

	return EXIT_SUCCESS;
}

运行结果:

球的开口从0增大到180度,动画结束。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UestcXiye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值