先看下面的模型,這是一個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),坐標軸向量長度為1個單位]
場景一:矩陣的順序問題
我們要對圖1中位於世界坐標系原點的圓錐體做如下操作:
1. 圓錐體在X軸正方向上移動1個單位
2.繞Z軸旋轉
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);

試着改變一下1, 2兩步的順序:

對比來看,是兩個不同的結果。而這個結果正是因為矩陣乘法並不滿足交換定律。
因此,在使用時,進行變換的順序非常重要,將對結果產生直接的影響。
對於變換矩陣,VTK是用以下順序來應用這些變化的:
![]()
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);

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

從兩個結果可以看出,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 }
