(翻譯) Efficiency Tips on Switching Spaces and Transformation Matrices in Unity
原文
https://blog.lidia-martinez.com/efficiency-tips-spaces-and-transformation-matrices-unity
Should I care which method I use to switch spaces?
This only matters truly if you are worried about efficiency and garbage collection. This means that it depends on what operation you perform and how many times. Othewise, it doesn't matter, but it is good to always choose the proper one beforehand in case you end up making it grow.
你是否需要在切換空間(spaces)的方法上下功夫?
只有當你關注效率和垃圾回收時,這才是真正關鍵的。這取決于你正在執行的操作類型以及操作的頻率。否則,這并不重要。但最好一開始就選擇合適的方式,以防后續需要擴展它。
Space switch operations to use
Performing a space switch is the same as multiplying a 4x4 matrix to a Vector3. You can perform a space switch of a Vector3 using two methods basically:
1) Using a Matrix4x4 to apply the transformation
You can use the transformation matrix given by the Transform using localToWorldMatrix or worldToLocalMatrix. Or you can build your own. I don't recommend this last one in general.
The Matrix4x4 class has these three methods to apply the transformation:
- Matrix4x4.MultiplyPoint will apply rotation, translation and scale of the tranfsormation.
- Matrix4x4.MultiplyVector will NOT apply the translation, so it is only used if you just care about the rotation and scale.
- Matrix4x4.MultiplyPoint4x3 avoids some operations, but is similar to the first one. We will talk about this later.
2) Using the Transform class to apply the transformation
You can directly gather the Transform component of the object that represents the space you want to switch from or to, and use its TransformXXX methods.
Use "TransformXXX" if you want to change a Vector3 in world space to the local space of that transform , and "InverseTransformXXX" if you want to pass a Vector3 expressed in the space of that particular object, and get a Vector3 in world space.
The three methods available are:
- Transform.(inverse)TransformVector The same as Matrix4x4. Rotation + scale
- Transform.(inverse)TransformPoint. The same as Matrix4x4. Rotation + scale + translation.
- Transform.(inverse)TransformDirection . This one is unique here, will apply only rotation.
You will understand why there is no Matrix4x4.MultiplyDirection . Doing so would be really really slow!
使用哪種空間變換操作
執行空間切換的原理,就等同于將一個 4x4 矩陣與一個 Vector3 相乘。基本上有兩種方法可以對 Vector3 進行空間切換:
1)使用 Matrix4x4 應用變換
你可以使用 Transform 提供的 localToWorldMatrix 或 worldToLocalMatrix 變換矩陣,或者自己構造一個矩陣(一般不推薦后者)。
Matrix4x4 類提供了以下三種方法來應用變換:
-
Matrix4x4.MultiplyPoint:應用旋轉、平移和縮放變換。 -
Matrix4x4.MultiplyVector:不應用平移,僅用于你只關心旋轉和縮放的情況。 -
Matrix4x4.MultiplyPoint3x4:與第一個方法類似,但省略了一些操作。我們稍后會詳細討論這個方法。
2)使用 Transform 類應用變換
你可以直接獲取代表要變換空間的對象的 Transform 組件,并使用它的 TransformXXX 方法。
-
使用
TransformXXX方法:將世界空間中的 Vector3 轉換到該 Transform 的局部空間。 -
使用
InverseTransformXXX方法:將以該對象空間表示的 Vector3 轉換為世界空間中的 Vector3。
三種可用的方法包括:
-
Transform.(Inverse)TransformVector:等同于Matrix4x4,應用旋轉 + 縮放。 -
Transform.(Inverse)TransformPoint:等同于Matrix4x4,應用旋轉 + 縮放 + 平移。 -
Transform.(Inverse)TransformDirection:僅應用旋轉,是此處獨有的操作。
你會明白為什么沒有 Matrix4x4.MultiplyDirection,因為這樣做會非常非常慢!
Matrix multiplication. Point, Direction and Vector differences.
Matrix4x4 and Transform classes, as we saw, always ask if you are applying that transformation to a Point, Direction or Vector.
A point represents a position relative to a given space, a direction just an orientation. A vector is basically the same as a point but the concept works differently when applying transformations!
When you use Matrix4x4.MultiplyPoint it will think your Vector3 passed is a point
矩陣乘法:Point、Direction 和 Vector 的區別
如前所述,Matrix4x4 和 Transform 類在應用變換時,總會問你到底是要對 Point(點)、Direction(方向) 還是 Vector(向量) 進行變換。
-
Point(點):表示相對于某個空間的一個位置。
-
Direction(方向):僅表示一個方向,不包含位置信息。
-
Vector(向量):本質上和點類似,但在應用變換時概念不同!
當你使用 Matrix4x4.MultiplyPoint 方法時,它會把你傳入的 Vector3 當作一個 點 來處理。
To perform a matrix multiplication of sizes:
aXb * cXd (where aXb means a rows and b columns)
the rule says b and c must be the same. So it is aXb by bXc , where a and b are 4 4X4 * 4X1 . So we can't work with a Vector3 (3x1), it has to be a 4x1!. It will add another item to build a Vector4. Then it will return a Vector3 without you noticing it.
Depending on how you want it to interpret it (point or vector) it will add a 0 or a 1 to that 4th item.
Why all this? Because the right side of the matrix, the red part, is the "translation" part. If you remember how multiplying two matrices was done (fun example), you multiply each row by each element of the Vector4, and sum all up. That gives the first item on the new Vector4. Then repeat for the second row... get the second item... etc.
要執行如下尺寸的矩陣乘法:
a×b × c×d(其中 a×b 表示 a 行 b 列)
根據規則,b 和 c 必須相等。
所以是 a×b 乘以 b×d,當 a 和 b 都為 4 時,就是 4×4 × 4×1。
因此我們不能直接使用一個 Vector3(3×1),它必須是一個 4×1 的向量!
這意味著它會為 Vector3 添加一個額外的分量,從而構建成一個 Vector4。
然后變換完成后,會自動返回一個 Vector3,整個過程你可能不會察覺。
根據你希望它被解釋為“點”還是“向量”,它會在第4個分量上添加 0 或 1:
-
如果是 點(Point),會添加 1,這樣平移部分會生效。
-
如果是 向量(Vector)或方向(Direction),會添加 0,這樣平移部分被忽略,只進行旋轉和縮放。
為什么要這么做?
因為矩陣右側的那一列(通常是紅色部分)表示的是 “平移”部分。
如果你還記得矩陣乘法是如何進行的(一個有趣的例子):
你會將每一行與 Vector4 的每個元素分別相乘,然后相加,得到新的向量的每一個分量。
這個過程依次進行,最終構成一個新的 Vector4。
The red part will be multiplied by the last item in the Vector4. (x,y,z,1) will add m14 m24 m34 to the three x,y,z values because each of them will be multiplied by 1 and summed to the rest... thus applying the translation to the resulting Vector4.
Instead, if you say it is a direction, it will use (x,y,z,0), and the red part will never be applied. So it will not translate the direction, it will just apply the blue part, which is rotation and scale.
The green part of the matrix is rarely used, except for shear operations and weird projections.

