vector_math.rst 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. .. _doc_vector_math:
  2. Vector math
  3. ===========
  4. Introduction
  5. ~~~~~~~~~~~~
  6. This tutorial is a short and practical introduction to linear algebra as
  7. it applies to game development. Linear algebra is the study of vectors and
  8. their uses. Vectors have many applications in both 2D and 3D development
  9. and Godot uses them extensively. Developing a good understanding of vector
  10. math is essential to becoming a strong game developer.
  11. .. note:: This tutorial is **not** a formal textbook on linear algebra. We
  12. will only be looking at how it is applied to game development.
  13. For a broader look at the mathematics,
  14. see https://www.khanacademy.org/math/linear-algebra
  15. Coordinate systems (2D)
  16. ~~~~~~~~~~~~~~~~~~~~~~~
  17. In 2D space, coordinates are defined using a horizontal axis (``x``) and
  18. a vertical axis (``y``). A particular position in 2D space is written
  19. as a pair of values such as ``(4, 3)``.
  20. .. image:: img/vector_axis1.png
  21. .. note:: If you're new to computer graphics, it might seem odd that the
  22. positive ``y`` axis points **downwards** instead of upwards,
  23. as you probably learned in math class. However, this is common
  24. in most computer graphics applications.
  25. Any position in the 2D plane can be identified by a pair of numbers in this
  26. way. However, we can also think of the position ``(4, 3)`` as an **offset**
  27. from the ``(0, 0)`` point, or **origin**. Draw an arrow pointing from
  28. the origin to the point:
  29. .. image:: img/vector_xy1.png
  30. This is a **vector**. A vector represents a lot of useful information. As
  31. well as telling us that the point is at ``(4, 3)``, we can also think of
  32. it as an angle ``θ`` and a length (or magnitude) ``m``. In this case, the
  33. arrow is a **position vector** - it denotes a position in space, relative
  34. to the origin.
  35. A very important point to consider about vectors is that they only
  36. represent **relative** direction and magnitude. There is no concept of
  37. a vector's position. The following two vectors are identical:
  38. .. image:: img/vector_xy2.png
  39. Both vectors represent a point 4 units to the right and 3 units below some
  40. starting point. It does not matter where on the plane you draw the vector,
  41. it always represents a relative direction and magnitude.
  42. Vector operations
  43. ~~~~~~~~~~~~~~~~~
  44. You can use either method (x and y coordinates or angle and magnitude) to
  45. refer to a vector, but for convenience, programmers typically use the
  46. coordinate notation. For example, in Godot, the origin is the top-left
  47. corner of the screen, so to place a 2D node named ``Node2D`` 400 pixels to the right and
  48. 300 pixels down, use the following code:
  49. .. tabs::
  50. .. code-tab:: gdscript GDScript
  51. $Node2D.position = Vector2(400, 300)
  52. .. code-tab:: csharp
  53. var node2D = (Node2D) GetNode("Node2D");
  54. node2D.Position = new Vector2(400, 300);
  55. Godot supports both :ref:`Vector2 <class_Vector2>` and
  56. :ref:`Vector3 <class_Vector3>` for 2D and 3D usage, respectively. The same
  57. mathematical rules discussed in this article apply to both types.
  58. Member access
  59. -------------
  60. The individual components of the vector can be accessed directly by name.
  61. .. tabs::
  62. .. code-tab:: gdscript GDScript
  63. # create a vector with coordinates (2, 5)
  64. var a = Vector2(2, 5)
  65. # create a vector and assign x and y manually
  66. var b = Vector2()
  67. b.x = 3
  68. b.y = 1
  69. .. code-tab:: csharp
  70. // create a vector with coordinates (2, 5)
  71. var a = new Vector2(2, 5);
  72. // create a vector and assign x and y manually
  73. var b = new Vector2();
  74. b.x = 3;
  75. b.y = 1;
  76. Adding vectors
  77. --------------
  78. When adding or subtracting two vectors, the corresponding components are added:
  79. .. tabs::
  80. .. code-tab:: gdscript GDScript
  81. var c = a + b # (2, 5) + (3, 1) = (5, 6)
  82. .. code-tab:: csharp
  83. var c = a + b; // (2, 5) + (3, 1) = (5, 6)
  84. We can also see this visually by adding the second vector at the end of
  85. the first:
  86. .. image:: img/vector_add1.png
  87. Note that adding ``a + b`` gives the same result as ``b + a``.
  88. Scalar multiplication
  89. ---------------------
  90. .. note:: Vectors represent both direction and magnitude. A value
  91. representing only magnitude is called a **scalar**.
  92. A vector can be multiplied by a **scalar**:
  93. .. tabs::
  94. .. code-tab:: gdscript GDScript
  95. var c = a * 2 # (2, 5) * 2 = (4, 10)
  96. var d = b / 3 # (3, 6) / 3 = (1, 2)
  97. .. code-tab:: csharp
  98. var c = a * 2; // (2, 5) * 2 = (4, 10)
  99. var d = b / 3; // (3, 6) / 3 = (1, 2)
  100. .. image:: img/vector_mult1.png
  101. .. note:: Multiplying a vector by a scalar does not change its direction,
  102. only its magnitude. This is how you **scale** a vector.
  103. Practical applications
  104. ~~~~~~~~~~~~~~~~~~~~~~
  105. Let's look at two common uses for vector addition and subtraction.
  106. Movement
  107. --------
  108. A vector can represent **any** quantity with a magnitude and direction. Typical examples are: position, velocity, acceleration, and force. In
  109. this image, the spaceship at step 1 has a position vector of ``(1,3)`` and
  110. a velocity vector of ``(2,1)``. The velocity vector represents how far the
  111. ship moves each step. We can find the position for step 2 by adding
  112. the velocity to the current position.
  113. .. image:: img/vector_movement1.png
  114. .. tip:: Velocity measures the **change** in position per unit of time. The
  115. new position is found by adding velocity to the previous position.
  116. Pointing toward a target
  117. ------------------------
  118. In this scenario, you have a tank that wishes to point its turret at a
  119. robot. Subtracting the tank's position from the robot's position gives the
  120. vector pointing from the tank to the robot.
  121. .. image:: img/vector_subtract2.png
  122. .. tip:: To find a vector pointing from ``A`` to ``B`` use ``B - A``.
  123. Unit vectors
  124. ~~~~~~~~~~~~
  125. A vector with **magnitude** of ``1`` is called a **unit vector**. They are
  126. also sometimes referred to as **direction vectors** or **normals**. Unit
  127. vectors are helpful when you need to keep track of a direction.
  128. Normalization
  129. -------------
  130. **Normalizing** a vector means reducing its length to ``1`` while
  131. preserving its direction. This is done by dividing each of its components
  132. by its magnitude:
  133. .. tabs::
  134. .. code-tab:: gdscript GDScript
  135. var a = Vector2(2, 4)
  136. var m = sqrt(a.x*a.x + a.y*a.y) # get magnitude "m" using the Pythagorean theorem
  137. a.x /= m
  138. a.y /= m
  139. .. code-tab:: csharp
  140. var a = new Vector2(2, 4);
  141. var m = Mathf.Sqrt(a.x*a.x + a.y*a.y); // get magnitude "m" using the Pythagorean theorem
  142. a.x /= m;
  143. a.y /= m;
  144. Because this is such a common operation, ``Vector2`` and ``Vector3`` provide
  145. a method for normalizing:
  146. .. tabs::
  147. .. code-tab:: gdscript GDScript
  148. a = a.normalized()
  149. .. code-tab:: csharp
  150. a = a.Normalized();
  151. .. warning:: Because normalization involves dividing by the vector's length,
  152. you cannot normalize a vector of length ``0``. Attempting to
  153. do so will result in an error.
  154. Reflection
  155. ----------
  156. A common use of unit vectors is to indicate **normals**. Normal
  157. vectors are unit vectors aligned perpendicularly to a surface, defining
  158. its direction. They are commonly used for lighting, collisions, and other
  159. operations involving surfaces.
  160. For example, imagine we have a moving ball that we want to bounce off a
  161. wall or other object:
  162. .. image:: img/vector_reflect1.png
  163. The surface normal has a value of ``(0, -1)`` because this is a horizontal
  164. surface. When the ball collides, we take its remaining motion (the amount
  165. left over when it hits the surface) and reflect it using the normal. In
  166. Godot, the :ref:`Vector2 <class_Vector2>` class has a ``bounce()`` method
  167. to handle this. Here is a GDScript example of the diagram above using a
  168. :ref:`KinematicBody2D <class_KinematicBody2D>`:
  169. .. tabs::
  170. .. code-tab:: gdscript GDScript
  171. # object "collision" contains information about the collision
  172. var collision = move_and_collide(velocity * delta)
  173. if collision:
  174. var reflect = collision.remainder.bounce(collision.normal)
  175. velocity = velocity.bounce(collision.normal)
  176. move_and_collide(reflect)
  177. .. code-tab:: csharp
  178. // KinematicCollision2D contains information about the collision
  179. KinematicCollision2D collision = MoveAndCollide(_velocity * delta);
  180. if (collision != null)
  181. {
  182. var reflect = collision.Remainder.Bounce(collision.Normal);
  183. _velocity = _velocity.Bounce(collision.Normal);
  184. MoveAndCollide(reflect);
  185. }
  186. Dot product
  187. ~~~~~~~~~~~
  188. The **dot product** is one of the most important concepts in vector math,
  189. but is often misunderstood. Dot product is an operation on two vectors that
  190. returns a **scalar**. Unlike a vector, which contains both magnitude and
  191. direction, a scalar value has only magnitude.
  192. The formula for dot product takes two common forms:
  193. .. math::
  194. A \cdot B = \left \| A \right \|\left \| B \right \|\cos \Theta
  195. and
  196. .. math::
  197. A \cdot B = A_{x}B_{x} + A_{y}B_{y}
  198. However, in most cases it is easiest to use the built-in method. Note that
  199. the order of the two vectors does not matter:
  200. .. tabs::
  201. .. code-tab:: gdscript GDScript
  202. var c = a.dot(b)
  203. var d = b.dot(a) # these are equivalent
  204. .. code-tab:: csharp
  205. float c = a.Dot(b);
  206. float d = b.Dot(a); // these are equivalent
  207. The dot product is most useful when used with unit vectors, making the
  208. first formula reduce to just ``cosθ``. This means we can use the dot
  209. product to tell us something about the angle between two vectors:
  210. .. image:: img/vector_dot3.png
  211. When using unit vectors, the result will always be between ``-1`` (180°)
  212. and ``1`` (0°).
  213. Facing
  214. ------
  215. We can use this fact to detect whether an object is facing toward another
  216. object. In the diagram below, the player ``P`` is trying to avoid the
  217. zombies ``A`` and ``B``. Assuming a zombie's field of view is **180°**, can they see the player?
  218. .. image:: img/vector_facing2.png
  219. The green arrows ``fA`` and ``fB`` are **unit vectors** representing the
  220. zombies' facing directions and the blue semicircle represents its field of
  221. view. For zombie ``A``, we find the direction vector ``AP`` pointing to
  222. the player using ``P - A`` and normalize it. If the angle between this
  223. vector and the facing vector is less than 90°, then the zombie can see
  224. the player.
  225. In code it would look like this:
  226. .. tabs::
  227. .. code-tab:: gdscript GDScript
  228. var AP = (P - A).normalized()
  229. if AP.dot(fA) > 0:
  230. print("A sees P!")
  231. .. code-tab:: csharp
  232. var AP = (P - A).Normalized();
  233. if (AP.Dot(fA) > 0)
  234. {
  235. GD.Print("A sees P!");
  236. }
  237. Cross product
  238. ~~~~~~~~~~~~~
  239. Like the dot product, the **cross product** is an operation on two vectors.
  240. However, the result of the cross product is a vector with a direction
  241. that is perpendicular to both. Its magnitude depends on their relative angle.
  242. If two vectors are parallel, the result of their cross product will be a null vector.
  243. .. math::
  244. \left \|a \times b \right \| = \left \| a \right \|\left \| b \right \|\ |\sin(a,b)|
  245. .. image:: img/tutovec16.png
  246. The cross product is calculated like this:
  247. .. tabs::
  248. .. code-tab:: gdscript GDScript
  249. var c = Vector3()
  250. c.x = (a.y * b.z) - (a.z * b.y)
  251. c.y = (a.z * b.x) - (a.x * b.z)
  252. c.z = (a.x * b.y) - (a.y * b.x)
  253. .. code-tab:: csharp
  254. var c = new Vector3();
  255. c.x = (a.y * b.z) - (a.z * b.y);
  256. c.y = (a.z * b.x) - (a.x * b.z);
  257. c.z = (a.x * b.y) - (a.y * b.x);
  258. With Godot, you can use the built-in method:
  259. .. tabs::
  260. .. code-tab:: gdscript GDScript
  261. var c = a.cross(b)
  262. .. code-tab:: csharp
  263. var c = a.Cross(b);
  264. .. note:: In the cross product, order matters. ``a.cross(b)`` does not
  265. give the same result as ``b.cross(a)``. The resulting vectors
  266. point in **opposite** directions.
  267. Calculating normals
  268. -------------------
  269. One common use of cross products is to find the surface normal of a plane
  270. or surface in 3D space. If we have the triangle ``ABC`` we can use vector
  271. subtraction to find two edges ``AB`` and ``AC``. Using the cross product,
  272. ``AB x AC`` produces a vector perpendicular to both: the surface normal.
  273. Here is a function to calculate a triangle's normal:
  274. .. tabs::
  275. .. code-tab:: gdscript GDScript
  276. func get_triangle_normal(a, b, c):
  277. # find the surface normal given 3 vertices
  278. var side1 = b - a
  279. var side2 = c - a
  280. var normal = side1.cross(side2)
  281. return normal
  282. .. code-tab:: csharp
  283. Vector3 GetTriangleNormal(Vector3 a, Vector3 b, Vector3 c)
  284. {
  285. // find the surface normal given 3 vertices
  286. var side1 = b - a;
  287. var side2 = c - a;
  288. var normal = side1.Cross(side2);
  289. return normal;
  290. }
  291. Pointing to a target
  292. --------------------
  293. In the dot product section above, we saw how it could be used to find the
  294. angle between two vectors. However, in 3D, this is not enough information.
  295. We also need to know what axis to rotate around. We can find that by
  296. calculating the cross product of the current facing direction and the
  297. target direction. The resulting perpendicular vector is the axis of
  298. rotation.
  299. More information
  300. ~~~~~~~~~~~~~~~~
  301. For more information on using vector math in Godot, see the following articles:
  302. - :ref:`doc_vectors_advanced`
  303. - :ref:`doc_matrices_and_transforms`