vector_math.rst 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920
  1. .. _doc_vector_math:
  2. Vector Math
  3. ===========
  4. Introduction
  5. ~~~~~~~~~~~~
  6. This small tutorial aims to be a short and practical introduction to
  7. vector math, useful for 3D but also 2D games. Again, vector math is not
  8. only useful for 3D but *also* 2D games. It is an amazing tool once you
  9. get the grasp of it and makes programming of complex behaviors much
  10. simpler.
  11. It often happens that young programmers rely too much on the *incorrect*
  12. math for solving a wide array of problems, for example using only
  13. trigonometry instead of vector of math for 2D games.
  14. This tutorial will focus on practical usage, with immediate application
  15. to the art of game programming.
  16. Coordinate Systems (2D)
  17. ~~~~~~~~~~~~~~~~~~~~~~~
  18. Typically, we define coordinates as an (x,y) pair, x representing the
  19. horizontal offset and y the vertical one. This makes sense given the
  20. screen is just a rectangle in two dimensions. As an example, here is a
  21. position in 2D space:
  22. .. image:: /img/tutovec1.png
  23. A position can be anywhere in space. The position (0,0) has a name, it's
  24. called the **origin**. Remember this term well because it has more
  25. implicit uses later. The (0,0) of a n-dimensions coordinate system is
  26. the **origin**.
  27. In vector math, coordinates have two different uses, both equally
  28. important. They are used to represent a *position* but also a *vector*.
  29. The same position as before, when imagined as a vector, has a different
  30. meaning.
  31. .. image:: /img/tutovec2.png
  32. When imagined as a vector, two properties can be inferred, the
  33. **direction** and the **magnitude**. Every position in space can be a
  34. vector, with the exception of the **origin**. This is because
  35. coordinates (0,0) can't represent direction (magnitude 0).
  36. .. image:: /img/tutovec2b.png
  37. Direction
  38. ---------
  39. Direction is simply towards where the vector points to. Imagine an arrow
  40. that starts at the **origin** and goes towards a [STRIKEOUT:position].
  41. The tip of the arrow is in the position, so it always points outwards,
  42. away from the origin. Imagining vectors as arrows helps a lot.
  43. .. image:: /img/tutovec3b.png
  44. Magnitude
  45. ---------
  46. Finally, the length of the vector is the distance from the origin to the
  47. position. Obtaining the length from a vector is easy, just use the
  48. `Pithagorean
  49. Theorem <http://en.wikipedia.org/wiki/Pythagorean_theorem>`__.
  50. ::
  51. var len = sqrt( x*x + y*y )
  52. But.. Angles?
  53. -------------
  54. But why not using an *angle*? After all, we could also think of a vector
  55. as an angle and a magnitude, instead of a direction and a magnitude.
  56. Angles also are a more familiar concept.
  57. To say truth, angles are not that useful in vector math, and most of the
  58. time they are not dealt with directly. Maybe they work in 2D, but in 3D
  59. a lot of what can usually be done with angles does not work anymore.
  60. Still, using angles is still not an excuse, even for 2D. Most of what
  61. takes a lot of work with angles in 2D, is still much more natural easier
  62. to accomplish with vector math. In vector math, angles are useful only
  63. as measure, but take little part in the math. So, give up the
  64. trigonometry already, prepare to embrace vectors!
  65. In any case, obtaining an angle from a vector is easy and can be
  66. accomplished with trig.. er what was that? I mean, the
  67. `atan2(x,y) <https://github.com/okamstudio/godot/wiki/class_@gdscript#atan2>`__
  68. function.
  69. Vectors in Godot
  70. ~~~~~~~~~~~~~~~~
  71. To make examples easier, it is worth explaining how vectors are
  72. implemented in GDScript. GDscript has both
  73. :ref:`Vector2 <class_Vector2>` and
  74. :ref:`Vector3 <class_Vector3>`,
  75. for 2D and 3D math respectively. Godot uses Vector classes as both
  76. position and direction. They also contain x and y (for 2D) and x, y and
  77. z (for 3D) member variables.
  78. ::
  79. h1. create a vector with coordinates (2,5)
  80. var a = Vector2(2,5)
  81. h1. create a vector and assign x and y manually
  82. var b = Vector2()
  83. b.x=7
  84. b.y=8
  85. When operating with vectors, it is not necessary to operate on the
  86. members directly (in fact this is much slower). Vectors support regular
  87. arithmetic operations:
  88. ::
  89. #add a and b
  90. var c = a+b
  91. h1. will result in c vector, with value (9,13)
  92. It is the same as doing:
  93. ::
  94. var c = Vector2()
  95. c.x=a.x+b.x
  96. c.y=a.y+b.y
  97. Except the former is way more efficient and readable.
  98. Regular arithmetic operations such as addition, subtraction,
  99. multiplication and division are supported.
  100. Vector multiplication and division can also be mixed with single-digit
  101. numbers, also named **scalars**.
  102. ::
  103. h1. Multiplication of vector by scalar
  104. var c = a*2.0
  105. h1. will result in c vector, with value (4,10)
  106. Which is the same as doing
  107. ::
  108. var c = Vector2()
  109. c.x = a.x*2.0
  110. c.y = a.y*2.0
  111. Except, again, the former is way more efficient and readable.
  112. Perpendicular Vectors
  113. ~~~~~~~~~~~~~~~~~~~~~
  114. Rotating a 2D vector 90° degrees to either side, left or right, is
  115. really easy, just swap x and y, then
  116. negate either x or y (direction of rotation depends on which is
  117. negated).
  118. .. image:: /img/tutovec15.png
  119. Example:
  120. ::
  121. var v = Vector2(0,1)
  122. #rotate right (clockwise)
  123. var v_right = Vector2(-v.y,v.x)
  124. #rotate left (counter-clockwise)
  125. var v_right = Vector2(v.y,-v.x)
  126. This is a handy trick that is often of use. It is impossible to do with
  127. 3D vectors, because there are an infinite amount of perpendicular
  128. vectors.
  129. Unit Vectors
  130. ~~~~~~~~~~~~
  131. Ok, so we know what a vector is. It has a **direction** and a
  132. **magnitude**. We also know how to use them in Godot. The next step is
  133. learning about **unit vectors**. Any vector with **magnitude** of length
  134. 1 is considered a **unit vector**. In 2D, imagine drawing a circle of
  135. radius one. That circle contains all unit vectors in existence for 2
  136. dimensions:
  137. .. image:: /img/tutovec3.png
  138. So, what is so special about unit vectors? Unit vectors are amazing. In
  139. other words, unit vectors have **several, very useful properties**.
  140. Can't wait to know more about the fantastic properties of unit vectors,
  141. but one step at a time. So, how is a unit vector created from a regular
  142. vector?
  143. Normalization
  144. -------------
  145. Taking any vector and reducing it's **magnitude** to 1.0 while keeping
  146. it's **direction** is called **normalization**. Normalization is
  147. performed by dividing the x and y (and z in 3D) components of a vector
  148. by it's magnitude:
  149. ::
  150. var a = Vector2(2,4)
  151. var m = sqrt( a.x*a.x + a.y*a.y )
  152. a.x/=m
  153. a.y/=m
  154. As you might have guessed, if the vector has magnitude 0 (meaning, it's
  155. not a vector but the **origin** also called *null vector*), a division
  156. by zero occurs and the universe goes through a second big bang, except
  157. in reverse polarity and then back. As a result, humanity is safe but
  158. Godot will print an error. Remember! Vector(0,0) can't be normalized!.
  159. Of course, Vector2 and Vector3 already provide a method to do this:
  160. ::
  161. a = a.normalized()
  162. Dot Product
  163. ~~~~~~~~~~~
  164. OK, the **dot product** is the most important part of vector math.
  165. Without the dot product, Quake would have never been made. This is the
  166. most important section of the tutorial, so make sure to grasp it
  167. properly. Most people trying to understand vector math give up here
  168. because, despite how simple it is, they can't make head or tails from
  169. it. Why? Here's why, it's because..
  170. The dot product takes two vectors and returns a **scalar**:
  171. ::
  172. var s = a.x*b.x + a.y*b.y
  173. Yes, pretty much that. Multiply **x** from vector **a** by **x** from
  174. vector **b**. Do the same with y and add it together. In 3D it's pretty
  175. much the same:
  176. ::
  177. var s = a.x*b.x + a.y*b.y + a.z*b.z
  178. I know, it's totally meaningless! you can even do it with a built-in
  179. function:
  180. ::
  181. var s = a.dot(b)
  182. The order of two vectors does *not* matter, \`a.dot(b)\` returns the
  183. same value as \`b.dot(a)\`.
  184. This is where despair begins and books and tutorials show you this
  185. formula:
  186. .. image:: /img/tutovec4.png
  187. And you realize it's time to give up making 3D games or complex 2D
  188. games. How can something so simple be so complex? Someone else will have
  189. to make the next Zelda or Call of Duty. Top down RPGs don't look so bad
  190. after all. Yeah I hear someone did pretty will with one of those on
  191. Steam...
  192. So this is your moment, this is your time to shine. **DO NOT GIVE UP**!
  193. At this point, this tutorial will take a sharp turn and focus on what
  194. makes the dot product useful. This is, **why** it is useful. We will
  195. focus one by one in the use cases for the dot product, with real-life
  196. applications. No more formulas that don't make any sense. Formulas will
  197. make sense *once you learn* why do they exist for.
  198. Siding
  199. ------
  200. The first useful and most important property of the dot product is to
  201. check what side stuff is looking at. Let's imagine we have any two
  202. vectors, **a** and **b**. Any **direction** or **magnitude** (neither
  203. **origin**). Does not matter what they are, but let's imagine we compute
  204. the dot product between them.
  205. ::
  206. var s = a.dot(b)
  207. The operation will return a single floating point number (but since we
  208. are in vector world, we call them **scalar**, will keep using that term
  209. from now on). This number will tell us the following:
  210. - If the number is greater than zero, both are looking towards the same
  211. direction (the angle between them is < 90° degrees).
  212. - If the number is less than zero, both are looking towards opposite
  213. direction (the angle between them is > 90° degrees).
  214. - If the number is zero, vectors are shaped in L (the angle between
  215. them *is* 90° degrees).
  216. .. image:: /img/tutovec5.png
  217. So let's think of a real use-case scenario. Imagine Snake is going
  218. through a forest, and then there is an enemy nearby. How can we quickly
  219. tell if the enemy has seen discovered Snake? In order to discover him,
  220. the enemy must be able to *see* Snake. Let's say, then that:
  221. - Snake is in position **A**.
  222. - The enemy is in position **B**.
  223. - The enemy is *facing* towards direction vector **F**.
  224. .. image:: /img/tutovec6.png
  225. So, let's create a new vector **BA** that goes from the guard (**B**) to
  226. Snake (**A**), by subtracting the two:
  227. ::
  228. var BA = A-B
  229. .. image:: /img/tutovec7.png
  230. Ideally, if the guard was looking straight towards snake, to make eye to
  231. eye contact, it would do it in the same direction as vector BA.
  232. If the dot product between **F** and **BA** is greater than 0, then
  233. Snake will be discovered. This happens because we will be able to tell
  234. that the guard is facing towards him:
  235. ::
  236. if ( BA.dot(F) > 0 ):
  237. print("!")
  238. Seems Snake is safe so far.
  239. Siding with Unit Vectors
  240. ~~~~~~~~~~~~~~~~~~~~~~~~
  241. Ok, so now we know that dot product between two vectors will let us know
  242. if they are looking towards the same side, opposite sides or are just
  243. perpendicular to each other.
  244. This works the same with all vectors, no matter the magnitude so **unit
  245. vectors** are not the exception. However, using the same property with
  246. unit vectors yields an even more interesting result, as an extra
  247. property is added:
  248. - If both vectors are facing towards the exact same direction (parallel
  249. to each other, angle between them is 0°), the resulting scalar is
  250. **1**.
  251. - If both vectors are facing towards the exact opposite direction
  252. (parallel to each other, but angle between them is 180°), the
  253. resulting scalar is **-1**.
  254. This means that dot product between unit vectors is always between the
  255. range of 1 and -1. So Again..
  256. - If their angle is **0°** dot product is **1**.
  257. - If their angle is **90°**, then dot product is **0**.
  258. - If their angle is **180°**, then dot product is **-1**.
  259. Uh.. this is oddly familiar.. seen this before.. where?
  260. Let's take two unit vectors. The first one is pointing up, the second
  261. too but we will rotate it all the way from up (0°) to down (180°
  262. degrees)..
  263. .. image:: /img/tutovec8.png
  264. ..while plotting the resulting scalar!
  265. .. image:: /img/tutovec9.png
  266. Aha! It all makes sense now, this is a
  267. `Cosine <http://mathworld.wolfram.com/Cosine.html>`__ function!
  268. We can say that, then, as a rule..
  269. The **dot product** between two **unit vectors** is the **cosine** of
  270. the **angle** between those two vectors. So, to obtain the angle between
  271. two vectors, we must do:
  272. ::
  273. var angle_in_radians = acos( a.dot(b) )
  274. What is this useful for? Well obtaining the angle directly is probably
  275. not as useful, but just being able to tell the angle is useful for
  276. reference. One example is in the `Kinematic
  277. Character <https://github.com/okamstudio/godot/blob/master/demos/2d/kinematic_char/player.gd#L83>`__
  278. demo, when the character moves in a certain direction then we hit an
  279. object. How to tell if what we hit is the floor?
  280. By comparing the normal of the collision point with a previously
  281. computed angle.
  282. The beauty of this is that the same code works exactly the same and
  283. without modification in
  284. `3D <https://github.com/okamstudio/godot/blob/master/demos/3d/kinematic_char/cubio.gd#L64>`__.
  285. Vector math is, in a great deal, dimemsion-amount-independent, so adding
  286. or removing an axis only adds very little complexity.
  287. Planes
  288. ~~~~~~
  289. The dot product has another interesting property with unit vectors.
  290. Imagine that perpendicular to that vector (and through the origin)
  291. passes a [STRIKEOUT:plane]. Planes divide the entire space into positive
  292. (over the plane) and negative (under the plane), and (contrary to
  293. popular belief) you can also use their math in 2D:
  294. .. image:: /img/tutovec10.png
  295. Unit vectors that are perpendicular to a surface (so, they describe the
  296. orientation of the surface) are called **unit normal vectors**. Though,
  297. usually they are just abbreviated as \*normalsÄ. Normals appear in
  298. planes, 3D geometry (to determine where each face or vertex is siding),
  299. etc. A **normal** *is* a **unit vector**, but it's called *normal*
  300. because of it's usage. (Just like we call Origin to (0,0)!).
  301. It's as simple as it looks. The plane passes by the origin and the
  302. surface of it is perpendicular to the unit vector (or *normal*). The
  303. side towards the vector points to is the positive half-space, while the
  304. other side is the negative half-space. In 3D this is exactly the same,
  305. except that the plane is an infinite surface (imagine an infinite, flat
  306. sheet of paper that you can orient and is pinned to the origin) instead
  307. of a line.
  308. Distance to Plane
  309. -----------------
  310. Now that it's clear what a plane is, let's go back to the dot product.
  311. The dot product between a **unit vector** and any **point in space**
  312. (yes, this time we do dot product between vector and position), returns
  313. the **distance from the point to the plane**:
  314. ::
  315. var distance = normal.dot(point)
  316. But not just the absolute distance, if the point is in the negative half
  317. space the distance will be negative, too:
  318. .. image:: /img/tutovec11.png
  319. This allows us to tell which side of the plane a point is.
  320. #h3. Away from the Origin
  321. I know what you are thinking! So far this is nice, but *real* planes are
  322. everywhere in space, not only passing through the origin. You want real
  323. *plane* action and you want it *now*.
  324. Remember that planes not only split space in two, but they also have
  325. *polarity*. This means that it is possible to have perfectly overlapping
  326. planes, but their negative and positive half-spaces are swapped.
  327. With this in mind, let's describe a full plane as a **normal** *N* and a
  328. **distance from the origin** scalar *D*. Thus, our plane is represented
  329. by N and D. For example:
  330. .. image:: /img/tutovec12.png
  331. For 3D math, Godot provides a
  332. :ref:`Plane <class_Plane>`
  333. built-in type that handles this.
  334. Basically, N and D can represent any plane in space, be it for 2D or 3D
  335. (depending on the amount of dimensions of N) and the math is the same
  336. for both. It's the same as before, but D id the distance from the origin
  337. to the plane, travelling in N direction. As an example, imagine you want
  338. to reach a point in the plane, you will just do:
  339. .. raw:: html
  340. </pre>
  341. var point\_in\_plane = N\*D
  342. .. raw:: html
  343. </pre>
  344. This will stretch (resize) the normal vector and make it touch the
  345. plane. This math might seem confusing, but it's actually much simpler
  346. than it seems. If we want to tell, again, the distance from the point to
  347. the plane, we do the same but adjusing for distance:
  348. ::
  349. var distance = N.dot(point) - D
  350. This will, again, return either a positive or negative distance.
  351. Flipping the polarity of the plane is also very simple, just negate both
  352. N and D. this will result in a plane in the same position, but with
  353. inverted negative and positive half spaces:
  354. ::
  355. N = -N
  356. D = -D
  357. Of course, Godot implements this operator in
  358. :ref:`Plane <class_Plane>`, so
  359. doing:
  360. ::
  361. var inverted_plane = -plane
  362. Will work as expected.
  363. So, remember, a plane is just that and it's main practical use is
  364. calculating the distance to it. So, why is it useful to calculate the
  365. distance from a point to a plane? It's extremely useful! Let's see some
  366. simple examples..
  367. Constructing a Plane in 2D
  368. --------------------------
  369. Planes clearly don't come out of nowhere, so they must be built.
  370. Constructing them in 2D is easy, this can be done from either a normal
  371. (unit vector) and a point, or from two points in space.
  372. In the case of a normal and a point, most of the work is done, as the
  373. normal is already computed, so just calculate D from the dot product of
  374. the normal and the point.
  375. ::
  376. var N = normal
  377. var D = normal.dot(point)
  378. For two points in space, there are actually two planes that pass through
  379. them, sharing the same space but with normal pointing to the opposite
  380. directions. To compute the normal from the two points, the direction
  381. vector must be obtained first, and then it needs to be rotated 90°
  382. degrees to either side:
  383. ::
  384. #calculate vector from a to b
  385. var dvec = (point_b - point_a).normalized()
  386. #rotate 90 degrees
  387. var normal = Vector2(dvec.y,-dev.x)
  388. #or alternatively
  389. # var normal = Vector2(-dvec.y,dev.x)
  390. # depending the desired side of the normal
  391. The rest is the same as the previous example, either point\_a or
  392. point\_b will work since they are in the same plane:
  393. ::
  394. var N = normal
  395. var D = normal.dot(point_a)
  396. # this works the same
  397. # var D = normal.dot(point_b)
  398. Doing the same in 3D is a little more complex and will be explained
  399. further down.
  400. Some Examples of Planes
  401. -----------------------
  402. Here is a simple example of what planes are useful for. Imagine you have
  403. a `convex <http://www.mathsisfun.com/definitions/convex.html>`__
  404. polygon. For example, a rectangle, a trapezoid, a triangle, or just any
  405. polygon where faces that don't bend inwards.
  406. For every segment of the polygon, we compute the plane that passes by
  407. that segment. Once we have the list of planes, we can do neat things,
  408. for example checking if a point is inside the polygon.
  409. We go through all planes, if we can find a plane where the distance to
  410. the point is positive, then the point is outside the polygon. If we
  411. can't, then the point is inside.
  412. .. image:: /img/tutovec13.png
  413. Code should be something like this:
  414. ::
  415. var inside=true
  416. for p in planes:
  417. #check if distance to plane is positive
  418. if ( N.dot(point) - D > 0):
  419. inside=false
  420. break h1. with one that fails, it's enough
  421. Pretty cool, huh? But this gets much better! With a little more effort,
  422. similar logic will let us know when two convex polygons are overlapping
  423. too. This is called the Separating Axis Theorem (or SAT) and most
  424. physics engines use this to detect collision.
  425. The idea is really simple! With a point, just checking if a plane
  426. returns a positive distance is enough to tell if the point is outside.
  427. With another polygon, we must find a plane where *all the **other**
  428. polygon points* return a positive distance to it. This check is
  429. performed with the planes of A against the points of B, and then with
  430. the planes of B against the points of A:
  431. .. image:: /img/tutovec14.png
  432. Code should be something like this:
  433. ::
  434. var overlapping=true
  435. for p in planes_of_A:
  436. var all_out = true
  437. for v in points_of_B:
  438. if ( p.distance_to(v) < 0):
  439. all_out=false
  440. break
  441. if (all_out):
  442. # a separating plane was found
  443. # do not continue testing
  444. overlapping=false
  445. break
  446. if (overlapping):
  447. #only do this check if no separating plane
  448. #was found in planes of A
  449. for p in planes_of_B:
  450. var all_out = true
  451. for v in points_of_A:
  452. if ( p.distance_to(v) < 0):
  453. all_out=false
  454. break
  455. if (all_out):
  456. overlapping=false
  457. break
  458. if (overlapping):
  459. print("Polygons Collided!")
  460. As you can see, planes are quite useful, and this is the tip of the
  461. iceberg. You might be wondering what happens with non convex polygons.
  462. This is usually just handled by splitting the concave polygon into
  463. smaller convex polygons, or using a technique such as BSP (which is not
  464. used much nowadays).
  465. Cross Product
  466. -------------
  467. Quite a lot can be done with the dot product! But the party would not be
  468. complete without the cross product. Remember back at the beginning of
  469. this tutorial? Specifically how to obtain a perpendicular (rotated 90
  470. degrees) vector by swapping x and y, then negating either of them for
  471. right (clockwise) or left (counter-clockwise) rotation? That ended up
  472. being useful for calculating a 2D plane normal from two points.
  473. As mentioned before, no such thing exists in 3D because a 3D vector has
  474. infinite perpendicular vectors. It would also not make sense to obtain a
  475. 3D plane from 2 points, as 3 points are needed instead.
  476. To aid in this kind stuff, the brightest minds of humanity's top
  477. mathematicians brought us the **cross product**.
  478. The cross product takes two vectors and returns another vector. The
  479. returned third vector is always perpendicular to the first two. The
  480. source vectors, of course, must not be the same, and must not be
  481. parallel or opposite, else the resulting vector will be (0,0,0):
  482. .. image:: /img/tutovec16.png
  483. The formula for the cross product is:
  484. ::
  485. var c = Vector3()
  486. c.x = (a.y + b.z) - (a.z + b.y)
  487. c.y = (a.z + b.x) - (a.x + b.z)
  488. c.z = (a.x + b.y) - (a.y + b.x)
  489. This can be simplified, in Godot, to:
  490. .. raw:: html
  491. </pre>
  492. var c = a.cross(b)
  493. .. raw:: html
  494. </pre>
  495. However, unlike the dot product, doing \`a.cross(b)\` and \`b.cross(a)\`
  496. will yield different results. Specifically, the returned vector will be
  497. negated in the second case. As you might have realized, this coincides
  498. with creating perpendicular vectors in 2D. In 3D, there are also two
  499. possible perpendicular vectors to a pair of 2D vectors.
  500. Also, the resulting cross product of two unit vectors is *not* a unit
  501. vector. Result will need to be renormalized.
  502. Area of a Triangle
  503. ~~~~~~~~~~~~~~~~~~
  504. Cross product can be used to obtain the surface area of a triangle in
  505. 3D. Given a triangle consisting of 3 points, **A**, **B** and **C**:
  506. .. image:: /img/tutovec17.png
  507. Take any of them as a pivot and compute the adjacent vectors to the
  508. other two points. As example, we will use B as a pivot:
  509. .. raw:: html
  510. </pre>
  511. var BA = A-B
  512. var BC = C-B
  513. .. raw:: html
  514. </pre>
  515. .. image:: /img/tutovec18.png
  516. Compute the cross product between **BA** and **BC** to obtain the
  517. perpendicular vector **P**:
  518. ::
  519. var P = BA.cross(BC)
  520. .. image:: /img/tutovec19.png
  521. The length (magnitude) of **P** is the surface area of the parallelogram
  522. built by the two vectors **BA** and **BC**, therefore the surface area
  523. of the triangle is half of it.
  524. ::
  525. var area = P.length()/2
  526. Plane of the Triangle
  527. ~~~~~~~~~~~~~~~~~~~~~
  528. With **P** computed from the previous step, normalize it to get the
  529. normal of the plane.
  530. .. raw:: html
  531. </pre>
  532. var N = P.normalized()
  533. .. raw:: html
  534. </pre>
  535. And obtain the distance by doing the dot product of P with any of the 3
  536. points of the **ABC** triangle:
  537. ::
  538. var D = P.dot(A)
  539. Fantastic! you computed the plane from a triangle!
  540. Here's some useful info (that you can find in Godot source code anyway).
  541. Computing a plane from a triangle can result in 2 planes, so a sort of
  542. convention needs to be set. This usually depends (in video games and 3D
  543. visualization) to use the front-facing side of the triangle.
  544. In Godot, front-facing triangles are those that, when looking at the
  545. camera, are in clockwise order. Triangles that look Counter-clockwise
  546. when looking at the camera are not drawn (this helps to draw less, so
  547. the back-part of the objects is not drawn).
  548. To make it a little clearer, in the image below, the triangle **ABC**
  549. appears clock-wise when looked at from the *Front Camera*, but to the
  550. *Rear Camera* it appears counter-clockwise so it will not be drawn.
  551. .. image:: /img/tutovec20.png
  552. Normals of triangles often are sided towards the direction they can be
  553. viewed from, so in this case, the normal of triangle ABC would point
  554. towards the front camera:
  555. .. image:: /img/tutovec21.png
  556. So, to obtain N, the correct formula is:
  557. ::
  558. # clockwise normal from triangle formula
  559. var N = (A-C).cross(A-B).normalized()
  560. # for counter-clockwise:
  561. # var N = (A-B).cross(A-C).normalized()
  562. var D = N.dot(A)
  563. Collision Detection in 3D
  564. ~~~~~~~~~~~~~~~~~~~~~~~~~
  565. This is another bonus bit, a reward for being patient and keeping up
  566. with this long tutorial. Here is another piece of wisdom. This maybe is
  567. not something with a direct use case (Godot already does collision
  568. detection pretty well) but It's a really cool algorithm to understand
  569. anyway, because it's used by almost all physics engines and collision
  570. detection libraries :)
  571. Remember that converting a convex shape in 2D to an array of 2D planes
  572. was useful for collision detection? You could detect if a point was
  573. inside any convex shape, or if two 2D convex shapes were overlapping.
  574. Well, this works in 3D too, if two 3D polyhedral shapes are colliding,
  575. you won't be able to find a separating plane. If a separating plane is
  576. found, then the shapes are definitely not colliding.
  577. To refresh a bit a separating plane means that all vertices of polygon A
  578. are in one side of the plane, and all vertices of polygon B are in the
  579. other side. This plane is always one of the face-planes of either
  580. polygon A or polygon B.
  581. In 3D though, there is a problem to this approach, because it is
  582. possible that, in some cases a separating plane can't be found. This is
  583. an example of such situation:
  584. .. image:: /img/tutovec22.png
  585. To avoid it, some extra planes need to be tested as separators, these
  586. planes are the cross product between the edges of polygon A and the
  587. edges of polygon B
  588. .. image:: /img/tutovec23.png
  589. So the final algorithm is something like:
  590. ::
  591. var overlapping=true
  592. for p in planes_of_A:
  593. var all_out = true
  594. for v in points_of_B:
  595. if ( p.distance_to(v) < 0):
  596. all_out=false
  597. break
  598. if (all_out):
  599. # a separating plane was found
  600. # do not continue testing
  601. overlapping=false
  602. break
  603. if (overlapping):
  604. #only do this check if no separating plane
  605. #was found in planes of A
  606. for p in planes_of_B:
  607. var all_out = true
  608. for v in points_of_A:
  609. if ( p.distance_to(v) < 0):
  610. all_out=false
  611. break
  612. if (all_out):
  613. overlapping=false
  614. break
  615. if (overlapping):
  616. for ea in edges_of_A:
  617. for eb in edges_of_B:
  618. var n = ea.cross(eb)
  619. if (n.length()==0):
  620. continue
  621. var max_A=-1e20 # tiny number
  622. var min_A=1e20 # huge number
  623. # we are using the dot product directly
  624. # so we can map a maximum and minimum range
  625. # for each polygon, then check if they
  626. # overlap.
  627. for v in points_of_A:
  628. var d = n.dot(v)
  629. if (d>max_A):
  630. max_A=d
  631. if (dmax_B):
  632. max_B=d
  633. if (dmax_B or min_B>max_A):
  634. # not overlapping!
  635. overlapping=false
  636. break
  637. if (not overlapping):
  638. break
  639. if (overlapping):
  640. print("Polygons Collided!")
  641. This was all! Hope it was helpful, and please give feedback and let know
  642. if something in this tutorial is not clear! You should be now ready for
  643. the next challenge... :ref:`doc_matrices_and_transforms`!