VTK笔记——空间几何变换(Transform),平移、旋转和缩放

先看下面的模型,这是一个Cow的三维模型,

在使用中,你是否会有下面的操作?

1.将Cow移动到某个位置——平移

2.转动到Cow背面——旋转

3.改变它大小——缩放

等等

可能你会说,这还不简单,通过操作相机就好了。然而并不是这样,操作相机,只使得相机的空间位置发生了变化,对三维物体并没有改变,要想改变模型,就需要对模形本身做空间变换

空间变换的基础知识

变换矩阵(Transformation Matrices)

我们都知道,在屏幕上显示的是二维的图形,三维图形都是投影到二维平面的,但它们定义在三维空间的。空间变换的基本元素都是三维坐标点,在计算机图形学中,三维坐标点用齐次坐标表示。利用齐次坐标,可以将空间变换用4x4的矩阵来表示。这些变换最终都是由矩阵的运算完成。

VTK有关空间变换的类和方法

VTK相关的类有:

vtkTransform, vtkTransformFilter, vtkMatrix4x4

相关的方法有:

• RotateX(angle)、RotateY(angle)、RotateZ(angle)

• RotateWXYZ(angle,x,y,z)

• Scale(x,y,z)

• Translate(x,y,z)

• SetMatrix(m)、GetMatrix(m)

• PostMultiply()、PreMultiply()

• SetPosition(x,y,z)、GetPosition(x,y,z)

• SetOrientation(x,y,z)、 GetOrientation(x,y,z)

• SetScale(sx,sy,sz)

• SetOrigin(x,y,z)、GetOrigin

下面通过几个场景来看看上面的一些类和方法是如何使用以及一些常见的问题。

[图1 圆锥体位于(0,0,0),坐标轴x, y, z分别用红、绿、蓝表示,向量长度为1个单位]

场景一:矩阵的顺序问题

我们要对图1中位于世界坐标系原点的圆锥体做如下操作:

1. 圆锥体在X轴(图中红色轴)正方向上移动1个单位

2.绕Z(图中蓝色轴)轴旋转45^{\circ}

vtkSmartPointer<vtkTransform> trans = 
	vtkSmartPointer<vtkTransform>::New();
trans->PostMultiply();
trans->Translate(1, 0, 0);
trans->RotateZ(45);
coneActor->SetUserTransform(trans);

试着改变一下1, 2两步的顺序,结果又将如何?

对比来看,结果却不相同,然而这个结果并没什么奥妙,只因为矩阵乘法不满足交换律。

因此,在使用时,进行变换的顺序非常重要,将对结果产生直接的影响。

对于变换矩阵,VTK是用以下顺序来应用这些变化的:

1. 移动几何物体到它的原点,缩放和旋转都是基于这个点完成的。

2. 缩放几何物体。

3.几何物体依次绕Y, X和Z轴旋转。

4.从旋转中心移回到原来的位置后再移动几何物体到最终的位置。

在VTK中,矩阵乘法默认是左乘,即PreMultiply,上面的公式也遵循这个原则。为了便于理解,示例代码特地使用了右乘PostMultiply.

场景二:GetMatrix和GetUserMatrix的区别

Code1:

coneActor->RotateZ(45);
coneActor->SetPosition(1, 0, 0);

Code2:

trans->RotateZ(45);
trans->Translate(1, 0, 0);
coneActor->SetUserTransform(trans);

从两个结果可以看出,GetMatixGetUserMatrix都是获取变换矩阵。所不同的是:

GetMatrix始终都可以获取到值,也就是说它得到的是圆锥体在世界坐标系的变换矩阵

GetUserMatrix在Code2中获取到了值,而在Code1中得到是NULL,这说明它获取的是用户设置的变换矩阵

注:GetUserMatrix、SetUserMatrix和GetUserTransform、SetUserTransform具有相同的作用。

完整示例代码

#include <vtkLineSource.h>
#include <vtkPolyData.h>
#include <vtkSmartPointer.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
#include <vtkAxesActor.h>
#include <vtkConeSource.h>
#include <vtkTextActor.h>
#include <vtkTextProperty.h>
#include <vtkTransform.h>
#include <vtkSphereSource.h>

