123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903 |
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
- <html >
- <head><title></title>
- <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
- <meta name="generator" content="TeX4ht (http://www.cse.ohio-state.edu/~gurari/TeX4ht/)">
- <meta name="originator" content="TeX4ht (http://www.cse.ohio-state.edu/~gurari/TeX4ht/)">
- <!-- html -->
- <meta name="src" content="tutorial.tex">
- <meta name="date" content="2009-10-07 00:28:00">
- <link rel="stylesheet" type="text/css" href="tutorial.css">
- </head><body
- >
- <h3 class="sectionHead"><span class="titlemark">1 </span> <a
- id="x1-10001"></a>Introduction to 3D Math</h3>
- <!--l. 27--><p class="noindent" >
- <h4 class="subsectionHead"><span class="titlemark">1.1 </span> <a
- id="x1-20001.1"></a>Introduction</h4>
- <!--l. 29--><p class="noindent" >There are many approaches to understanding the type of 3D math used in video
- games, modelling, ray-tracing, etc. The usual is through vector algebra, matrices, and
- linear transformations and, while they are not completely necesary to understand
- most of the aspects of 3D game programming (from the theorical point of view), they
- provide a common language to communicate with other programmers or
- engineers.
- <!--l. 36--><p class="indent" > This tutorial will focus on explaining all the basic concepts needed for a
- programmer to understand how to develop 3D games without getting too deep into
- algebra. Instead of a math-oriented language, code examples will be given instead
- when possible. The reason for this is that. while programmers may have
- different backgrounds or experience (be it scientific, engineering or self taught),
- code is the most familiar language and the lowest common denominator for
- understanding.
- <!--l. 45--><p class="noindent" >
- <h4 class="subsectionHead"><span class="titlemark">1.2 </span> <a
- id="x1-30001.2"></a>Vectors</h4>
- <!--l. 48--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.2.1 </span> <a
- id="x1-40001.2.1"></a>Brief Introduction</h5>
- <!--l. 50--><p class="noindent" >When writing 2D games, interfaces and other applications, the typical convention is
- to define coordinates as an <span
- class="ecti-1000">x,y </span>pair, <span
- class="ecti-1000">x </span>representing the horizontal offset and <span
- class="ecti-1000">y </span>the
- vertical one. In most cases, the unit for both is <span
- class="ecti-1000">pixels</span>. This makes sense given the
- screen is just a rectangle in two dimensions.
- <!--l. 56--><p class="indent" > An <span
- class="ecti-1000">x,y </span>pair can be used for two purposes. It can be an absolute position (screen
- cordinate in the previous case), or a relative direction, if we trace an arrow from the
- origin (0,0 coordinates) to it’s position.
- <div class="center"
- >
- <!--l. 60--><p class="noindent" >
- <div class="tabular">
- <table id="TBL-1" class="tabular"
- cellspacing="0" cellpadding="0"
- ><colgroup id="TBL-1-1g"><col
- id="TBL-1-1"><col
- id="TBL-1-2"><col
- id="TBL-1-3"></colgroup><tr
- style="vertical-align:baseline;" id="TBL-1-1-"><td style="white-space:nowrap; text-align:center;" id="TBL-1-1-1"
- class="td11"><img
- src="tutorial0x.png" alt="PIC" class="graphics" width="100.375pt" height="100.375pt" ><!--tex4ht:graphics
- name="tutorial0x.png" src="0_home_red_coding_godot_doc_math_position.eps"
- --></td><td style="white-space:nowrap; text-align:center;" id="TBL-1-1-2"
- class="td11"></td><td style="white-space:nowrap; text-align:center;" id="TBL-1-1-3"
- class="td11"><img
- src="tutorial1x.png" alt="PIC" class="graphics" width="100.375pt" height="100.375pt" ><!--tex4ht:graphics
- name="tutorial1x.png" src="1_home_red_coding_godot_doc_math_direction.eps"
- --></td>
- </tr><tr
- style="vertical-align:baseline;" id="TBL-1-2-"><td style="white-space:nowrap; text-align:center;" id="TBL-1-2-1"
- class="td11"> <span
- class="ecti-0700">Position </span></td><td style="white-space:nowrap; text-align:center;" id="TBL-1-2-2"
- class="td11"></td><td style="white-space:nowrap; text-align:center;" id="TBL-1-2-3"
- class="td11"> <span
- class="ecti-0700">Direction </span></td>
- </tr><tr
- style="vertical-align:baseline;" id="TBL-1-3-"><td style="white-space:nowrap; text-align:center;" id="TBL-1-3-1"
- class="td11"> </td>
- </tr></table></div>
- </div>
- <!--l. 67--><p class="indent" > When used as a direction, this pair is called a <span
- class="ecti-1000">vector</span>, and two properties can be
- observed: The first is the <span
- class="ecti-1000">magnitude </span>or <span
- class="ecti-1000">length </span>, and the second is the direction. In
- two dimensions, direction can be an angle. The <span
- class="ecti-1000">magnitude </span>or <span
- class="ecti-1000">length </span>can be computed
- by simply using Pithagoras theorem:
- <div class="center"
- >
- <!--l. 73--><p class="noindent" >
- <div class="tabular"> <table id="TBL-2" class="tabular"
- cellspacing="0" cellpadding="0"
- ><colgroup id="TBL-2-1g"><col
- id="TBL-2-1"><col
- id="TBL-2-2"></colgroup><tr
- style="vertical-align:baseline;" id="TBL-2-1-"><td style="white-space:nowrap; text-align:center;" id="TBL-2-1-1"
- class="td11"><img
- src="tutorial2x.png" alt="∘x2-+-y2-" class="sqrt" ></td><td style="white-space:nowrap; text-align:center;" id="TBL-2-1-2"
- class="td11"><img
- src="tutorial3x.png" alt="∘x2-+-y2 +-z2" class="sqrt" ></td>
- </tr><tr
- style="vertical-align:baseline;" id="TBL-2-2-"><td style="white-space:nowrap; text-align:center;" id="TBL-2-2-1"
- class="td11"> <span
- class="ecti-0700">2D </span></td><td style="white-space:nowrap; text-align:center;" id="TBL-2-2-2"
- class="td11"> <span
- class="ecti-0700">3D </span></td>
- </tr><tr
- style="vertical-align:baseline;" id="TBL-2-3-"><td style="white-space:nowrap; text-align:center;" id="TBL-2-3-1"
- class="td11"> </td>
- </tr></table></div>
- </div>
- <!--l. 80--><p class="indent" > The direction can be an arbitrary angle from either the <span
- class="ecti-1000">x </span>or <span
- class="ecti-1000">y </span>axis, and could be
- computed by using trigonometry, or just using the usual <span
- class="ecti-1000">atan2 </span>function present in
- most math libraries. However, when dealing with 3D, the direction can’t be described
- as an angle. To separate magnitude and direction, 3D uses the concept of <span
- class="ecti-1000">normal</span>
- <span
- class="ecti-1000">vectors.</span>
- <!--l. 88--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.2.2 </span> <a
- id="x1-50001.2.2"></a>Implementation</h5>
- <!--l. 90--><p class="noindent" >Vectors are implemented in Godot Engine as a class named <span
- class="ecti-1000">Vector3 </span>for 3D, and as
- both <span
- class="ecti-1000">Vector2</span>, <span
- class="ecti-1000">Point2 </span>or <span
- class="ecti-1000">Size2 </span>in 2D (they are all aliases). They are used for any
- purpose where a pair of 2D or 3D values (described as <span
- class="ecti-1000">x,y </span>or <span
- class="ecti-1000">x,y,z) </span>is needed. This is
- somewhat a standard in most libraries or engines. In the script API, they can be
- instanced like this:
- <!--l. 98-->
- <div class="lstlisting"><span class="label"><a
- id="x1-5001r1"></a></span>a = Vector3() <br /><span class="label"><a
- id="x1-5002r2"></a></span>a = Vector2( 2.0, 3.4 )
- </div>
- <!--l. 104--><p class="indent" > Vectors also support the common operators <span
- class="ecti-1000">+, -, / and * </span>for addition,
- substraction, multiplication and division.
- <!--l. 108-->
- <div class="lstlisting"><span class="label"><a
- id="x1-5003r1"></a></span>a = Vector3(1,2,3) <br /><span class="label"><a
- id="x1-5004r2"></a></span>b = Vector3(4,5,6) <br /><span class="label"><a
- id="x1-5005r3"></a></span>c = Vector3() <br /><span class="label"><a
- id="x1-5006r4"></a></span> <br /><span class="label"><a
- id="x1-5007r5"></a></span>// writing <br /><span class="label"><a
- id="x1-5008r6"></a></span> <br /><span class="label"><a
- id="x1-5009r7"></a></span>c = a + b <br /><span class="label"><a
- id="x1-5010r8"></a></span> <br /><span class="label"><a
- id="x1-5011r9"></a></span>// is the same as writing <br /><span class="label"><a
- id="x1-5012r10"></a></span> <br /><span class="label"><a
- id="x1-5013r11"></a></span>c.x = a.x + b.x <br /><span class="label"><a
- id="x1-5014r12"></a></span>c.y = a.y + b.y <br /><span class="label"><a
- id="x1-5015r13"></a></span>c.z = a.z + b.z <br /><span class="label"><a
- id="x1-5016r14"></a></span> <br /><span class="label"><a
- id="x1-5017r15"></a></span>// both will result in a vector containing (5,7,9). <br /><span class="label"><a
- id="x1-5018r16"></a></span>// the same happens for the rest of the operators.
- </div>
- <!--l. 128--><p class="indent" > Vectors also can perform a wide variety of built-in functions, their most common
- usages will be explored next.
- <!--l. 132--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.2.3 </span> <a
- id="x1-60001.2.3"></a>Normal Vectors</h5>
- <!--l. 134--><p class="noindent" >Two points ago, it was mentioned that 3D vectors can’t describe their direction as an
- agle (as 2D vectors can). Because of this, <span
- class="ecti-1000">normal vectors </span>become important for
- separating a vector between <span
- class="ecti-1000">direction </span>and <span
- class="ecti-1000">magnitude.</span>
- <!--l. 139--><p class="indent" > A <span
- class="ecti-1000">normal vector </span>is a vector with a <span
- class="ecti-1000">magnitude </span>of <span
- class="ecti-1000">1. </span>This means, no matter where
- the vector is pointing to, it’s length is always <span
- class="ecti-1000">1</span>.
- <div class="tabular">
- <table id="TBL-3" class="tabular"
- cellspacing="0" cellpadding="0"
- ><colgroup id="TBL-3-1g"><col
- id="TBL-3-1"></colgroup><tr
- style="vertical-align:baseline;" id="TBL-3-1-"><td style="white-space:nowrap; text-align:center;" id="TBL-3-1-1"
- class="td11"><img
- src="tutorial4x.png" alt="PIC" class="graphics" width="100.375pt" height="100.375pt" ><!--tex4ht:graphics
- name="tutorial4x.png" src="2_home_red_coding_godot_doc_math_normals.eps"
- --></td>
- </tr><tr
- style="vertical-align:baseline;" id="TBL-3-2-"><td style="white-space:nowrap; text-align:center;" id="TBL-3-2-1"
- class="td11"> <span
- class="ecrm-0700">Normal vectors aroud the origin. </span></td>
- </tr><tr
- style="vertical-align:baseline;" id="TBL-3-3-"><td style="white-space:nowrap; text-align:center;" id="TBL-3-3-1"
- class="td11"> </td> </tr></table>
- </div>
- <!--l. 148--><p class="indent" > Normal vectors have endless uses in 3D graphics programming, so it’s
- recommended to get familiar with them as much as possible.
- <!--l. 152--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.2.4 </span> <a
- id="x1-70001.2.4"></a>Normalization</h5>
- <!--l. 154--><p class="noindent" >Normalization is the process through which normal vectors are obtained
- from regular vectors. In other words, normalization is used to reduce the
- <span
- class="ecti-1000">magnitude </span>of any vector to <span
- class="ecti-1000">1</span>. (except of course, unless the vector is (0,0,0)
- ).
- <!--l. 159--><p class="indent" > To normalize a vector, it must be divided by its magnitude (which should be
- greater than zero):
- <!--l. 163-->
- <div class="lstlisting"><span class="label"><a
- id="x1-7001r1"></a></span><span
- class="ecti-1000">//</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">a</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">custom</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">vector</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">is</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">created</span> <br /><span class="label"><a
- id="x1-7002r2"></a></span>a = Vector3(4,5,6) <br /><span class="label"><a
- id="x1-7003r3"></a></span><span
- class="ecti-1000">//</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">’</span><span
- class="ecti-1000">l</span><span
- class="ecti-1000">’</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">is</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">a</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">single</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">real</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">number</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">(</span><span
- class="ecti-1000">or</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">scalar</span><span
- class="ecti-1000">)</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">containight</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">the</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">length</span> <br /><span class="label"><a
- id="x1-7004r4"></a></span>l = Math.sqrt( a.x<span
- class="cmsy-10">*</span>a.x + a.y<span
- class="cmsy-10">*</span>a.y + a.z<span
- class="cmsy-10">*</span>a.z ) <br /><span class="label"><a
- id="x1-7005r5"></a></span><span
- class="ecti-1000">//</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">the</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">vector</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">’</span><span
- class="ecti-1000">a</span><span
- class="ecti-1000">’</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">is</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">divided</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">by</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">its</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">length</span><span
- class="ecti-1000">,</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">by</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">performing</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">scalar</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">divide</span> <br /><span class="label"><a
- id="x1-7006r6"></a></span>a = a / l <br /><span class="label"><a
- id="x1-7007r7"></a></span><span
- class="ecti-1000">//</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">which</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">is</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">the</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">same</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">as</span> <br /><span class="label"><a
- id="x1-7008r8"></a></span>a.x = a.x / l <br /><span class="label"><a
- id="x1-7009r9"></a></span>a.y = a.y / l <br /><span class="label"><a
- id="x1-7010r10"></a></span>a.z = a.z / l
- </div>
- <!--l. 177--><p class="indent" > Vector3 contains two built in functions for normalization:
- <!--l. 180-->
- <div class="lstlisting"><span class="label"><a
- id="x1-7011r1"></a></span>a = Vector3(4,5,6) <br /><span class="label"><a
- id="x1-7012r2"></a></span>a.normalize() <span
- class="ecti-1000">//</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">in</span><span
- class="cmsy-10">-</span><span
- class="ecti-1000">place</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">normalization</span> <br /><span class="label"><a
- id="x1-7013r3"></a></span>b = a.normalized() <span
- class="ecti-1000">//</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">returns</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">a</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">copy</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">of</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">a</span><span
- class="ecti-1000">,</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">normalized</span>
- </div>
- <!--l. 188--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.2.5 </span> <a
- id="x1-80001.2.5"></a>Dot Product</h5>
- <!--l. 190--><p class="noindent" >The dot product is, pheraps, the most useful operation that can be applied to 3D
- vectors. In the surface, it’s multiple usages are not very obvious, but in depth it can
- provide very useful information between two vectors (be it direction or just points in
- space).
- <!--l. 195--><p class="indent" > The dot product takes two vectors (<span
- class="ecti-1000">a </span>and <span
- class="ecti-1000">b </span>in the example) and returns a scalar
- (single real number):
- <div class="center"
- >
- <!--l. 198--><p class="noindent" >
- <!--l. 199--><p class="noindent" ><span
- class="cmmi-10">a</span><sub><span
- class="cmmi-7">x</span></sub><span
- class="cmmi-10">b</span><sub><span
- class="cmmi-7">x</span></sub> <span
- class="cmr-10">+ </span><span
- class="cmmi-10">a</span><sub><span
- class="cmmi-7">y</span></sub><span
- class="cmmi-10">b</span><sub><span
- class="cmmi-7">y</span></sub> <span
- class="cmr-10">+ </span><span
- class="cmmi-10">a</span><sub><span
- class="cmmi-7">z</span></sub><span
- class="cmmi-10">b</span><sub><span
- class="cmmi-7">z</span></sub>
- </div>
- <!--l. 202--><p class="indent" > The same expressed in code:
- <!--l. 205-->
- <div class="lstlisting"><span class="label"><a
- id="x1-8001r1"></a></span>a = Vector3(...) <br /><span class="label"><a
- id="x1-8002r2"></a></span>b = Vector3(...) <br /><span class="label"><a
- id="x1-8003r3"></a></span> <br /><span class="label"><a
- id="x1-8004r4"></a></span>c = a.x<span
- class="cmsy-10">*</span>b.x + a.y<span
- class="cmsy-10">*</span>b.y + a.z<span
- class="cmsy-10">*</span>b.z <br /><span class="label"><a
- id="x1-8005r5"></a></span> <br /><span class="label"><a
- id="x1-8006r6"></a></span><span
- class="ecti-1000">//</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">using</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">built</span><span
- class="cmsy-10">-</span><span
- class="ecti-1000">in</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">dot</span><span
- class="ecti-1000">()</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">function</span> <br /><span class="label"><a
- id="x1-8007r7"></a></span> <br /><span class="label"><a
- id="x1-8008r8"></a></span>c = a.dot(b)
- </div>
- <!--l. 218--><p class="indent" > The dot product presents several useful properties:
- <ul class="itemize1">
- <li class="itemize">If both <span
- class="ecti-1000">a </span>and <span
- class="ecti-1000">b </span>parameters to a <span
- class="ecti-1000">dot product </span>are direction vectors, dot
- product will return positive if both point towards the same direction,
- negative if both point towards opposite directions, and zero if they are
- orthogonal (one is perpendicular to the other).
- </li>
- <li class="itemize">If both <span
- class="ecti-1000">a </span>and <span
- class="ecti-1000">b </span>parameters to a <span
- class="ecti-1000">dot product </span>are <span
- class="ecti-1000">normalized </span>direction
- vectors, then the dot product will return the cosine of the angle between
- them (ranging from 1 if they are equal, 0 if they are orthogonal, and -1 if
- they are opposed (a == -b)).
- </li>
- <li class="itemize">If <span
- class="ecti-1000">a </span>is a <span
- class="ecti-1000">normalized </span>direction vector and <span
- class="ecti-1000">b </span>is a point, the dot product will
- return the distance from <span
- class="ecti-1000">b </span>to the plane passing through the origin, with
- normal <span
- class="ecti-1000">a (see item about planes)</span>
- </li>
- <li class="itemize">More uses will be presented later in this tutorial.</li></ul>
- <!--l. 236--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.2.6 </span> <a
- id="x1-90001.2.6"></a>Cross Product</h5>
- <!--l. 238--><p class="noindent" >The <span
- class="ecti-1000">cross product </span>also takes two vectors <span
- class="ecti-1000">a </span>and <span
- class="ecti-1000">b</span>, but returns another vector <span
- class="ecti-1000">c </span>that is
- orthogonal to the two previous ones.
- <div class="center"
- >
- <!--l. 242--><p class="noindent" >
- <!--l. 243--><p class="noindent" ><span
- class="cmmi-10">c</span><sub><span
- class="cmmi-7">x</span></sub> <span
- class="cmr-10">= </span><span
- class="cmmi-10">a</span><sub><span
- class="cmmi-7">x</span></sub><span
- class="cmmi-10">b</span><sub><span
- class="cmmi-7">z</span></sub> <span
- class="cmsy-10">- </span><span
- class="cmmi-10">a</span><sub><span
- class="cmmi-7">z</span></sub><span
- class="cmmi-10">b</span><sub><span
- class="cmmi-7">y</span></sub>
- </div>
- <div class="center"
- >
- <!--l. 246--><p class="noindent" >
- <!--l. 247--><p class="noindent" ><span
- class="cmmi-10">c</span><sub><span
- class="cmmi-7">y</span></sub> <span
- class="cmr-10">= </span><span
- class="cmmi-10">a</span><sub><span
- class="cmmi-7">z</span></sub><span
- class="cmmi-10">b</span><sub><span
- class="cmmi-7">x</span></sub> <span
- class="cmsy-10">- </span><span
- class="cmmi-10">a</span><sub><span
- class="cmmi-7">x</span></sub><span
- class="cmmi-10">b</span><sub><span
- class="cmmi-7">z</span></sub>
- </div>
- <div class="center"
- >
- <!--l. 250--><p class="noindent" >
- <!--l. 251--><p class="noindent" ><span
- class="cmmi-10">c</span><sub><span
- class="cmmi-7">z</span></sub> <span
- class="cmr-10">= </span><span
- class="cmmi-10">a</span><sub><span
- class="cmmi-7">x</span></sub><span
- class="cmmi-10">b</span><sub><span
- class="cmmi-7">y</span></sub> <span
- class="cmsy-10">- </span><span
- class="cmmi-10">a</span><sub><span
- class="cmmi-7">y</span></sub><span
- class="cmmi-10">b</span><sub><span
- class="cmmi-7">x</span></sub>
- </div>
- <!--l. 254--><p class="indent" > The same in code:
- <!--l. 257-->
- <div class="lstlisting"><span class="label"><a
- id="x1-9001r1"></a></span>a = Vector3(...) <br /><span class="label"><a
- id="x1-9002r2"></a></span>b = Vector3(...) <br /><span class="label"><a
- id="x1-9003r3"></a></span>c = Vector3(...) <br /><span class="label"><a
- id="x1-9004r4"></a></span> <br /><span class="label"><a
- id="x1-9005r5"></a></span>c.x = a.x<span
- class="cmsy-10">*</span>b.z <span
- class="cmsy-10">-</span> a.z<span
- class="cmsy-10">*</span>b.y <br /><span class="label"><a
- id="x1-9006r6"></a></span>c.y = a.z<span
- class="cmsy-10">*</span>b.x <span
- class="cmsy-10">-</span> a.x<span
- class="cmsy-10">*</span>b.z <br /><span class="label"><a
- id="x1-9007r7"></a></span>c.z = a.x<span
- class="cmsy-10">*</span>b.y <span
- class="cmsy-10">-</span> a.y<span
- class="cmsy-10">*</span>b.x <br /><span class="label"><a
- id="x1-9008r8"></a></span> <br /><span class="label"><a
- id="x1-9009r9"></a></span>// or using the built<span
- class="cmsy-10">-</span>in function <br /><span class="label"><a
- id="x1-9010r10"></a></span> <br /><span class="label"><a
- id="x1-9011r11"></a></span>c = a.cross(b)
- </div>
- <!--l. 273--><p class="indent" > The <span
- class="ecti-1000">cross product </span>also presents several useful properties:
- <ul class="itemize1">
- <li class="itemize">As mentioned, the resulting vector <span
- class="ecti-1000">c </span>is orthogonal to the input vectors <span
- class="ecti-1000">a</span>
- and <span
- class="ecti-1000">b.</span>
- </li>
- <li class="itemize">Since the <span
- class="ecti-1000">cross product </span>is anticommutative, swapping <span
- class="ecti-1000">a </span>and <span
- class="ecti-1000">b </span>will result
- in a negated vector <span
- class="ecti-1000">c.</span>
- </li>
- <li class="itemize">if <span
- class="ecti-1000">a </span>and <span
- class="ecti-1000">b </span>are taken from two of the segmets <span
- class="ecti-1000">AB</span>, <span
- class="ecti-1000">BC </span>or <span
- class="ecti-1000">CA </span>that form a
- 3D triangle, the magnitude of the resulting vector divided by 2 is the area
- of that triangle.
- </li>
- <li class="itemize">The direction of the resulting vector <span
- class="ecti-1000">c </span>in the previous triangle example
- determines wether the points A,B and C are arranged in clocwise or
- counter-clockwise order.</li></ul>
- <!--l. 287--><p class="noindent" >
- <h4 class="subsectionHead"><span class="titlemark">1.3 </span> <a
- id="x1-100001.3"></a>Plane</h4>
- <!--l. 290--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.3.1 </span> <a
- id="x1-110001.3.1"></a>Theory</h5>
- <!--l. 292--><p class="noindent" >A plane can be considered as an infinite, flat surface that splits space in two halves,
- usually one named positive and one named negative. In regular mathematics, a plane
- formula is described as:
- <div class="center"
- >
- <!--l. 296--><p class="noindent" >
- <!--l. 297--><p class="noindent" ><span
- class="cmmi-10">ax </span><span
- class="cmr-10">+ </span><span
- class="cmmi-10">by </span><span
- class="cmr-10">+ </span><span
- class="cmmi-10">cz </span><span
- class="cmr-10">+ </span><span
- class="cmmi-10">d</span>
- </div>
- <!--l. 300--><p class="indent" > However, in 3D programming, this form alone is often of little use. For planes to
- become useful, they must be in normalized form.
- <!--l. 303--><p class="indent" > A normalized plane consists of a <span
- class="ecti-1000">normal vector n </span>and a <span
- class="ecti-1000">distance d. </span>To normalize
- a plane, a vector <span
- class="ecti-1000">n </span>and distance <span
- class="ecti-1000">d’ </span>are created this way:
- <!--l. 307--><p class="indent" > <span
- class="cmmi-10">n</span><sub><span
- class="cmmi-7">x</span></sub> <span
- class="cmr-10">= </span><span
- class="cmmi-10">a</span>
- <!--l. 309--><p class="indent" > <span
- class="cmmi-10">n</span><sub><span
- class="cmmi-7">y</span></sub> <span
- class="cmr-10">= </span><span
- class="cmmi-10">b</span>
- <!--l. 311--><p class="indent" > <span
- class="cmmi-10">n</span><sub><span
- class="cmmi-7">z</span></sub> <span
- class="cmr-10">= </span><span
- class="cmmi-10">c</span>
- <!--l. 313--><p class="indent" > <span
- class="cmmi-10">d</span><span
- class="cmsy-10">′ </span><span
- class="cmr-10">= </span><span
- class="cmmi-10">d</span>
- <!--l. 315--><p class="indent" > Finally, both <span
- class="ecti-1000">n </span>and <span
- class="ecti-1000">d’ </span>are both divided by the magnitude of n.
- <!--l. 318--><p class="indent" > In any case, normalizing planes is not often needed (this was mostly for
- explanation purposes), and normalized planes are useful because they can be created
- and used easily.
- <!--l. 322--><p class="indent" > A normalized plane could be visualized as a plane pointing towards normal <span
- class="ecti-1000">n,</span>
- offseted by <span
- class="ecti-1000">d </span>in the direction of <span
- class="ecti-1000">n</span>.
- <!--l. 325--><p class="indent" > In other words, take <span
- class="ecti-1000">n</span>, multiply it by scalar <span
- class="ecti-1000">d </span>and the resulting point will be part
- of the plane. This may need some thinking, so an example with a 2D normal vector
- (z is 0, so plane is orthogonal to it) is provided:
- <!--l. 330--><p class="indent" > Some operations can be done with normalized planes:
- <ul class="itemize1">
- <li class="itemize">Given any point <span
- class="ecti-1000">p</span>, the distance from it to a plane can be computed by
- doing: n.dot(p) - d
- </li>
- <li class="itemize">If the resulting distance in the previous point is negative, the point is
- below the plane.
- </li>
- <li class="itemize">Convex polygonal shapes can be defined by enclosing them in planes (the
- physics engine uses this property)</li></ul>
- <!--l. 340--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.3.2 </span> <a
- id="x1-120001.3.2"></a>Implementation</h5>
- <!--l. 342--><p class="noindent" >Godot Engine implements normalized planes by using the <span
- class="ecti-1000">Plane </span>class.
- <!--l. 346-->
- <div class="lstlisting"><span class="label"><a
- id="x1-12001r1"></a></span>//creates a plane with normal (0,1,0) and distance 5 <br /><span class="label"><a
- id="x1-12002r2"></a></span>p = Plane( Vector3(0,1,0), 5 ) <br /><span class="label"><a
- id="x1-12003r3"></a></span>// get the distance to a point <br /><span class="label"><a
- id="x1-12004r4"></a></span>d = p.distance( Vector3(4,5,6) )
- </div>
- <!--l. 355--><p class="noindent" >
- <h4 class="subsectionHead"><span class="titlemark">1.4 </span> <a
- id="x1-130001.4"></a>Matrices, Quaternions and Coordinate Systems</h4>
- <!--l. 357--><p class="noindent" >It is very often needed to store the location/rotation of something. In 2D, it is often
- enough to store an <span
- class="ecti-1000">x,y </span>location and maybe an angle as the rotation, as that should
- be enough to represent any posible position.
- <!--l. 362--><p class="indent" > In 3D this becomes a little more difficult, as there is nothing as simple as an angle
- to store a 3-axis rotation.
- <!--l. 365--><p class="indent" > The first think that may come to mind is to use 3 angles, one for x, one for y and
- one for z. However this suffers from the problem that it becomes very cumbersome to
- use, as the individual rotations in each axis need to be performed one after another
- (they can’t be performed at the same time), leading to a problem called “gimbal
- lock”. Also, it becomes impossible to accumulate rotations (add a rotation to an
- existing one).
- <!--l. 373--><p class="indent" > To solve this, there are two known diferent approaches that aid in solving
- rotation, <span
- class="ecti-1000">Quaternions </span>and <span
- class="ecti-1000">Oriented Coordinate Systems.</span>
- <!--l. 378--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.4.1 </span> <a
- id="x1-140001.4.1"></a>Oriented Coordinate Systems</h5>
- <!--l. 380--><p class="noindent" ><span
- class="ecti-1000">Oriented Coordinate Systems </span>(<span
- class="ecti-1000">OCS</span>) are a way of representing a coordinate system
- inside the cartesian coordinate system. They are mainly composed of 3 Vectors, one
- for each axis. The first vector is the <span
- class="ecti-1000">x </span>axis, the second the <span
- class="ecti-1000">y </span>axis, and the third is the
- <span
- class="ecti-1000">z </span>axis. The OCS vectors can be rotated around freely as long as they are kept the
- same length (as changing the length of an axis changes its cale), and as long as they
- remain orthogonal to eachother (as in, the same as the default cartesian system,
- with <span
- class="ecti-1000">y </span>pointing up, <span
- class="ecti-1000">x </span>pointing left and <span
- class="ecti-1000">z </span>pointing front, but all rotated
- together).
- <!--l. 391--><p class="indent" > <span
- class="ecti-1000">Oriented Coordinate Systems </span>are represented in 3D programming as a 3x3 matrix,
- where each row (or column, depending on the implementation) contains one of the
- axis vectors. Transforming a Vector by a rotated OCS Matrix results in the rotation
- being applied to the resulting vector. OCS Matrices can also be multiplied to
- accumulate their transformations.
- <!--l. 397--><p class="indent" > Godot Engine implements OCS Matrices in the <span
- class="ecti-1000">Matrix3 </span>class:
- <!--l. 400-->
- <div class="lstlisting"><span class="label"><a
- id="x1-14001r1"></a></span><span
- class="ecti-1000">//</span><span
- class="ecti-1000">create</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">a</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">3</span><span
- class="ecti-1000">x3</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">matrix</span> <br /><span class="label"><a
- id="x1-14002r2"></a></span>m = Matrix3() <br /><span class="label"><a
- id="x1-14003r3"></a></span><span
- class="ecti-1000">//</span><span
- class="ecti-1000">rotate</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">the</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">matrix</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">in</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">the</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">y</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">axis</span><span
- class="ecti-1000">,</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">by</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">45</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">degrees</span> <br /><span class="label"><a
- id="x1-14004r4"></a></span>m.rotate( Vector3(0,1,0), Math.deg2rad(45) ) <br /><span class="label"><a
- id="x1-14005r5"></a></span><span
- class="ecti-1000">//</span><span
- class="ecti-1000">transform</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">a</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">vector</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">v</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">(</span><span
- class="ecti-1000">xform</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">method</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">is</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">used</span><span
- class="ecti-1000">)</span> <br /><span class="label"><a
- id="x1-14006r6"></a></span>v = Vector3(...) <br /><span class="label"><a
- id="x1-14007r7"></a></span>result = m.xform( v )
- </div>
- <!--l. 412--><p class="indent" > However, in most usage cases, one wants to store a translation together with the
- rotation. For this, an <span
- class="ecti-1000">origin </span>vector must be added to the OCS, thus transforming it
- into a 3x4 (or 4x3, depending on preference) matrix. Godot engine implements this
- functionality in the <span
- class="ecti-1000">Transform </span>class:
- <!--l. 419-->
- <div class="lstlisting"><span class="label"><a
- id="x1-14010r1"></a></span>t = Transform() <br /><span class="label"><a
- id="x1-14011r2"></a></span>//rotate the transform in the y axis, by 45 degrees <br /><span class="label"><a
- id="x1-14012r3"></a></span>t.rotate( Vector3(0,1,0), Math.deg2rad(45) ) <br /><span class="label"><a
- id="x1-14013r4"></a></span>//translate the transform by 5 in the z axis <br /><span class="label"><a
- id="x1-14014r5"></a></span>t.translate( Vector3( 0,0,5 ) ) <br /><span class="label"><a
- id="x1-14015r6"></a></span>//transform a vector v (xform method is used) <br /><span class="label"><a
- id="x1-14016r7"></a></span>v = Vector3(...) <br /><span class="label"><a
- id="x1-14017r8"></a></span>result = t.xform( v )
- </div>
- <!--l. 431--><p class="indent" > Transform contains internally a Matrix3 “basis” and a Vector3 “origin” (which can
- be modified individually).
- <!--l. 435--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.4.2 </span> <a
- id="x1-150001.4.2"></a>Transform Internals</h5>
- <!--l. 437--><p class="noindent" >Internally, the xform() process is quite simple, to apply a 3x3 transform to a vector,
- the transposed axis vectors are used (as using the regular axis vectors will result on
- an inverse of the desired transform):
- <!--l. 442-->
- <div class="lstlisting"><span class="label"><a
- id="x1-15001r1"></a></span>m = Matrix3(...) <br /><span class="label"><a
- id="x1-15002r2"></a></span>v = Vector3(..) <br /><span class="label"><a
- id="x1-15003r3"></a></span>result = Vector3(...) <br /><span class="label"><a
- id="x1-15004r4"></a></span> <br /><span class="label"><a
- id="x1-15005r5"></a></span>x_axis = m.get_axis(0) <br /><span class="label"><a
- id="x1-15006r6"></a></span>y_axis = m.get_axis(1) <br /><span class="label"><a
- id="x1-15007r7"></a></span>z_axis = m.get_axis(2) <br /><span class="label"><a
- id="x1-15008r8"></a></span> <br /><span class="label"><a
- id="x1-15009r9"></a></span>result.x = Vector3(x_axis.x, y_axis.x, z_axis.x).dot(v) <br /><span class="label"><a
- id="x1-15010r10"></a></span>result.y = Vector3(x_axis.y, y_axis.y, z_axis.y).dot(v) <br /><span class="label"><a
- id="x1-15011r11"></a></span>result.z = Vector3(x_axis.z, y_axis.z, z_axis.z).dot(v) <br /><span class="label"><a
- id="x1-15012r12"></a></span> <br /><span class="label"><a
- id="x1-15013r13"></a></span>// is the same as doing <br /><span class="label"><a
- id="x1-15014r14"></a></span> <br /><span class="label"><a
- id="x1-15015r15"></a></span>result = m.xform(v) <br /><span class="label"><a
- id="x1-15016r16"></a></span> <br /><span class="label"><a
- id="x1-15017r17"></a></span>// if m this was a Transform(), the origin would be added <br /><span class="label"><a
- id="x1-15018r18"></a></span>// like this: <br /><span class="label"><a
- id="x1-15019r19"></a></span> <br /><span class="label"><a
- id="x1-15020r20"></a></span>result = result + t.get_origin()
- </div>
- <!--l. 468--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.4.3 </span> <a
- id="x1-160001.4.3"></a>Using The Transform</h5>
- <!--l. 470--><p class="noindent" >So, it is often desired apply sucessive operations to a transformation. For example,
- let’s a assume that there is a turtle sitting at the origin (the turtle is a logo reference,
- for those familiar with it). The <span
- class="ecti-1000">y </span>axis is up, and the the turtle’s nose is pointing
- towards the <span
- class="ecti-1000">z </span>axis.
- <!--l. 476--><p class="indent" > The turtle (like many other animals, or vehicles!) can only walk towards the
- direction it’s looking at. So, moving the turtle around a little should be something
- like this:
- <!--l. 481-->
- <div class="lstlisting"><span class="label"><a
- id="x1-16001r1"></a></span><span
- class="ecti-1000">//</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">turtle</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">at</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">the</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">origin</span> <br /><span class="label"><a
- id="x1-16002r2"></a></span>turtle = Transform() <br /><span class="label"><a
- id="x1-16003r3"></a></span><span
- class="ecti-1000">//</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">turtle</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">will</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">walk</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">5</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">units</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">in</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">z</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">axis</span> <br /><span class="label"><a
- id="x1-16004r4"></a></span>turtle.translate( Vector3(0,0,5) ) <br /><span class="label"><a
- id="x1-16005r5"></a></span><span
- class="ecti-1000">//</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">turtle</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">eyes</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">a</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">lettuce</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">3</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">units</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">away</span><span
- class="ecti-1000">,</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">will</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">rotate</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">45</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">degrees</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">right</span> <br /><span class="label"><a
- id="x1-16006r6"></a></span>turtle.rotate( Vector3(0,1,0), Math.deg2rad(45) ) <br /><span class="label"><a
- id="x1-16007r7"></a></span><span
- class="ecti-1000">//</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">turtle</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">approaches</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">the</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">lettuce</span> <br /><span class="label"><a
- id="x1-16008r8"></a></span>turtle.translate( Vector3(0,0,5) ) <br /><span class="label"><a
- id="x1-16009r9"></a></span><span
- class="ecti-1000">//</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">happy</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">turtle</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">over</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">lettuce</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">is</span><span
- class="ecti-1000"> </span><span
- class="ecti-1000">at</span> <br /><span class="label"><a
- id="x1-16010r10"></a></span>print(turtle.get_origin())
- </div>
- <!--l. 496--><p class="indent" > As can be seen, every new action the turtle takes is based on the previous one it
- took. Had the order of actions been different and the turtle would have never reached
- the lettuce.
- <!--l. 500--><p class="indent" > Transforms are just that, a mean of “accumulating” rotation, translation, scale,
- etc.
- <!--l. 504--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.4.4 </span> <a
- id="x1-170001.4.4"></a>A Warning about Numerical Precision</h5>
- <!--l. 506--><p class="noindent" >Performing several actions over a transform will slowly and gradually lead to
- precision loss (objects that draw according to a transform may get jittery, bigger,
- smaller, skewed, etc). This happens due to the nature of floating point numbers. if
- transforms/matrices are created from other kind of values (like a position and
- some angular rotation) this is not needed, but if has been accumulating
- transformations and was never recreated, it can be normalized by calling the
- .orthonormalize() built-in function. This function has little cost and calling it every
- now and then will avoid the effects from precision loss to become visible.
-
- </body></html>
|