揭開 matrix4的神秘面紗,並充分利用轉換小部件的能力
本文首次發表在codemagic.io!
Codemagic為Flutter和移動應用程序項目提供持續集成和持續交付。Developed by Nevercode。
Transform 組件是 Flutter 目錄中最強大的小部件之一(對我來說,也是最被低估的)。Transform 允許我們從根本上改變組件的外觀和行為,允許我們創建新的、復雜的動畫類型。在 Transform 組件下面,在 Transform 組件下,一個4D矩陣為實際的轉換提供動力——由 Matrix4 類定義。雖然 Flutter 已經提供了一些簡單的轉換方法,比如平移、縮放和旋轉,但是我們可以使用 Matrix4 來創建更棒的東西,比如3d 透視轉換。
在這篇文章中,我們將探索4D矩陣本身以及其中的個體值是做什么的。在我之前寫的 Transform Deep Dive 中,我們討論了如何在不直接與4D矩陣交互的情況下使用 Transform。如果你需要復習一下這個小部件的簡單使用方法,可以查看一下。
什么是4D 矩陣?
盡管任何帶有“4D”的東西在默認情況下聽起來都很酷,但實際上,4D 矩陣只是一個4行4列的矩陣。我們需要使用一個4d 矩陣來轉換一個物體的三維(在這里,維度是我們習慣的:長度、寬度和高度)。
這種矩陣的形成稱為單位矩陣。想象一個單位矩陣的最佳方式是,它等價於矩陣形式中的數字“1”——用於轉換窗口小部件時,它不會改變任何東西。
在這個矩陣中使用不同的數字組合,我們可以操縱給定對象的形狀、大小、方向等。
讓我們來看看我們是如何做到的。
基本設置
讓我們來看看我們將要用於實驗的代碼:
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
double x = 0;
double y = 0;
double z = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Transform(
transform: Matrix4(
1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1,
)..rotateX(x)..rotateY(y)..rotateZ(z),
alignment: FractionalOffset.center,
child: GestureDetector(
onPanUpdate: (details) {
setState(() {
y = y - details.delta.dx / 100;
x = x + details.delta.dy / 100;
});
},
child: Container(
color: Colors.red,
height: 200.0,
width: 200.0,
),
),
),
),
);
}
}
代碼只是使用 Transform 組件和彩色 Container 進行轉換。我們為起點定義了一個恆等矩陣,它確實……嗯……什么作用都沒有。使用 Gestuedector 的部分允許我們以 x 和 y 的方向旋轉正方形。如果你需要更多關於我們正在做什么的信息,我建議你看看 Wm Leler 的文章《Flutter透視》,其中一個類似的方法是使用x、 y 和 z 變量來跟蹤已經完成的旋轉量。
稍后我們將回到為什么我們允許用戶旋轉正方形的問題。現在,我們專注於矩陣和基本的2D結果。
*注一:
**alignment: FractionalOffset.center**
將轉換的中心點設置為正方形的中心。注 2(對於書呆子):Matrix4 默認以列優先順序排列。 在編寫代碼的方式上,我們有效地以行優先格式編寫它。 因此,寫入的所有行和列值都將沿對角線反轉。
下面是現在屏幕的樣子:
我們在那里有一個非常有趣的方形。 讓我們看看我們是否可以用它做點什么。
使用矩陣進行縮放
讓我們嘗試在 x、y、z 方向上單獨縮放(擴展/收縮)這個正方形,然后再一起縮放。
X軸的縮放
若要在 x 方向(水平方向)縮放一個對象,請根據所需的縮放因子更改矩陣的(0, 0)值。
讓我們試着這樣做,當比例因子為1.5時,我們的正方形變成:
transform: Matrix4(
1.5, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
)..rotateX(x)..rotateY(y)..rotateZ(z),
Y軸的縮放
若要沿 y 方向(垂直)縮放對象,請根據所需的縮放因子更改矩陣的(0, 0)值。
讓我們試着這樣做,當比例因子為1.5時,我們的正方形變成:
transform: Matrix4(
1, 0, 0, 0,
0, 1.5, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
)..rotateX(x)..rotateY(y)..rotateZ(z),
在z軸中縮放呢?
理論上,該值(2, 2)將沿 z 方向擴展,並具有類似的矩陣。
因為這並不適用於我們的2D方形,我們就讓它過吧。
向各個方向擴展
一種向所有方向縮放的方法是將上述方法結合起來,並使用它來均勻縮放我們的正方形。然而,我們也可以使用另一種方法:
我們可以用1除以我們想要使用的比例因子來代替位置(3, 3)。所以如果我們想讓這個正方形增大兩倍,我們會用1/2,也就是0.5。
下面是使用在(3, 3)處使用0.5的正方形:
transform: Matrix4(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1.5,
)..rotateX(x)..rotateY(y)..rotateZ(z),
使用矩陣進行轉換
為了在 x、y 或 z 方向中轉換,我們可以很容易地改變底部 x、y 和 z 三個的值。
重要提示: 上面給出的矩陣表示代碼中的矩陣。由於實際的 matrix4采用列主格式,因此 x、 y 和 z 分別為(0, 3)、(1, 3)和(2, 3)。
讓我們以 x 的值等於75為例:
transform: Matrix4(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
75, 0, 0, 1,
)..rotateX(x)..rotateY(y)..rotateZ(z),
使用矩陣旋轉
生活中所有的事情都不容易——因此,就像用矩陣縮放和平移物體一樣簡單,旋轉也不是一件容易記住的事情,而且你可能會在數學期末考試中搞砸。
圍繞 x 軸旋轉:
圍繞 y 軸旋轉:
圍繞 z 軸旋轉:
這可能正好解釋了為什么在開始的代碼中我們有:
..rotateX(x)..rotateY(y)..rotateZ(z)
而不是手動實現角度和進一步的矩陣乘法。
透視變換
透視變換修改軸上位置的長度。最常見的用途是給用戶一種深度感ーー就像你站的地方鐵軌看起來很寬,但是當你看得更遠時,它們就會變得越來越短。在這種情況下,靠近我們的那一邊應該看起來更大,而遠離我們的那一邊應該看起來更小。
當正方形旋轉時,沒有深度感。我們可以使用透視變換來解決這個問題。要啟用 z 方向的深度知覺,我們需要在代碼中的矩陣中設置這個值。
你可能已經看到其他教程使用這一行:
..setEntry(3, 2, 0.001)
當物體遠離時,它們的長度減少,當物體靠近時,它們的長度增加。
讓我們把 z 值設置為0.002,看看我們的正方形會發生什么。
double z = 0.002;
我們現在可以看到差異,近的一面變大,遠的一面變小。較高的值會給出較高的長度梯度的距離。
但是... 不是這樣的
如果您注意到本文中所有軸的對稱主題,則可能會思考“Z軸的深度感知值的兩個值呢”?
與 z 軸類似,其他兩個值也以相同的方式工作。
設置這個值可以讓我們感知沿着 x 軸的距離,就像我們感知 z 軸一樣。雖然這不一定是相同的效果,但這在理論上仍然與上面所做的透視圖轉換相同。
在這里,當 x 軸的位置增加時,邊的長度減少,大概是這樣:
類似地,y 軸:
計算機圖形學中的原點在左上角,因此,Y的位置隨着向下移動而增加。因此,長度會隨着Y值的減小而減小。