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

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

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

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

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

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

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

[图1 圆锥体位于(0,0,0),坐标轴向量长度为1个单位]

场景一:矩阵的顺序问题

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

1. 圆锥体在X轴正方向上移动1个单位

2.绕Z轴旋转VTK 空间几何变换(Transform),平移、旋转和缩放

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

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

试着改变一下1, 2两步的顺序:

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

对比来看,是两个不同的结果。而这个结果正是因为矩阵乘法并不满足交换定律。

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

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

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

1. 移动actor到它的origin,缩放和旋转都是基于这个点完成的。

2. 缩放几何体。

3.actor依次绕Y, X和Z轴旋转。

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

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

场景二:GetMatrix和GetUserMatrix的区别

Code1:

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

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

Code2:

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

 

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

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

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

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

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

完整示例代码

  1 #include <vtkLineSource.h>
  2 #include <vtkPolyData.h>
  3 #include <vtkSmartPointer.h>
  4 #include <vtkPolyDataMapper.h>
  5 #include <vtkActor.h>
  6 #include <vtkRenderWindow.h>
  7 #include <vtkRenderer.h>
  8 #include <vtkRenderWindowInteractor.h>
  9 #include <vtkProperty.h>
 10 #include <vtkAxesActor.h>
 11 #include <vtkConeSource.h>
 12 #include <vtkTextActor.h>
 13 #include <vtkTextProperty.h>
 14 #include <vtkTransform.h>
 15 #include <vtkSphereSource.h>
 16  
 17 int main(int, char *[])
 18 {
 19     vtkSmartPointer<vtkSphereSource> sphereSource =
 20         vtkSmartPointer<vtkSphereSource>::New();
 21     sphereSource->SetRadius(0.1);
 22     sphereSource->Update();
 23  
 24     vtkSmartPointer<vtkPolyDataMapper> sphereMapper =
 25         vtkSmartPointer<vtkPolyDataMapper>::New();
 26     sphereMapper->SetInputConnection(sphereSource->GetOutputPort());
 27  
 28     vtkSmartPointer<vtkActor> sphereActor =
 29         vtkSmartPointer<vtkActor>::New();
 30     sphereActor->SetPosition(0, 0, 0);
 31     sphereActor->SetMapper(sphereMapper);
 32     sphereActor->GetProperty()->SetColor(1, 0, 0);
 33  
 34     vtkSmartPointer<vtkConeSource> coneSource =
 35         vtkSmartPointer<vtkConeSource>::New();
 36     coneSource->SetRadius(.2);
 37     coneSource->SetHeight(.5);
 38     coneSource->SetCenter(0, 0, 0);
 39     vtkSmartPointer<vtkPolyDataMapper> coneMapper =
 40         vtkSmartPointer<vtkPolyDataMapper>::New();
 41     coneMapper->SetInputConnection(coneSource->GetOutputPort());
 42     vtkSmartPointer<vtkActor> coneActor =
 43         vtkSmartPointer<vtkActor>::New();
 44     coneActor->SetMapper(coneMapper);
 45  
 46     vtkSmartPointer<vtkActor> oriConeActor =
 47         vtkSmartPointer<vtkActor>::New();
 48     oriConeActor->SetMapper(coneMapper);
 49 #define AXIS_LEN 1.
 50     vtkSmartPointer<vtkAxesActor> oriAxesActor =
 51         vtkSmartPointer<vtkAxesActor>::New();
 52     oriAxesActor->SetPosition(0, 0, 0);
 53     oriAxesActor->SetTotalLength(AXIS_LEN, AXIS_LEN, AXIS_LEN);
 54     oriAxesActor->SetShaftType(0);
 55     oriAxesActor->SetAxisLabels(0);
 56     oriAxesActor->SetCylinderRadius(0.02);
 57  
 58     vtkSmartPointer<vtkAxesActor> axesActor =
 59         vtkSmartPointer<vtkAxesActor>::New();
 60     axesActor->SetPosition(0, 0, 0);
 61     axesActor->SetTotalLength(AXIS_LEN, AXIS_LEN, AXIS_LEN);
 62     axesActor->SetShaftType(0);
 63     axesActor->SetAxisLabels(0);
 64     axesActor->SetCylinderRadius(0.02);
 65  
 66     vtkSmartPointer<vtkTextActor> textActor = 
 67         vtkSmartPointer<vtkTextActor>::New();
 68     textActor->SetPosition2(100, 40);
 69     textActor->GetTextProperty()->SetFontSize(24);
 70     textActor->GetTextProperty()->SetColor(1, 0, 0);
 71  
 72  
 73     vtkSmartPointer<vtkTransform> trans = 
 74         vtkSmartPointer<vtkTransform>::New();
 75  
 76 #if 0
 77     trans->PostMultiply();
 78  
 79     coneActor->SetPosition(1, 0, 0);
 80     //trans->Translate(1, 0, 0);
 81     //trans->RotateZ(45);
 82     trans->RotateZ(45);
 83     trans->Translate(1, 0, 0);
 84     coneActor->SetUserTransform(trans);
 85     //textActor->SetInput("PostMultiply()\nTranslate(1, 0, 0)\nRotateZ(45)");
 86     textActor->SetInput("PostMultiply()\nRotateZ(45)\nTranslate(1, 0, 0)");
 87 #endif
 88  
 89 #if 1
 90     //coneActor->RotateZ(45);
 91     //coneActor->SetPosition(1, 0, 0);
 92     //textActor->SetInput("coneActor->RotateZ(45)\nconeActor->SetPosition(1, 0, 0)");
 93  
 94     trans->RotateZ(45);
 95     trans->Translate(1, 0, 0);
 96     coneActor->SetUserTransform(trans);
 97     textActor->SetInput("trans->RotateZ(45)\ntrans->Translate(1, 0, 0)\nconeActor->SetUserTransform(trans)");
 98  
 99     cout << "GetMatrix:" << endl;
100     if (coneActor->GetMatrix()!=NULL)
101     {
102         coneActor->GetMatrix()->Print(cout);
103     }
104     else
105     {
106         cout << "NULL" << endl;
107     }
108     cout << "GetUserMatrix:" << endl;
109     if (coneActor->GetUserMatrix() !=NULL)
110     {
111         coneActor->GetUserMatrix()->Print(cout);
112     }
113     else
114     {
115         cout << "NULL" << endl;
116     }
117     //cout << "GetUserTransform:" << endl;
118     //if (coneActor->GetUserTransform() !=NULL)
119     //{
120     //    coneActor->GetUserTransform()->Print(cout);
121     //}
122     //else
123     //{
124     //    cout << "NULL" << endl;
125     //}
126 #endif
127     vtkSmartPointer<vtkRenderer> renderer1 =
128         vtkSmartPointer<vtkRenderer>::New();
129     vtkSmartPointer<vtkRenderer> renderer2 =
130         vtkSmartPointer<vtkRenderer>::New();
131  
132     vtkSmartPointer<vtkRenderWindow> renderWindow =
133         vtkSmartPointer<vtkRenderWindow>::New();
134     renderWindow->SetSize(800, 400);
135     renderWindow->AddRenderer(renderer1);
136     renderWindow->AddRenderer(renderer2);
137     vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
138         vtkSmartPointer<vtkRenderWindowInteractor>::New();
139     renderWindowInteractor->SetRenderWindow(renderWindow);
140  
141     double leftViewport[] = { 0.0, 0.0, 0.5, 1.0 };
142     double rightViewport[] = { 0.5, 0.0, 1.0, 1.0 };
143  
144     renderer1->AddActor(oriAxesActor);
145     renderer1->AddActor(sphereActor);
146     renderer1->AddActor(oriConeActor);
147     renderer2->AddActor(axesActor);
148     renderer2->AddActor(sphereActor);
149     renderer2->AddActor(coneActor);
150     renderer2->AddActor2D(textActor);
151     renderer1->SetBackground(.3, .3, .5);
152     renderer2->SetBackground(.2, .4, .5);
153     renderer1->SetViewport(leftViewport);
154     renderer2->SetViewport(rightViewport);
155  
156     renderWindow->Render();
157     renderWindowInteractor->Start();
158  
159     return EXIT_SUCCESS;
160 }

 

上一篇:浅尝Unity ECS的笔记 2020 System and Component(三)


下一篇:将region用一个等效的形状替代,并求出相应的尺寸