int main(int, char *[])
{
	vtkSmartPointer<vtkSphereSource> sphereSource =
		vtkSmartPointer<vtkSphereSource>::New();
	sphereSource->SetRadius(0.1);
	sphereSource->Update();

	vtkSmartPointer<vtkPolyDataMapper> sphereMapper =
		vtkSmartPointer<vtkPolyDataMapper>::New();
	sphereMapper->SetInputConnection(sphereSource->GetOutputPort());

	vtkSmartPointer<vtkActor> sphereActor =
		vtkSmartPointer<vtkActor>::New();
	sphereActor->SetPosition(0, 0, 0);
	sphereActor->SetMapper(sphereMapper);
	sphereActor->GetProperty()->SetColor(1, 0, 0);

	vtkSmartPointer<vtkConeSource> coneSource =
		vtkSmartPointer<vtkConeSource>::New();
	coneSource->SetRadius(.2);
	coneSource->SetHeight(.5);
	coneSource->SetCenter(0, 0, 0);
	vtkSmartPointer<vtkPolyDataMapper> coneMapper =
		vtkSmartPointer<vtkPolyDataMapper>::New();
	coneMapper->SetInputConnection(coneSource->GetOutputPort());
	vtkSmartPointer<vtkActor> coneActor =
		vtkSmartPointer<vtkActor>::New();
	coneActor->SetMapper(coneMapper);

	vtkSmartPointer<vtkActor> oriConeActor =
		vtkSmartPointer<vtkActor>::New();
	oriConeActor->SetMapper(coneMapper);
#define AXIS_LEN 1.
	vtkSmartPointer<vtkAxesActor> oriAxesActor =
		vtkSmartPointer<vtkAxesActor>::New();
	oriAxesActor->SetPosition(0, 0, 0);
	oriAxesActor->SetTotalLength(AXIS_LEN, AXIS_LEN, AXIS_LEN);
	oriAxesActor->SetShaftType(0);
	oriAxesActor->SetAxisLabels(0);
	oriAxesActor->SetCylinderRadius(0.02);

	vtkSmartPointer<vtkAxesActor> axesActor =
		vtkSmartPointer<vtkAxesActor>::New();
	axesActor->SetPosition(0, 0, 0);
	axesActor->SetTotalLength(AXIS_LEN, AXIS_LEN, AXIS_LEN);
	axesActor->SetShaftType(0);
	axesActor->SetAxisLabels(0);
	axesActor->SetCylinderRadius(0.02);

	vtkSmartPointer<vtkTextActor> textActor = 
		vtkSmartPointer<vtkTextActor>::New();
	textActor->SetPosition2(100, 40);
	textActor->GetTextProperty()->SetFontSize(24);
	textActor->GetTextProperty()->SetColor(1, 0, 0);


	vtkSmartPointer<vtkTransform> trans = 
		vtkSmartPointer<vtkTransform>::New();

#if 0
	trans->PostMultiply();

	coneActor->SetPosition(1, 0, 0);
	//trans->Translate(1, 0, 0);
	//trans->RotateZ(45);
	trans->RotateZ(45);
	trans->Translate(1, 0, 0);
	coneActor->SetUserTransform(trans);
	//textActor->SetInput("PostMultiply()\nTranslate(1, 0, 0)\nRotateZ(45)");
	textActor->SetInput("PostMultiply()\nRotateZ(45)\nTranslate(1, 0, 0)");
#endif

#if 1
	//coneActor->RotateZ(45);
	//coneActor->SetPosition(1, 0, 0);
	//textActor->SetInput("coneActor->RotateZ(45)\nconeActor->SetPosition(1, 0, 0)");

	trans->RotateZ(45);
	trans->Translate(1, 0, 0);
	coneActor->SetUserTransform(trans);
	textActor->SetInput("trans->RotateZ(45)\ntrans->Translate(1, 0, 0)\nconeActor->SetUserTransform(trans)");

	cout << "GetMatrix:" << endl;
	if (coneActor->GetMatrix()!=NULL)
	{
		coneActor->GetMatrix()->Print(cout);
	}
	else
	{
		cout << "NULL" << endl;
	}
	cout << "GetUserMatrix:" << endl;
	if (coneActor->GetUserMatrix() !=NULL)
	{
		coneActor->GetUserMatrix()->Print(cout);
	}
	else
	{
		cout << "NULL" << endl;
	}
	//cout << "GetUserTransform:" << endl;
	//if (coneActor->GetUserTransform() !=NULL)
	//{
	//	coneActor->GetUserTransform()->Print(cout);
	//}
	//else
	//{
	//	cout << "NULL" << endl;
	//}
#endif
	vtkSmartPointer<vtkRenderer> renderer1 =
		vtkSmartPointer<vtkRenderer>::New();
	vtkSmartPointer<vtkRenderer> renderer2 =
		vtkSmartPointer<vtkRenderer>::New();

	vtkSmartPointer<vtkRenderWindow> renderWindow =
		vtkSmartPointer<vtkRenderWindow>::New();
	renderWindow->SetSize(800, 400);
	renderWindow->AddRenderer(renderer1);
	renderWindow->AddRenderer(renderer2);
	vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	renderWindowInteractor->SetRenderWindow(renderWindow);

	double leftViewport[] = { 0.0, 0.0, 0.5, 1.0 };
	double rightViewport[] = { 0.5, 0.0, 1.0, 1.0 };

	renderer1->AddActor(oriAxesActor);
	renderer1->AddActor(sphereActor);
	renderer1->AddActor(oriConeActor);
	renderer2->AddActor(axesActor);
	renderer2->AddActor(sphereActor);
	renderer2->AddActor(coneActor);
	renderer2->AddActor2D(textActor);
	renderer1->SetBackground(.3, .3, .5);
	renderer2->SetBackground(.2, .4, .5);
	renderer1->SetViewport(leftViewport);
	renderer2->SetViewport(rightViewport);

	renderWindow->Render();
	renderWindowInteractor->Start();

	return EXIT_SUCCESS;
}

Reference

VTK中模型的旋转与平移

三维空间几何变换原理[平移、旋转、错切]

  • 19
    点赞
  • 116
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值