矩陣中紅色部分會與 Vector4 的最后一個分量相乘。
當你使用 (x, y, z, 1) 時,矩陣中的 m14、m24 和 m34 會分別加到 x、y、z 上,因為它們每一個都乘以了 1,并加到其余部分上……
這樣就把平移變換應用到了最終的 Vector4 上。
而如果你說它是一個方向(Direction),那就會使用 (x, y, z, 0),這樣紅色部分就不會被應用。
所以這個方向不會被平移,只會應用藍色部分(旋轉和縮放)。
矩陣中的綠色部分很少被使用,除非用于剪切(Shear)變換或一些特殊的投影操作。
Summary. Which method to use?
總結:應該使用哪種方法?
Method A)
Transform.(inverse)transformXXX
This method is a one-liner, it is fast enough, but slower if you do it many many times. If not used many many times and you want to save lines of code, it's ok.
這是最簡潔的一行代碼,速度也夠快。如果你不是要重復執行很多次,而且希望代碼更簡潔,這種方式是可以接受的。
Method B)
Transform.worldToLocalMatrix.MultiplyXXX
If you use this directly and use it just once, it's ok. But I recommend using the method A before this one. If you end up using it many times, it's the slowest one. Careful with this!
但總體上推薦優先使用方法 A。
如果你頻繁使用這種方式,它是三種里最慢的,務必注意!
Method C)
Matrix4x4 savedMatrix = Transform.worldToLocalMatrix;
savedMatrix.MultiplyPoint...
This is the fastest method of all if you need to perform a lot of transform operations. But not fast if you use it for very few operations. If you are working with positions, use MultiplyPoint3x4 instead of MultiplyPoint for an even faster operation if you are not doing anything weird with transformations.
如果你需要執行大量的變換操作,這是最快的方法。但如果只是少量使用,反而不劃算。
如果你處理的是位置(Position),而且沒有涉及特別復雜的變換,建議使用 MultiplyPoint3x4 替代 MultiplyPoint,會更快。
Why?
The transformation of each gameObject is stored in the transform component. It is never stored as a matrix. It is instead stored as 3 items, T, R and S: A translation, a rotation and a scale, as you know. That means it stores a Vector3, a Quaternion, and a Vector3.
每個 GameObject 的變換信息都存儲在 transform 組件中。它從不會以矩陣形式存儲,而是以三個元素的形式:T、R 和 S,也就是你所知道的平移、旋轉和縮放。這意味著它存儲的是一個 Vector3、一個 Quaternion 和一個 Vector3。
Method A performs operations directly using the transform items, that means: Performing the scale by multiplying the scale vector, performing the rotation by applying the quaternion and then moving the element to the position by adding the translation. This means A LOT of operations.
方法 A 是直接使用 transform 中的這些數據來操作,這表示:通過乘縮放向量來執行縮放,通過應用四元數來執行旋轉,然后通過加上平移向量來移動物體。這意味著會進行大量的操作。
Method B uses worldToLocalMatrix. This is a c# property that creates and returns a Matrix4x4 and this matrix is a struct with 16 values created combining the elements that are stored (S, R, T) in a certain way. It needs performing Sin, Cos and other operations. So as you probably guessed, it is a slow operation. Using this all the time will create a new Struct with all that data all the time. BAD!
方法 B 使用 worldToLocalMatrix。它是一個 C# 屬性,會創建并返回一個 Matrix4x4 矩陣,而這個矩陣是通過以特定方式組合存儲的 S、R、T 元素而生成的結構體,它需要執行正弦、余弦等運算。所以你可能已經猜到,這個操作是比較慢的。如果你頻繁使用它,每次都會創建一個包含所有數據的新結構體。不好!
Method C stores the worldToLocalMatrix into a variable of type Matrix4x4. This is great if you are going to use it many many times. It is only generated once, and then used. To transform a vector using a matrix is just multiplying both.
方法 C 將 worldToLocalMatrix 緩存到一個 Matrix4x4 類型的變量中。如果你需要進行大量變換操作,這是最好的方式。它只生成一次,然后重復使用。用矩陣變換向量只是做乘法而已。
In my simulations a matrix like this is used with 500.000 items, so yes. It is faster. Why? Because multiplying a matrix by a vector is basically performing 28 operations: 16 multiplications (4 per row by vector) and 12 sums (sum 4 multiplication per row), which is way less than creating the struct, building the matrix and returning it. Learn more about matrix multiplication (4x4) by a vector, which is a matrix of (1x4) here.
Even better, with Matrix4x4 we have the oportunity to use this awesome method called MultiplyPoint3x4. which is faster because the last row of the matrix is completely ignored, removing 4 multiplications and 3 sums from the list or operations.
在我的模擬中,類似的矩陣對 500,000 個元素進行操作,確實更快。為什么?因為一個矩陣乘以一個向量基本上只執行 28 個操作:16 次乘法(每行 4 次乘以向量),再加上 12 次加法(每行 4 個乘積求和),遠比創建結構體、構建矩陣并返回要少。你可以通過這里了解更多關于 4x4 矩陣與向量的乘法。
更進一步,使用 Matrix4x4 時我們可以用一個非常棒的方法叫做 MultiplyPoint3x4,它更快,因為它完全忽略了矩陣的最后一行,從操作中移除了 4 次乘法和 3 次加法。
It contains shear values operations, which are normally seen when you are trying to perform a transformation that changes the perspective, in projections of points, for example, when you want to put a 3D object on top of a character, and you need to project that 3D point into the 2D flat plane of the camera.
Those operations are not normally used unless you are doing something fancy like this. In case you are doing regular operations with positions of objects, moving objects, rotating, and not doing any projection or shear operation, feel free to use Multiply3x4 and save even more time!
它包含的是剪切(shear)運算值,這些通常出現在你要進行視角變化的變換中,比如投影點時使用的操作。例如,當你想把一個 3D 物體投影到角色頭頂上,在相機的二維平面中展示那個 3D 點時,就會用到這種操作。
這些操作在常規使用中是不會用到的,除非你在做一些特別的事情。
如果你只是進行常規的對象位置操作,比如移動、旋轉、而不是做投影或剪切變換,盡管放心使用 MultiplyPoint3x4,它會更快!

浙公網安備 33010602011771號