matrices_and_transforms.rst 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. Matrices & Transforms
  2. =====================
  3. Introduction
  4. ------------
  5. Before reading this tutorial, it is advised to read the previous one
  6. about [[Vector Math]] as this one is a direct continuation.
  7. | This tutorial will be about *transformations* and will cover a little
  8. about matrices (but not in-depth).
  9. | Transformations are most of the time applied as translation, rotation
  10. and scale so they will be considered as priority here.
  11. Oriented Coordinate System (OCS)
  12. --------------------------------
  13. Imagine we have a spaceship somewhere in space. In Godot this is easy,
  14. just move the ship somewhere and rotate it:
  15. .. image:: /img/tutomat1.png
  16. Ok, so in 2D this looks simple, a position and an angle for a rotation.
  17. But remember, we are grown ups here and don't use angles (plus, angles
  18. are not really even that useful when working in 3D).
  19. | We should realize that at some point, someone *designed* this
  20. spaceship. Be it for 2D in a drawing such as Paint.net, Gimp,
  21. Photoshop, etc. or in 3D through a 3D DCC tool such as Blender, Max,
  22. Maya, etc.
  23. | When it was designed, it was not rotated. It was designed in it's own
  24. *coordinate system*.
  25. .. image:: /img/tutomat2.png
  26. | This means that the tip of the ship has a coordinate, the fin has
  27. another, etc. Be it in pixels (2D) or vertices (3D).
  28. | So, let's recall again that the ship was somewhere in space:
  29. .. image:: /img/tutomat3.png
  30. How did it get there? What moved it and rotated it from the place it was
  31. designed to it's current position? The answer is... a **transform**, the
  32. ship was *transformed* from their original position to the new one. This
  33. allows the ship to be displayed where it is.
  34. So, a transform is too generic of a term. To solve this puzzle, we will
  35. overimpose the ship's original design position at their current
  36. position:
  37. .. image:: /img/tutomat4.png
  38. So, we can see that the "design space" has been transformed too. How can
  39. we best represent this transformation? Let's use 3 vectors for this (in
  40. 2D), a unit vector pointing towards X positive, a unit vector pointing
  41. towards Y positive and a translation.
  42. .. image:: /img/tutomat5.png
  43. Let's call the 3 vectors "X", "Y" and "Origin", and let's also
  44. overimpose them over the ship so it makes more sense:
  45. .. image:: /img/tutomat6.png
  46. Ok, this is nicer, but it still does not make sense. What do X,Y and
  47. Origin have to do with how the ship got there?
  48. Well, let's take the point from top tip of the ship as reference:
  49. .. image:: /img/tutomat7.png
  50. And let's apply the following operation to it (and to all the points in
  51. the ship too, but we'll track the top tip as our reference point):
  52. ::
  53. var new_pos = pos - origin
  54. Doing this to the selected point will move it back to the center:
  55. .. image:: /img/tutomat8.png
  56. This was expected, but then let's do something more interesting. Use the
  57. dot product of X and the point, and add it to the dot product of Y and
  58. the point:
  59. ::
  60. var final_pos = x.dot(new_pos) + y.dot(new_pos)
  61. Then what we have is.. wait a minute, it's the ship in it's design
  62. position!
  63. .. image:: /img/tutomat9.png
  64. | How did this black magic happen? The ship was lost in space, and now
  65. it's back home!
  66. | It might seem strange, but it does have plenty of logic. Remember, as
  67. we have seen in the [[tutorial\_vector\_math#distance-to-plane]], what
  68. happened is that the distance to X axis, and the distance to Y axis
  69. were computed. Calculating distance in a direction or plane was one of
  70. the uses for the dot product. This was enough to obtain back the
  71. design coordinates for every point in the ship.
  72. So, what he have been working with so far (with X, Y and Origin) is an
  73. *Oriented Coordinate System\*. X an Y are the **Basis**, and \*Origin*
  74. is the offset.
  75. Basis
  76. -----
  77. The Origin we know what it is. It's where the 0.0 (origin) of the design
  78. coordinate system ended up after being transformed to a new position.
  79. This is why it's called *Origin*, But in practice, it's just an offset
  80. to the new position.
  81. The Basis is more interesting. The basis is the X and Y of the new,
  82. transformed, OCS are pointing towards. It's telling what is in change of
  83. drawing 2D and 3D "Hey, the original X and Y axes or your design are
  84. *right here*, pointing towards *these directions*".
  85. So, let's change the representation of the basis. Instead of 2 vectors,
  86. let's use a *matrix*.
  87. .. image:: /img/tutomat10.png
  88. The vectors are up there in the matrix, horizontally. The next problem
  89. now is that.. what is this matrix thing? Well, we'll assume you've never
  90. heard of a matrix.
  91. Transforms in Godot
  92. -------------------
  93. This tutorial will not explain matrix math (and their operations) in
  94. depth, only it's practical use. There is plenty of material for that,
  95. which should be a lot simpler to understand after completing this
  96. tutorial. We'll just explain how to use transforms.
  97. Matrix32
  98. --------
  99. `Matrix32 <https://github.com/okamstudio/godot/wiki/class_matrix32>`__
  100. is a 3x2 matrix. It has 3 Vector2 elements and it's used for 2D. The "X"
  101. axis is the element 0, "Y" axis is the element 1 and "Origin" is element
  102. 2. It's not divided in basis/origin for convenience, due to it's
  103. simplicity.
  104. ::
  105. var m = Matrix32()
  106. var x = m[0] # 'X'
  107. var y = m[1] # 'Y'
  108. var o = m[2] # 'Origin'
  109. Most operations will be explained with this datatype (Matrix32), but the
  110. same logic applies to 3D.
  111. Identity
  112. --------
  113. By default, Matrix32 is created as an "identity" matrix. This means:
  114. - 'X' Points right: Vector2(1,0)
  115. - 'Y' Points up (or down in pixels): Vector2(0,1)
  116. - 'Origin' is the origin Vector2(0,0)
  117. .. image:: /img/tutomat11.png
  118. It's easy to guess that an *identity* matrix is just a matrix that
  119. aligns the transform to it's parent coordinate system. It's an *OCS*
  120. that hasn't been translated, rotated or scaled. All transform types in
  121. Godot are created with *identity*.
  122. Operations
  123. ----------
  124. Rotation
  125. --------
  126. Rotating Matrix32 is done by using the "rotated" function:
  127. ::
  128. var m = Matrix32()
  129. m = m.rotated(PI/2) # rotate 90°
  130. .. image:: /img/tutomat12.png
  131. Translation
  132. -----------
  133. There are two ways to translate a Matrix32, the first one is just moving
  134. the origin:
  135. ::
  136. # Move 2 units to the right
  137. var m = Matrix32()
  138. m = m.rotated(PI/2) # rotate 90°
  139. m[2]+=Vector2(2,0)
  140. .. image:: /img/tutomat13.png
  141. | This will always work in global coordinates.
  142. | If instead, translation is desired in *local* coordinates of the
  143. matrix (towards where the *basis* is oriented), there is the
  144. `Matrix32.translated <https://github.com/okamstudio/godot/wiki/class_matrix32#translated>`__
  145. method:
  146. ::
  147. # Move 2 units towards where the basis is oriented
  148. var m = Matrix32()
  149. m = m.rotated(PI/2) # rotate 90°
  150. m=m.translated( Vector2(2,0) )
  151. .. image:: /img/tutomat14.png
  152. Scale
  153. -----
  154. A matrix can be scaled too. Scaling will multiply the basis vectors by a
  155. vetor (X vector by x component of the scale, Y vector by y component of
  156. the scale). It will leave the origin alone:
  157. ::
  158. # Make the basis twice it's size.
  159. var m = Matrix32()
  160. m = m.scaled( Vector2(2,2) )
  161. .. image:: /img/tutomat15.png
  162. These kind of operations in matrices are accumulative. It means every
  163. one starts relative to the previous one. For those that have been living
  164. on this planet long enough, a good reference of how transform works is
  165. this:
  166. .. image:: /img/tutomat16.png
  167. A matrix is used similarly to a turtle. The turtle most likely had a
  168. matrix inside (and you are likely learning this may years *after*
  169. discovering Santa is not real).
  170. Transform
  171. ---------
  172. Transform is the act of switching between coordinate systems. To convert
  173. a position (either 2D or 3D) from "designer" coordinate system to the
  174. OCS, the "xform" method is used.
  175. ::
  176. var new_pos = m.xform(pos)
  177. And only for basis (no translation):
  178. ::
  179. var new_pos = m.basis_xform(pos)
  180. Post - multiplying is also valid:
  181. ::
  182. var new_pos = m * pos
  183. Inverse Transform
  184. -----------------
  185. To do the opposite operation (what we did up there with the rocket), the
  186. "xform\_inv" method is used:
  187. ::
  188. var new_pos = m.xform_inv(pos)
  189. Only for Basis:
  190. ::
  191. var new_pos = m.basis_xform_inv(pos)
  192. Or pre-multiplication:
  193. ::
  194. var new_pos = pos * m
  195. Orthonormal Matrices
  196. --------------------
  197. | However, if the Matrix has been scaled (vectors are not unit length),
  198. or the basis vectors are not orthogonal (90°), the inverse transform
  199. will not work.
  200. | In other words, inverse transform is only valid in *orthonormal*
  201. matrices. For this, these cases an affine inverse must be computed.
  202. The transform, or inverse transform of an identity matrix will return
  203. the position unchanged:
  204. ::
  205. # Does nothing, pos is unchanged
  206. pos = Matrix32().xform(pos)
  207. Affine Inverse
  208. --------------
  209. The affine inverse is a matrix that does the inverse operation of
  210. another matrix, no matter if the matrix has scale or the axis vectors
  211. are not orthogonal. The affine inverse is calculated with the
  212. affine\_inverse() method:
  213. ::
  214. var mi = m.affine_inverse()
  215. var pos = m.xform(pos)
  216. pos = mi.xform(pos)
  217. #pos is unchanged
  218. If the matrix is orthonormal, then:
  219. ::
  220. #if m is orthonormal, then
  221. pos = mi.xform(pos)
  222. #is the same is
  223. pos = m.xform_inv(pos)
  224. Matrix Multiplication
  225. ---------------------
  226. | Matrices can be multiplied. Multiplication of two matrices "chains"
  227. (concatenates) their transforms.
  228. | However, as per convention, multiplication takes place in reverse
  229. order.
  230. Example:
  231. ::
  232. var m = more_transforms * some_transforms
  233. To make it a little clearer, this:
  234. ::
  235. pos = transform1.xform(pos)
  236. pos = transform2.xform(pos)
  237. Is the same as:
  238. ::
  239. h1. note the inverse order
  240. pos = (transform2 * transform1).xform(pos)
  241. However, this is not the same:
  242. ::
  243. # yields a different results
  244. pos = (transform1 * transform2).xform(pos)
  245. Because in matrix math, A + B is not the same as B + A.
  246. Multiplication by Inverse
  247. -------------------------
  248. Multiplying a matrix by it's inverse, results in identity
  249. ::
  250. # No matter what A is, B will be identity
  251. B = A.affine_inverse() * A
  252. Multiplication by Identity
  253. --------------------------
  254. Multiplying a matrix by identity, will result in the unchanged matrix:
  255. ::
  256. h1. B will be equal to A
  257. B = A * Matrix32()
  258. Matrix tips
  259. -----------
  260. When using a transform hierarchy, remember that matrix multiplication is
  261. reversed! To obtain the global transform for a hierarchy, do:
  262. ::
  263. var global_xform = parent_matrix * child_matrix
  264. For 3 levels:
  265. ::
  266. # due to reverse order, parenthesis are needed
  267. var global_xform = gradparent_matrix + (parent_matrix + child_matrix)
  268. To make a matrix relative to the parent, use the affine inverse (or
  269. regular inverse for orthonormal matrices).
  270. ::
  271. # transform B from a global matrix to one local to A
  272. var B_local_to_A = A.affine_inverse() * B
  273. Revert it just like the example above:
  274. ::
  275. # transform back local B to global B
  276. var B = A * B_local_to_A
  277. OK, hopefully this should be enough! Let's complete the tutorial by
  278. moving to 3D matrices
  279. Matrices & Transforms in 3D
  280. ---------------------------
  281. As mentioned before, for 3D, we deal with 3
  282. `Vector3 <https://github.com/okamstudio/godot/wiki/class_vector3>`__
  283. vectors for the rotation matrix, and an extra one for the origin.
  284. Matrix3
  285. -------
  286. Godot has a special type for a 3x3 matrix, named
  287. `Matrix3 <https://github.com/okamstudio/godot/wiki/class_matrix3>`__. It
  288. can be used to represent a 3D rotation and scale. Sub vectors can be
  289. accessed as:
  290. ::
  291. var m = Matrix3()
  292. var x = m[0] h1. Vector3
  293. var y = m[1] h1. Vector3
  294. var z = m[2] h1. Vector3
  295. or, alternatively as:
  296. ::
  297. var m = Matrix3()
  298. var x = m.x h1. Vector3
  299. var y = m.y h1. Vector3
  300. var z = m.z h1. Vector3
  301. Matrix3 is also initialized to Identity by default:
  302. .. image:: /img/tutomat17.png
  303. Rotation in 3D
  304. --------------
  305. Rotation in 3D is more complex than in 2D (translation and scale are the
  306. same), because rotation is an implicit 2D operation. To rotate in 3D, an
  307. *axis*, must be picked. Rotation, then, happens around this axis.
  308. The axis for the rotation must be a *normal vector*. As in, a vector
  309. that can point to any direction, but length must be one (1.0).
  310. ::
  311. #rotate in Y axis
  312. var m3 = Matrix3()
  313. m3 = m3.rotated( Vector3(0,1,0), PI/2 )
  314. Transform
  315. ---------
  316. To add the final component to the mix, Godot provides the
  317. `Transform <https://github.com/okamstudio/godot/wiki/class_transform>`__
  318. type. Transform has two members:
  319. - *basis* (of type
  320. `Matrix3 <https://github.com/okamstudio/godot/wiki/class_matrix3)>`__
  321. - *origin* (of type
  322. `Vector3 <https://github.com/okamstudio/godot/wiki/class_vector3)>`__
  323. Any 3D transform can be represented with Transform, and the separation
  324. of basis and origin makes it easier to work translation and rotation
  325. separately.
  326. An example:
  327. ::
  328. var t = Transform()
  329. pos = t.xform(pos) #transform 3D position
  330. pos = t.basis.xform(pos) h1. (only rotate)
  331. pos = t.origin + pos (only translate)