matrices_and_transforms.rst 13 KB

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