<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
	<title>Math and Physics - Articles</title>
	<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/</link>
	<pubDate>Sat, 25 Feb 2012 22:47:35 +0000</pubDate>
	<ttl>43200</ttl>
	<description>Resources for mathematics and physics that relate to game development, including collisions and algorithms</description>
	<item>
		<title>A Verlet based approach for 2D game physics</title>
		<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/a-verlet-based-approach-for-2d-game-physics-r2714</link>
		<description><![CDATA[<span style='font-size: 18px;'> <strong class='bbc'>Introduction</strong></span><br />
<br />
The purpose of this article is to describe a way to simulate game physics in two dimensions. We will use an approach known as Verlet integration, go over the basics of moving points and building shapes to topics like collision detection and response. The reader should know the basics of vector maths, meaning addition, subtraction, multiplication with a scalar and the dot product. More than that is not required, however, for deeper understanding more knowledge of Euclidean geometry in two dimensions wouldn't hurt.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Verlet integration</strong></span><br />
<br />
First of all, what is Verlet integration? The Verlet integration is a way of numerically integrating the equations of motion. For this article, you really don't have to know what numerical integration means; basically, the Verlet integration describes the movement of a point trough time. There are different methods to do that - I guess, most of you know the Euler method:<br />
<br />
 <a class='resized_img' rel='lightbox[fd542985689b454489faca5d169bdd73]' id='ipb-attach-url-5793-0-77983500-1330210055' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=5793" title="Formula1.png - Size: 2.72K, Downloads: 71"><img src="http://public.gamedev.net/uploads/monthly_10_2011/ccs-8549-0-28695500-1319079808_thumb.png" id='ipb-attach-img-5793-0-77983500-1330210055' style='width:250;height:37' class='attach' width="250" height="37" alt="Attached Image: Formula1.png" /></a><br />
<br />
 If we merge these two equations into one, meaning we substitute the Velocity<sub class='bbc'>New</sub> in the second equation by the right hand side of the first equation, we get:<br />
<br />
 <a class='resized_img' rel='lightbox[fd542985689b454489faca5d169bdd73]' id='ipb-attach-url-5794-0-78047400-1330210055' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=5794" title="Formula2.png - Size: 2.27K, Downloads: 107"><img src="http://public.gamedev.net/uploads/monthly_10_2011/ccs-8549-0-26889700-1319079869_thumb.png" id='ipb-attach-img-5794-0-78047400-1330210055' style='width:250;height:18' class='attach' width="250" height="18" alt="Attached Image: Formula2.png" /></a><br />
<br />
 There are different types of Verlet integration methods - Position Verlet, Velocity Verlet and Leapfrog. For this article, we will choose the position version, because it has some nice features that we're going to take advantage of.<br />
<br />
 The corresponding equation for position Verlet is actually not much different from the one shown above:<br />
<br />
 <a class='resized_img' rel='lightbox[fd542985689b454489faca5d169bdd73]' id='ipb-attach-url-5795-0-78063000-1330210055' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=5795" title="Formula3.png - Size: 3.01K, Downloads: 110"><img src="http://public.gamedev.net/uploads/monthly_10_2011/ccs-8549-0-06022000-1319079902_thumb.png" id='ipb-attach-img-5795-0-78063000-1330210055' style='width:250;height:24' class='attach' width="250" height="24" alt="Attached Image: Formula3.png" /></a><br />
<br />
 As we can see now, the term (Position<sub class='bbc'>Current</sub> – Position<sub class='bbc'>Old</sub>) in the Verlet equation replaces the velocity if we compare it with the Euler approach. Consequently, this means that this approach doesn't deal with velocities at all - one thing less to worry about. This integration method is not always quite accurate, since (Position<sub class='bbc'>Current</sub> – Position<sub class='bbc'>Old</sub>) is only an approximation of the actual velocity. However, it's fast and stable, which is why it is well suited for games. Also, using this approach the collision response gets really simple. Let us consider a point as shown in figure 1.<br />
<br />
<p class='bbc_center'>  <a class='resized_img' rel='lightbox[fd542985689b454489faca5d169bdd73]' id='ipb-attach-url-5796-0-78080400-1330210055' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=5796" title="Figure1.png - Size: 1.39K, Downloads: 109"><img src="http://public.gamedev.net/uploads/monthly_10_2011/ccs-8549-0-63486300-1319079930_thumb.png" id='ipb-attach-img-5796-0-78080400-1330210055' style='width:250;height:167' class='attach' width="250" height="167" alt="Attached Image: Figure1.png" /></a><br />
</p><br />
  The starting conditions for Position<sub class='bbc'>Old</sub> and Position<sub class='bbc'>Current</sub> are chosen such that the point moves slowly to the right. After a certain amount of time steps, the point will intersect with the square on the right. Once the collision is detected, we only have to move the point out of the square and we are done with the collision response. Since the integration uses (Position<sub class='bbc'>Current</sub> – Position<sub class='bbc'>Old</sub>) as its velocity, the speed of the point will subsequently change if we change either CurrentPosition or OldPosition - which is what we did in the collision response (we moved the point out of the square). As we can see in figure 2, the point will automatically decelerate and eventually stop.<br />
<br />
<p class='bbc_center'>  <a class='resized_img' rel='lightbox[fd542985689b454489faca5d169bdd73]' id='ipb-attach-url-5797-0-78095600-1330210055' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=5797" title="Figure2.png - Size: 5.99K, Downloads: 71"><img src="http://public.gamedev.net/uploads/monthly_10_2011/ccs-8549-0-73570500-1319079959_thumb.png" id='ipb-attach-img-5797-0-78095600-1330210055' style='width:250;height:100' class='attach' width="250" height="100" alt="Attached Image: Figure2.png" /></a><br />
</p><br />
  If we put the formula above in code, we get something like this (assuming you have a working vector-class, that is):<br />
<br />
<pre class='prettyprint'>struct Point {<br />  Vec2 Position;<br />  Vec2 OldPosition;<br />  Vec2 Acceleration;<br />};<br /><br />class Physics {<br />  int PointCount;<br />  Point* Points&#91; MAX_VERTICES &#93;;<br /><br />  float Timestep;<br /><br />public:<br />  void  UpdateVerlet();<br /><br />  //Constructors, getters/setters etc. omitted<br />};<br /><br />void Physics::UpdateVerlet() {<br />  for( int I = 0; I &lt; PointCount; I++ ) {<br />    Point& P = *Points&#91; I &#93;;<br /><br />    Vec2 Temp = P.Position;<br />    P.Position += P.Position - P.OldPosition + P.Acceleration*Timestep*Timestep;<br />    P.OldPosition = Temp;<br />  }<br />}</pre>Now we have a working physics code that will calculate the trajectories of arbitrary points just fine. But points alone are not very useful, except when you're programming a particle simulation. Since that's normally not the case if you're into game programming, we have to extend the points in some way so we can simulate rigid body behaviour as well. If we look at rigid bodies in nature, we see that they are actually a huge amount of points (=atoms) held together by various forces. <br />
<br />
We could of course try and create thousands of particles and connect them in some way to approximate the behaviour of rigid bodies, which would work indeed. However, that would cause a huge amount of calculations to be done for e.g. a single cube, let alone a whole game filled with physics bodies, so this isn't really an optimal solution. Luckily, it shows to be sufficient only to model the vertices of a body. If we were to simulate a box, we would simply create the four vertices that make up the shape of a box, connect them somehow and we're done.<br />
<br />
 The problem left to compute is now only that of the connections. If we again imagine a box and the four vertices, it should become clear that the distance of a vertex to another should always remain constant. If the distance between two vertices changes, this always means that the shape of the body gets deformed, and we don't want that - who would like to have a crate in his game that collapses once you stand on it? Therefore, we have to find a way to keep the distance between two vertices at a constant value.<br />
<br />
 If we had the same problem in reality, the solution would be simple - just insert some kind of pole in-between and the vertices won't approach each other anymore. We will do the exact same thing in our program; create a new class that represents an 'imaginary pole'. It connects two vertices and keeps those vertices at a constant distance. The algorithm to update these 'poles' is called once the Verlet is calculated. The algorithm itself is actually quite simple. First of all, we have to calculate the vector between the two vertices that are connected by the pole. The current distance between the two vertices is simply the length of that vector. Once we have the current length, the difference of the original length of the pole should be calculated. We can now use the difference to push the vertices to a position where the distance constraint is satisfied.<br />
<br />
<pre class='prettyprint'>struct Edge {<br />  Vertex* V1;<br />  Vertex* V2;<br /><br />  float OriginalLength; //The length of the edge when it was created<br /><br />  //Constructors etc. omitted<br />};<br /><br />void Physics::UpdateEdges() {<br />  for( int I = 0; I &lt; EdgeCount; I++ ) {<br />    Edge& E = *Edges&#91; I &#93;;<br /><br />    //Calculate the vector mentioned above<br />    Vec2 V1V2 = E.V2-&gt;Position - E.V1-&gt;Position; <br /><br />    //Calculate the current distance<br />    float V1V2Length = V1V2.Length(); <br />    <br />    //Calculate the difference from the original length<br />    float Diff       = V1V2Length - E.OriginalLength; <br />    <br />    V1V2.Normalize();<br /><br />    //Push both vertices apart by half of the difference respectively <br />    //so the distance between them equals the original length<br />    E.V1-&gt;Position += V1V2*Diff*0.5f; <br />    E.V2-&gt;Position -= V1V2*Diff*0.5f;<br />  }<br />}</pre>That's it - if we created a few points and connected them with our newly created edge struct, the resulting body would show very nice rigid body-behaviour, including rotational effects when it hits the floor. But why does that work? The code isn't much different from before, we only added a few lines to satisfy the distance constraint and suddenly we have rigid bodies. The reason behind this lies within our integration method. If we recall that the Verlet integration doesn't work with velocity but rather with the difference between the current position and the position before the last integration step, it should become clear that the speed of the point will change if we change its position. Therefore, since we change its position in the UpdateEdges method, its velocity will also change. The overall change in velocity looks exactly like we would expect it from a vertex of a rigid body; it is not totally correct, but good enough for games.<br />
<br />
 To be honest, I lied when I said before that the code would work just fine if we executed it like that. As the code is now, bodies would not be totally rigid. If a body collides with the floor, the distance between it's vertices is not totally constant, which means that the body is more or less deformed, depending on the it's speed before the collision. Why does that happen? The UpdateEdges method is totally correct, but still the distance between two vertices may vary. If we look at figure 3, this should become clear: If a vertex is connected to more than just one edge (which is normally the case), the length correction of one edge may disturb the length of another edge, which is why the bodies get deformed.<br />
<br />
<p class='bbc_center'>  <a class='resized_img' rel='lightbox[fd542985689b454489faca5d169bdd73]' id='ipb-attach-url-5798-0-78110800-1330210055' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=5798" title="Figure3.png - Size: 6.64K, Downloads: 61"><img src="http://public.gamedev.net/uploads/monthly_10_2011/ccs-8549-0-60735200-1319080139_thumb.png" id='ipb-attach-img-5798-0-78110800-1330210055' style='width:250;height:100' class='attach' width="250" height="100" alt="Attached Image: Figure3.png" /></a><br />
</p><br />
  The only way to get rid of this problem is to execute the edge correction method more than just once per frame. The more this method is called, the more perfect the situation gets approximated, where all vertices have the right distance to each other. This gives game programmers a scalable physics algorithm - the more time is left at the end of the main loop, the more iterations can be used for the distance correction (and the collision response that will be introduced later). Vice-versa, if the main loop takes more time to execute, the iterations used for physics can be reduced so the game runs at a more or less constant frame rate.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Collision Detection</strong></span><br />
<br />
Now that our algorithm supports the simulation of (almost) rigid bodies, let's proceed to the next problem - collision detection! In this article, we will use an algorithm known as the 'Separating Axis Theorem'. If you already now how it works, you might as well just skip this part and go straight to the collision response. So, how does the Separating Axis Theorem work? As the title suggests, it states that two bodies don't collide, as long we are able to put a straight line between the two, that doesn't intersect either body. Figure 4 demonstrates this.<br />
<br />
<p class='bbc_center'>  <a class='resized_img' rel='lightbox[fd542985689b454489faca5d169bdd73]' id='ipb-attach-url-5799-0-78125700-1330210055' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=5799" title="Figure4.png - Size: 8.69K, Downloads: 31"><img src="http://public.gamedev.net/uploads/monthly_10_2011/ccs-8549-0-14037800-1319080199_thumb.png" id='ipb-attach-img-5799-0-78125700-1330210055' style='width:200;height:200' class='attach' width="200" height="200" alt="Attached Image: Figure4.png" /></a><br />
</p><br />
  The only limitation of this algorithm is that it only works correctly with convex shapes. If we tested two concave shapes, the algorithm will fail, meaning that it would detect a collision when there is none. The reason should become evident if you take a look at figure 5.<br />
<br />
<p class='bbc_center'>  <a class='resized_img' rel='lightbox[fd542985689b454489faca5d169bdd73]' id='ipb-attach-url-5800-0-78140700-1330210055' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=5800" title="Figure5.png - Size: 8.76K, Downloads: 32"><img src="http://public.gamedev.net/uploads/monthly_10_2011/ccs-8549-0-88362700-1319080228_thumb.png" id='ipb-attach-img-5800-0-78140700-1330210055' style='width:200;height:200' class='attach' width="200" height="200" alt="Attached Image: Figure5.png" /></a><br />
</p><br />
  We could deal with that by breaking up each concave polygon into convex subshapes and then test each subshape separately, but for simplicity reasons, we will just stick to convex polygons in this article - feel free to add concave support later.<br />
<br />
 So, how do we find out whether we could put a line in-between? We could of course just test every possible line for intersection, but it is evident that this is completely inefficient. To do this, we will take advantage of projection. If we put a new line in figure 4 that is perpendicular to the separating line, we can see that the projections of the two bodies on this line do not overlap (as shown in figure 6). However, if we chose a line that does intersect, the projections of the two bodies do also overlap.<br />
<br />
<p class='bbc_center'>  <a class='resized_img' rel='lightbox[fd542985689b454489faca5d169bdd73]' id='ipb-attach-url-5801-0-78155900-1330210055' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=5801" title="Figure6.png - Size: 16.8K, Downloads: 29"><img src="http://public.gamedev.net/uploads/monthly_10_2011/ccs-8549-0-04196200-1319080251_thumb.png" id='ipb-attach-img-5801-0-78155900-1330210055' style='width:200;height:200' class='attach' width="200" height="200" alt="Attached Image: Figure6.png" /></a><br />
</p><br />
  It is irrelevant where we place the line that we project to, since the resulting projection is one-dimensional anyway - only its direction is important. This means that we don't have to look for a line that fits perfectly in-between the two bodies anymore, but for a direction where the projections don't overlap. Finding this direction shows to be quite easy. Let's consider the case where there is only one possible line that separates the two bodies (see figure 7).<br />
<br />
<p class='bbc_center'>  <a class='resized_img' rel='lightbox[fd542985689b454489faca5d169bdd73]' id='ipb-attach-url-5802-0-78173000-1330210055' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=5802" title="Figure7.png - Size: 11.96K, Downloads: 33"><img src="http://public.gamedev.net/uploads/monthly_10_2011/ccs-8549-0-73015800-1319080270_thumb.png" id='ipb-attach-img-5802-0-78173000-1330210055' style='width:200;height:200' class='attach' width="200" height="200" alt="Attached Image: Figure7.png" /></a><br />
</p><br />
  It is evident that this line is parallel to the left edge of the right body. Therefore, to find the direction of a separating line, we simply have to iterate over all edges of both bodies and check, if the projection of the bodies onto the perpendicular of the edge overlap. If they don't, the bodies don't collide and we can end the search. If they do, we go on to the next edge. If there is no such edge, the entities are colliding and we have to proceed with the collision response.<br />
<br />
 Let's put this into code! But before we can implement the collision detection, we first have to write a body class that contains its respective vertices and edges:<br />
<br />
<pre class='prettyprint'>struct PhysicsBody {<br />  int VertexCount;<br />  int EdgeCount;<br /><br />  Vertex* Vertices&#91; MAX_BODY_VERTICES &#93;;<br />  Edge*   Edges   &#91; MAX_BODY_EDGES    &#93;;<br /><br />  void ProjectToAxis( Vec2& Axis, float& Min, float& Max );<br /><br />  //Again, constructors etc. omitted<br />};</pre>The ProjectToAxis method will project the body onto the passed axis and change the Min and Max variables to the result of the projection. Since a projection of a 2D-shape onto 1D results in a mere interval of a line, the result of the projection can be stored in two floats that denote the beginning and the end of the interval. The projection method is quite simple: <br />
<br />
<pre class='prettyprint'>void PhysicsBody::ProjectToAxis( Vec2& Axis, float& Min, float& Max ) {<br />  float DotP = Axis*Vertices&#91; 0 &#93;-&gt;Position;<br /><br />  //Set the minimum and maximum values to the projection of the first vertex<br />  Min = Max = DotP; <br /><br />  for( int I = 1; I &lt; VertexCount; I++ ) {<br />    //Project the rest of the vertices onto the axis and extend <br />    //the interval to the left/right if necessary<br />    DotP = Axis*Vertices&#91; I &#93;-&gt;Position; <br /><br />    Min = MIN( DotP, Min );<br />    Max = MAX( DotP, Max );<br />  }<br />}</pre> As you can see, projection in 2D is simply a dot product of the projection axis and the point we want to project. The collision detection may look like this:<br />
<br />
<pre class='prettyprint'>bool Physics::DetectCollision( PhysicsBody* B1, PhysicsBody* B2 ) {<br />  //Just a fancy way of iterating through all of the edges of both bodies at once<br />  for( int I = 0; I &lt; B1-&gt;EdgeCount + B2-&gt;EdgeCount; I++ ) { <br />    Edge* E;<br /><br />    if( I &lt; B1-&gt;EdgeCount )<br />      E = B1-&gt;Edges&#91; I &#93;;<br />    else<br />      E = B2-&gt;Edges&#91; I - B1-&gt;EdgeCount &#93;;<br />    <br />    //Calculate the axis perpendicular to this edge and normalize it<br />    Vec2 Axis( E-&gt;V1-&gt;Position.Y - E-&gt;V2-&gt;Position.Y, E-&gt;V2-&gt;Position.X - E-&gt;V1-&gt;Position.X ); <br />    Axis.Normalize();<br /><br />    float MinA, MinB, MaxA, MaxB; //Project both bodies onto the perpendicular axis<br />    B1-&gt;ProjectToAxis( Axis, MinA, MaxA );<br />    B2-&gt;ProjectToAxis( Axis, MinB, MaxB );<br /><br />    //Calculate the distance between the two intervals - see below<br />    float Distance = IntervalDistance( MinA, MaxA, MinB, MaxB ); <br /><br />    if( Distance &gt; 0.0f ) //If the intervals don't overlap, return, since there is no collision<br />      return false;<br />  }<br /><br />  return true; //There is no separating axis. Report a collision!<br />}</pre>The algorithm works just like described above; if something isn't clear, I would suggest rereading the explanations step by step. The IntervalDistance method that is mentioned in the code is actually quite simple:<br />
<br />
<pre class='prettyprint'>float Physics::IntervalDistance( float MinA, float MaxA, float MinB, float MaxB ) {<br />  if( MinA &lt; MinB )<br />    return MinB - MaxA;<br />  else<br />    return MinA - MaxB;<br />}</pre>Since we don't know if body A will lie on the left and body B on the right or vice-versa, we have to check which interval begins sooner. We then subtract the end of the left interval from the beginning of the right interval to get the distance between the two - if this value is smaller than zero, they overlap. <br />
<br />
That's it for collision detection! ...well, not yet. Apart from detecting whether or not the two bodies collide, the collision detection should also provide certain information about the collision. We also have to calculate a so-called collision vector that is big enough to push the two bodies apart so they don't collide anymore, but touch each other. There are of course arbitrarily much vectors that could accomplish this, but for our physics to look right we have to find the smallest of those vectors. The vector we're looking for has the pleasant property that it's always parallel to one of the lines we projected to, which means that we only have to check each edge and calculate the length of the vector needed to push the two bodies apart. Figuring out the length isn't really a hard thing to do, if we take a look at figure 8.<br />
<br />
<p class='bbc_center'>  <a class='resized_img' rel='lightbox[fd542985689b454489faca5d169bdd73]' id='ipb-attach-url-5803-0-78188200-1330210055' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=5803" title="Figure8.png - Size: 16.88K, Downloads: 35"><img src="http://public.gamedev.net/uploads/monthly_10_2011/ccs-8549-0-38727200-1319080569_thumb.png" id='ipb-attach-img-5803-0-78188200-1330210055' style='width:200;height:200' class='attach' width="200" height="200" alt="Attached Image: Figure8.png" /></a><br />
</p><br />
  In the code above we projected both bodies onto the axis given by the (normalized!) vector 'Axis'. We then called the method IntervalDistance to check whether or not the intervals are overlapping. The length of the vector (which is parallel to the axis we projected to) needed to push the two bodies apart is simply the amount of overlapping. To allow the information calculated in the DetectCollision method to pass smoothly to the collision response, we add a new struct to our Physics class:<br />
<br />
<pre class='prettyprint'>class Physics {<br />  struct {<br />    float Depth;<br />    Vec2  Normal;<br />  } CollisionInfo;<br /><br />  //Everything else omitted<br />}</pre>The 'Depth' is the length of the vector, the 'Normal' is the direction of the vector discussed above. <br />
<br />
Our new DetectCollision method would now look like this:<br />
<br />
<pre class='prettyprint'>bool Physics::DetectCollision( PhysicsBody* B1, PhysicsBody* B2 ) {<br />  float MinLength = 10000.0f; //Initialize the length of the collision vector to a relatively large value<br />  for( int I = 0; I &lt; B1-&gt;EdgeCount + B2-&gt;EdgeCount; I++ ) {<br />    Edge* E;<br /><br />    if( I &lt; B1-&gt;EdgeCount )<br />      E = B1-&gt;Edges&#91; I &#93;;<br />    else<br />      E = B2-&gt;Edges&#91; I - B1-&gt;EdgeCount &#93;;<br /><br />    Vec2 Axis( E-&gt;V1-&gt;Position.Y - E-&gt;V2-&gt;Position.Y, E-&gt;V2-&gt;Position.X - E-&gt;V1-&gt;Position.X );<br />    Axis.Normalize();<br /><br />    float MinA, MinB, MaxA, MaxB;<br />    B1-&gt;ProjectToAxis( Axis, MinA, MaxA );<br />    B2-&gt;ProjectToAxis( Axis, MinB, MaxB );<br /><br />    float Distance = IntervalDistance( MinA, MaxA, MinB, MaxB );<br /><br />    if( Distance &gt; 0.0f )<br />      return false;<br />      <br />    //If the intervals overlap, check, whether the vector length on this <br />    //edge is smaller than the smallest length that has been reported so far<br />    else if( abs( Distance ) &lt; MinDistance ) { <br />      MinDistance = abs( Distance );<br /><br />      CollisionInfo.Normal = Axis; //Save collision information for later<br />    }<br />  }<br /><br />  CollisionInfo.Depth = MinDistance;<br /><br />  return true; //There is no separating axis. Report a collision!<br />}</pre>Once we have this, we'd be already able to write a very simple collision response. Since the collision vector we calculated pushes the two bodies apart so they don't collide anymore, we could just move all vertices of both bodies back by half the vector and we'd be done. This would work, since interpenetrations are resolved, but it wouldn't look right. The bodies would simply glide off each other, meaning they don't start to spin like a real object when hit. <br />
<br />
The problem is that a body in our approach only spins if the velocities of its vertices differ. In the same manner, a body only changes its rotational velocity if its vertices experience different acceleration. Acceleration is change in velocity, and in Verlet integration change in velocity is equal to change in position. Therefore, if we move the two bodies back by the collision vector, we change the velocity of all vertices of both bodies by the same amount, which means that there is no change in the rotational velocity. For this reason, we need to write a better collision response.<br />
<br />
 This is where the advantage of our approach kicks in! In a rigid body system, we would have to use complicated formulas to calculate the momentum and then treat the linear and angular case separately. In our system, the whole thing is much easier - we just have to move the edge and the vertex participating in the collision backwards so they don’t intersect, but touch each other. Since both the edge and the vertex are connected to the rest of their respective body, the position (and therefore the velocity) of the other vertices will change immediately to fulfil the length constraint. Both bodies will start spinning self-actingly. The whole collision response reduces to identifying the edge and the vertex that participate in the collision and separating them from each other; everything else will be done automatically by the edge correction step.<br />
<br />
 Identifying the collision edge and vertex is not that hard. The collision vertex is the vertex that lies closest to the other body. Therefore, we simply have to create a line whose normal vector is the collision normal (its starting point doesn't really matter). We then measure the distance of each vertex of the first body from the line using the line equation in vector geometry, which is<br />
<br />
 <a class='resized_img' rel='lightbox[fd542985689b454489faca5d169bdd73]' id='ipb-attach-url-5804-0-78203700-1330210055' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=5804" title="Formula4.png - Size: 751bytes, Downloads: 29"><img src="http://public.gamedev.net/uploads/monthly_10_2011/ccs-8549-0-49227200-1319080662_thumb.png" id='ipb-attach-img-5804-0-78203700-1330210055' style='width:120;height:36' class='attach' width="120" height="36" alt="Attached Image: Formula4.png" /></a><br />
<br />
 where N is the normal vector, R<sub class='bbc'>0</sub> the origin of the line, R the point to be tested and d the distance of the point from the line. The set of all points that form a line are given by d = 0 (all points that have zero distance from the line), just as a side note. Once we have the distance of each vertex from the line, we choose the one with the lowest distance - that's the collision vertex we were looking for. Please note that d can also be negative. A line separates a two dimensional space in two halves; if the point R lies in the half the line normal points into, the distance will be positive, but if it lies on the other side, the distance will be negative. Therefore, it is important in which direction the collision normal points (in the implementation presented below, it’s always made sure that the collision normal points at the body containing the collision vertex).<br />
<br />
 The collision edge is even easier to find. Remember when we projected the bodies on the perpendicular of an edge to find the smallest collision vector? The collision edge is simply the edge that resulted in the smallest vector.<br />
<br />
 Time to put this in code! First of all, we have to extend the collision info struct in the physics class to contain the collision edge and vertex:<br />
<br />
<pre class='prettyprint'>struct {<br />  float Depth;<br />  Vec2  Normal;<br /><br />  Edge*   E;<br />  Vertex* V;<br />} CollisionInfo;</pre>Now we can rewrite our DetectCollision method to detect the additional information:  <br />
<br />
<pre class='prettyprint'>bool Physics::DetectCollision( PhysicsBody* B1, PhysicsBody* B2 ) {<br />  float MinDistance = 10000.0f;<br />  for( int I = 0; I &lt; B1-&gt;EdgeCount + B2-&gt;EdgeCount; I++ ) { //Same old<br />    Edge* E;<br /><br />    if( I &lt; B1-&gt;EdgeCount )<br />      E = B1-&gt;Edges&#91; I &#93;;<br />    else<br />      E = B2-&gt;Edges&#91; I - B1-&gt;EdgeCount &#93;;<br /><br />    Vec2 Axis( E-&gt;V1-&gt;Position.Y - E-&gt;V2-&gt;Position.Y, E-&gt;V2-&gt;Position.X - E-&gt;V1-&gt;Position.X );<br />    Axis.Normalize();<br /><br />    float MinA, MinB, MaxA, MaxB;<br />    B1-&gt;ProjectToAxis( Axis, MinA, MaxA );<br />    B2-&gt;ProjectToAxis( Axis, MinB, MaxB );<br /><br />    float Distance = IntervalDistance( MinA, MaxA, MinB, MaxB );<br /><br />    if( Distance &gt; 0.0f )<br />      return false;<br />    else if( abs( Distance ) &lt; MinDistance ) {<br />      MinDistance = abs( Distance );<br /><br />      CollisionInfo.Normal = Axis;<br />      CollisionInfo.E      = E; //Store the edge, as it is the collision edge<br />    }<br />  }<br /><br />  CollisionInfo.Depth = MinDistance;<br /><br />  //Ensure that the body containing the collision edge lies in <br />  //B2 and the one containing the collision vertex in B1<br />  if( CollisionInfo.E-&gt;Parent != B2 ) { <br />    PhysicsBody* Temp = B2;<br />    B2 = B1;<br />    B1 = Temp;<br />  }<br /><br />  //This is needed to make sure that the collision normal is pointing at B1<br />  int Sign = SGN( CollisionInfo.Normal*( B1-&gt;Center - B2-&gt;Center ) ); <br /><br />  //Remember that the line equation is N*( R - R0 ). We choose B2-&gt;Center <br />  //as R0; the normal N is given by the collision normal<br /><br />  if( Sign != 1 )<br />    CollisionInfo.Normal = -CollisionInfo.Normal; //Revert the collision normal if it points away from B1<br /><br /><br />  float SmallestD = 10000.0f; //Initialize the smallest distance to a high value<br />  for( int I = 0; I &lt; B1-&gt;VertexCount; I++ ) {<br />    //Measure the distance of the vertex from the line using the line equation<br />    float Distance = CollisionInfo.Normal*( B1-&gt;Vertices&#91; I &#93;-&gt;Position - B2-&gt;Center ); <br /><br />    //If the measured distance is smaller than the smallest distance reported <br />    //so far, set the smallest distance and the collision vertex<br />    if( Distance &lt; SmallestD ) { <br />      SmallestD = Distance;<br />      CollisionInfo.V = B1-&gt;Vertices&#91; I &#93;;<br />    }<br />  }<br /><br />  return true;<br />}</pre>In the above code, we introduced a new variable in the PhysicsBody struct, the center. It will be recalculated before the collision step and is simply the average of all vertices of the body. <br />
<strong class='bbc'><br />
<br />
<span style='font-size: 18px;'>Collision Response</span></strong><br />
<br />
Finally, we're done with collision detection. The only thing left to do is the collision response, which is luckily not that hard. As explained above, we just have to push the collision vertex and the collision edge apart by the collision vector and we're done. This is trivial for the collision vertex. Since we already ensured that the collision normal points at the first body which contains the collision vertex, we just have to add half of the collision vector to the position of the vertex:  <br />
<br />
<pre class='prettyprint'>void Physics::ProcessCollision() {<br />  Vec2 CollisionVector = CollisionInfo.Normal*CollisionInfo.Depth;<br /><br />  CollisionInfo.V-&gt;Position += CollisionVector*0.5f;<br />}</pre>For the edge case, this will become a bit more complicated. The edge consists of two vertices that will move differently, depending on where the collision vertex lies. The closer it lies to the one end of the edge, the more this end will move and vice-versa. This means that we first have to calculate where on the edge the collision vertex lies. This is done using the following equation: <br />
<br />
<a class='resized_img' rel='lightbox[fd542985689b454489faca5d169bdd73]' id='ipb-attach-url-5805-0-78218400-1330210055' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=5805" title="Formula5.png - Size: 709bytes, Downloads: 26"><img src="http://public.gamedev.net/uploads/monthly_10_2011/ccs-8549-0-98095700-1319081150_thumb.png" id='ipb-attach-img-5805-0-78218400-1330210055' style='width:86;height:51' class='attach' width="86" height="51" alt="Attached Image: Formula5.png" /></a><br />
<br />
 Where V is the position of the collision vertex and E<sub class='bbc'>1</sub> and E<sub class='bbc'>2</sub> are the two vertices connected by the edge. t is the factor that determines where on the edge the vertex lies, reaching from 0 to 1. It doesn't matter whether we choose the X or the Y coordinate to calculate t, since both would result in the same value. The X case would look like this:<br />
<br />
<pre class='prettyprint'>Vertex* E1 = CollisionInfo.E-&gt;V1;<br />Vertex* E2 = CollisionInfo.E-&gt;V2;<br /><br />float T = ( CollisionInfo.V-&gt;Position.X - CollisionVector.X - E1-&gt;Position.X )/(  E2-&gt;Position.X - E1-&gt;Position.X );</pre>But be careful! If E2 lies directly above E1, the program would divide by zero. Therefore, we should build in a small check to avoid this:  <br />
<br />
<pre class='prettyprint'>float T;<br />if( abs( E1-&gt;Position.X - E2-&gt;Position.X ) &gt; abs( E1-&gt;Position.Y - E2-&gt;Position.Y ) )<br />  T = ( CollisionInfo.V-&gt;Position.X - CollisionVector.X - E1-&gt;Position.X )/(  E2-&gt;Position.X - E1-&gt;Position.X );<br />else<br />  T = ( CollisionInfo.V-&gt;Position.Y - CollisionVector.Y - E1-&gt;Position.Y )/(  E2-&gt;Position.Y - E1-&gt;Position.Y );</pre>This basically divides by the X denominator if it is bigger than the Y denominator and vice-versa. <br />
<br />
We then use the following neat formula to calculate a scaling factor that ensures that the collision vertex lies on the collision edge after the collision response. We could derive it by solving a few equations, but I don't think the derivation is really important, so I'll just leave this here:<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/programming/verletPhys/Formula6.png' alt='Posted Image' class='bbc_img' /></span><br />
<br />
 Once we put all of this in code, we get:<br />
<br />
<pre class='prettyprint'>void Physics::ProcessCollision() {<br />  Vec2 CollisionVector = CollisionInfo.Normal*CollisionInfo.Depth;<br /><br />  Vertex* E1 = CollisionInfo.E-&gt;V1;<br />  Vertex* E2 = CollisionInfo.E-&gt;V2;<br /><br />  float T;<br />  if( abs( E1-&gt;Position.X - E2-&gt;Position.X ) &gt; abs( E1-&gt;Position.Y - E2-&gt;Position.Y ) )<br />    T = ( CollisionInfo.V-&gt;Position.X - CollisionVector.X - E1-&gt;Position.X )/(  E2-&gt;Position.X - E1-&gt;Position.X);<br />  else<br />    T = ( CollisionInfo.V-&gt;Position.Y - CollisionVector.Y - E1-&gt;Position.Y )/(  E2-&gt;Position.Y - E1-&gt;Position.Y);<br /><br />  float Lambda = 1.0f/( T*T + ( 1 - T )*( 1 - T ) );<br /><br />  E1-&gt;Position -= CollisionVector*( 1 - T )*0.5f*Lambda;<br />  E2-&gt;Position -= CollisionVector*      T  *0.5f*Lambda;<br /><br />  CollisionInfo.V-&gt;Position += CollisionVector*0.5f;<br />}</pre>That's it. We're done with collision response - easy, wasn't it? <br />
<br />
All that's left to do is to put all of the methods we wrote into a single update method:<br />
<br />
<pre class='prettyprint'>void Physics::Update() {<br />  UpdateForces();<br />  UpdateVerlet();<br />  IterateCollisions();<br />}</pre>IterateCollisions is a method that does multiple things. It iterates over all bodies, calls the respective UpdateEdges method, recalculates the body center and then does the collision detection (and the collision response, if necessary). Of course, it doesn't just do this once, but repeats those steps a few times. The more repetitions are made, the more realistic the physics will look. The reason was explained above (if you've forgotten, better read it again ;) ). <br />
<br />
<br />
<span style='font-size: 18px;'><strong class='bbc'>Final Words</strong></span><br />
<br />
You can download a working implementation using GLUT and OGL as a Visual C++ 2008 project via the attached resource file. It is basically the same code as discussed in this article with a few optimizations and a very simple rendering and input function. I hope you enjoyed this article and found it useful. If you have any questions or suggestions, please let me know. Since I'm not a native English speaker, there might be a few mistakes here and there; please bear with it.]]></description>
		<pubDate>Thu, 19 Nov 2009 22:49:22 +0000</pubDate>
		<guid isPermaLink="false">9e69fd6d1c5d1cef75ffbe159c1f322e</guid>
	</item>
	<item>
		<title>2D Car Physics</title>
		<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/2d-car-physics-r2443</link>
		<description><![CDATA[

<h1>Introduction</h1>
<p>Someone asked me in the #gamedev IRC channel about how to make a 2d vehicle simulator. Instead of spending all day trying to explain the concepts to him, I decided just to write this tutorial.
Please bear with me, this is my first tutorial.</p>
<p>So as I mentioned we&rsquo;re going to be learning how to make a basic 2d vehicle simulator. We&rsquo;re going to do it in C# and try do use as few hacks as possible. I&rsquo;ve broken the process
down into three steps. First, we will learn how to setup a basic game application in C#.NET and how to draw some basic graphics (emphasis on basic.) Next, we will learn how to create a rigid body
simulator using a simple Euler integrator with a variable time step. And last but not least, we will calculate vehicle forces simulating the tire patch contacting the road. And that&rsquo;s all there
is to it! Let&rsquo;s get started.</p>
<h2>Math Requirements</h2>
There are two ways to get through this tutorial: you can rush to the end and download the project, or you can read through it and hopefully I&rsquo;ll be able to explain things clearly. If you choose
the second route, you&rsquo;re going to need to have a bit of math background. In a 2D simulation this is mostly in the form of a vector object. You&rsquo;ll need to be able to add, subtract, dot,
and project 2 vectors. Also you&rsquo;ll need to be able to use a cross product. In 2D this is kind of a fake situation since we know the result will point in the screen&rsquo;s direction, so the
result is returned as a scalar. If you&rsquo;re not familiar with any of these terms please look them up now. I tried to write this tutorial without using a matrix object but eventually I cracked and
used the Drawing2D.Matrix object to transform and inversely transform a vector between spaces. If you don&rsquo;t know what I&rsquo;m talking about let me give you an example. Let&rsquo;s say your
personal body is your &ldquo;local space&rdquo; and the room you&rsquo;re sitting in is the &ldquo;world space.&rdquo; Let&rsquo;s also say that your monitor is the front of the world, and your eyes
look in the forward direction of your local space. If you turn sideways, and transform the monitor&rsquo;s direction into your space, it is now the side direction. Vise versa, if you transform your
facing direction into world space, it is the opposite side direction. This is a critical concept so please, if that didn&rsquo;t make sense, do some searching on Google for transforming between
spaces. The reason this is so important is because we will be doing all of our vehicle force calculations in local vehicle space. Yet the vehicle itself, and its integrator, persist in world space.
<h1>Phase One</h1>
<p>Phase one, as I mentioned, is to create the renderer; something graphical so we can actually see what our simulation is doing. This will make it a lot easier to debug. Create a windows form
project in C# and place a picturebox control on it (name it "screen"). This control is where we will display our simulation. We could just start drawing to this screen but we&rsquo;re going to be
using double buffering as well to avoid flicker, so we need to create the back buffer now. That bit of code looks like this.</p>
<pre class="code">
Graphics graphics; //gdi+
Bitmap backbuffer;
Size buffersize;

//intialize rendering
private void Init(Size size)
{
  //setup rendering device
  buffersize = size;
  backbuffer = new Bitmap(buffersize.Width, buffersize.Height);
  graphics = Graphics.FromImage(backbuffer);
}
</pre>
The <code>Init</code> function must be called with the size of the &ldquo;screen&rdquo; control that you created on the form. This will create a bitmap &ldquo;backbuffer&rdquo; to which we can do our
offscreen rendering. We&rsquo;ll then take this backbuffer and draw it to the screen to illiminate any flickering. This is how you draw a basic shape to the backbuffer, and present it to the screen.
<pre class="code">
//main rendering function
private void Render(Graphics g)
{
  //clear back buffer
  graphics.Clear(Color.Black);

  //draw to back buffer
  graphics.DrawLine(new Pen(Color.Yellow), 1, 0, 1, 5);

  //present back buffer
  g.DrawImage(backbuffer, new Rectangle(0, 0, buffersize.Width, buffersize.Height), 0, 0, buffersize.Width, buffersize.Height, GraphicsUnit.Pixel);
}
</pre>
This function is called from the <code>on_paint</code> method of the "screen" control placed on our form. The <code>on_paint</code> method has a parameter &ldquo;e&rdquo; that contains a graphics
object we can use to draw to the control. We pass this graphics object to the render function and as you can see, we draw the backbuffer to it as the very last step.
<p>Now by default, the graphics of a picturebox control has the origin in the top-left corner, and extends downward for +y and to the right for +x. This is highly unnatural for most cases. In
addition to that, it has extremely large units. Since we will be simulating in the metric system, I recommend introducing a scale factor to scale up the simulation and make it much more visible. The
transformation looks like this and takes place after <code>Graphics.Clear()</code> is called.</p>
<pre class="code">
graphics.ResetTransform();
graphics.ScaleTransform(screenScale, -screenScale);
graphics.TranslateTransform(buffersize.Width / 2.0f / screenScale, -buffersize.Height / 2.0f / screenScale);
</pre>
That transformation flips the Y axis so that +Y points up. It simultaneously scales the space by our &ldquo;screenScale&rdquo; factor (something like 3.0f should work fine). Next, we translate the
graphics space into the center of the screen control by half of the screen dimensions divided by our scale (since we are now in the scaled space.)
<p>Now the line should draw starting right at the center of the screen.</p>
<h2>Forms Wiring</h2>
<p>Up until now, I havn&rsquo;t explained how to connect all the functions. The first thing you&rsquo;ll need to do is call the <code>Render</code> function from your <code>on_paint</code> event.
Next, you&rsquo;ll need to create a function that gets called continously to update the simulation. It is preferred to call this function on the <code>Application_Idle</code> event. So create an
event handler for <code>Application_Idle</code> and have it call your <code>DoFrame</code> function. Inside this function you&rsquo;ll need to</p>
<ol>
<li>Process input</li>
<li>Update the simulation</li>
<li>Invalidate the screen control</li>
</ol>
The last step is so that an <code>On_Paint</code> gets triggerd and the simulation gets drawn. You&rsquo;ll also want to wire up some &ldquo;key_down&rdquo; and &ldquo;key_up&rdquo; events to keep
track of key states.
<h2>The Timer</h2>
<p>Since we don&rsquo;t know how often our <code>DoFrame</code> function will be getting called, we need to code everything to handle a variable time step. To utilize this we must measure the time
between <code>DoFrame</code> calls. So I&rsquo;ll introduce the timer which, very simply, queries the number of milliseconds that have passed since the computer was turned on. So we store this number
every frame and on a subsequent frame we compute the difference, which gives us the amount of time that has passed since the last frame. Here is my very simple timer object. <b>Note:</b> you will
need to call <code>GetETime</code> in your intialize function in order to clear the timer, otherwise the first call to it will return the amount of time that has passed since the computer was turned
on.</p>
<pre class="code">
class Timer
{
  //store last time sample
  private int lastTime = Environment.TickCount;
  private float etime;

  //calculate and return elapsed time since last call
  public float GetETime()
  {
    etime = (Environment.TickCount - lastTime) / 1000.0f;
    lastTime = Environment.TickCount;

    return etime;
  }
}
</pre>
<h2>Conclusion of Phase One</h2>
<p>So up until now we&rsquo;ve covered: setting up a rendering surface using GDI, wiring a form to process a game loop and draw it to the screen, and computing the time that has passed since the last
frame. Our application looks like this:</p>
<pre class="code">
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Windows.Forms;

namespace racing_simulation_2d
{
  //our main application form
  public partial class frmMain : Form
  {
    //graphics
    Graphics graphics; //gdi+
    Bitmap backbuffer;
    Size buffersize;
    const float screenScale = 3.0f;
    Timer timer = new Timer();

    //keyboard controls
    bool leftHeld = false, rightHeld = false;
    bool upHeld = false, downHeld = false;

    //vehicle controls
    float steering = 0; //-1 is left, 0 is center, 1 is right
    float throttle = 0; //0 is coasting, 1 is full throttle
    float brakes = 0; //0 is no brakes, 1 is full brakes

    public frmMain()
    {
      InitializeComponent();
      Application.Idle += new EventHandler(ApplicationIdle);

      screen.Paint += new PaintEventHandler(screen_Paint);
      this.KeyDown += new KeyEventHandler(&#111;nkeydown);
      this.KeyUp += new KeyEventHandler(&#111;nkeyup);

      Init(screen.Size);
    }

    //intialize rendering
    private void Init(Size size)
    {
      //setup rendering device
      buffersize = size;
      backbuffer = new Bitmap(buffersize.Width, buffersize.Height);
      graphics = Graphics.FromImage(backbuffer);

      timer.GetETime(); //reset timer
    }

    //main rendering function
    private void Render(Graphics g)
    {
      //clear back buffer
      graphics.Clear(Color.Black);
      graphics.ResetTransform();
      graphics.ScaleTransform(screenScale, -screenScale);
      graphics.TranslateTransform(buffersize.Width / 2.0f /
          screenScale, -buffersize.Height / 2.0f / screenScale);

      //draw to back buffer
      DrawScreen();

      //present back buffer
      g.DrawImage(backbuffer, new Rectangle(0, 0, buffersize.Width,
       buffersize.Height), 0, 0, buffersize.Width, 
       buffersize.Height, GraphicsUnit.Pixel);
    }

    //draw the screen
    private void DrawScreen()
    {
      //draw our simulation here
    }

    //process game logic
    private void DoFrame()
    {
      //get elapsed time since last frame
      float etime = timer.GetETime();

      //process input
      ProcessInput();

      ////////////////////////////////
      //integrate our simulation here
      ////////////////////////////////

      //redraw our screen
      screen.Invalidate();
    }


    //process keyboard input
    private void ProcessInput()
    {
      if (leftHeld)
        steering = -1;
      else if (rightHeld)
        steering = 1;
      else
        steering = 0;

      if (upHeld)
        throttle = 1;
      else
        throttle = 0;

      if (downHeld)
        brakes = 1;
      else
        brakes = 0;
    }

    private void &#111;nkeydown(object sender, KeyEventArgs e)
    {
      switch (e.KeyCode)
      {
        case Keys.Left:
          leftHeld = true;
          break;
        case Keys.Right:
          rightHeld = true;
          break;
        case Keys.Up:
          upHeld = true;
          break;
        case Keys.Down:
          downHeld = true;
          break;
        default: //no match found
          return; //return so handled dosnt get set
      }

      //match found
      e.Handled = true;
    }

    private void &#111;nkeyup(object sender, KeyEventArgs e)
    {
      switch (e.KeyCode)
      {
        case Keys.Left:
          leftHeld = false;
          break;
        case Keys.Right:
          rightHeld = false;
          break;
        case Keys.Up:
          upHeld = false;
          break;
        case Keys.Down:
          downHeld = false;
          break;
        default: //no match found
          return; //return so handled dosnt get set
      }

      //match found
      e.Handled = true;
    }

    //rendering - only when screen is invalidated
    private void screen_Paint(object sender, PaintEventArgs e)
    {
      Render(e.Graphics);
    }

    //when the os gives us time, run the game
    private void ApplicationIdle(object sender, EventArgs e)
    {
      // While the application is still idle, run frame routine.
      DoFrame();
    }

    private void MenuExit_Click(object sender, EventArgs e)
    {
      this.Close();
    }
  }

  //keep track of time between frames
  class Timer
  {
    //store last time sample
    private int lastTime = Environment.TickCount;
    private float etime;

    //calculate and return elapsed time since last call
    public float GetETime()
    {
      etime = (Environment.TickCount - lastTime) / 1000.0f;
      lastTime = Environment.TickCount;

      return etime;
    }
  }
}
</pre>
<h1>Phase Two - Rigid Body Simulation</h1>
<p>Ok, now we&rsquo;re getting into some good stuff here. Let's put everything we just covered on the back burner now and talk about some physics. We&rsquo;re going to be using a very simple Euler
integration method. Basically, each frame we accumulate a bunch of forces (in our case from each wheel of the vehicle) and calculate the resultant acceleration, which is in the form of A=F/M (the
same as F=MA, Newton&rsquo;s second law of motion). We use this to modify Newton&rsquo;s first law of motion, &ldquo;an object in motion stays in motion&hellip;&rdquo; So we calculate our A, and we
integrate it into our V. Without an A, V would be constant, hence staying in motion, if no forces should act on it. Newton's third law gets applied in the form that any potential force the vehicle is
applying to the ground, gets applied in the opposite direction to the vehicle (I'll explain this in the vehicle section). This topic is much easier to explain with symbols. So, P is our vehicle
position, V is its linear velocity, F is the net force acting on it, M is its mass, A is the resultant acceleration, and T is the time step (the value our timer gave us from the last frame).</p>
<pre>
  A = F / M
  V = V + A * T
  P = P + V * T
</pre>
So with a constant mass, and some force, we will generate acceleration, which will in turn generate velocity, which will in turn generate a displacement (a change in P).
<p>This is a basic linear rigid body simulator. Each frame, we total up some F, integrate it, and then zero out F to restart the accumulation the next frame. Now let&rsquo;s talk about rotation. The
angular case is nearly identical to the linear case (especially in 2D). Instead of P we have an Angle, instead of V we have an Angular Velocity, instead of F we have a torque, and instead of M we
have inertia. So the angular model looks like this</p>
<pre>
  AngA = Torque / Inertia
  AngV = AngV + AngA * T
  Angle = Angle + AngV * T
</pre>
Simple huh? Now you may be wondering where this Torque came from. A torque is generated every time you apply a force. Lay a book down on your desk and push on the corner of it. The book should slide
across the desk, but it should also begin to rotate. The slide is caused by the force. This rotation is caused by the torque, and the magnitude of the torque is directly proportional to how far away
from the center of the object the force was applied. If you applied the force directly to the center of the object, the torque would be zero. We need to construct an <code>AddForce</code> function
for our rigid body. This is what gets called every frame, once per wheel, to accumulate the chassis' rigid body force/torque. The linear case is simple, Force = Force + newForce. The angular case is
a little trickier. We take the cross product of the force direction and the torque arm (the offset between where the force was applied and the center of mass of the body.) In 2D, this results in a
scalar value that we can just add to Torque. So, Torque = Torque + TorqueArm.Cross(Force)
<p>This is what that bit of code looks like. % is the cross product operator for my vector class.</p>
<pre class="code">
public void AddForce(Vector worldForce, Vector worldOffset)
{
  //add linar force
  m_forces += worldForce;
  //and it's associated torque
  m_torque += worldOffset % worldForce;
}
</pre>
You&rsquo;ll notice the &ldquo;world" prefix on the parameters. This is because all computation of the rigid body happens in world space. So as your book is rotating on the desk, the worldOffset
value is changing, even though your finger is not moving on the book (this would be the relativeOffset). So if we know we&rsquo;re applying a force &ldquo;across the book, at the top right corner" we
need to convert both &ldquo;across" and &ldquo;top right corner" into world space vectors, then add them to the rigid body.
<h2>Code Dump</h2>
<p>Here is my rigid body object. You&rsquo;ll notice all the properties I mentioned above. It has a <code>Draw</code> function which will draw its rectangle to the provided graphics object. It has an
<code>AddForce</code> function, a space conversion method, to and from world space (very handy), and a function that returns the velocity of a point on the body (in world space). This point velocity
is a combination of the linear velocity and the angular velocity. But the angular velocity is multiplied by the distance the point is from the center of rotation and perpendicular to its offset
direction. So to kill two birds with one stone, I simply find the orthogonal vector to the point offset and multiply it by the angular velocity (then add the linear velocity.)</p>
<p>One thing you may be curious about is how I calculate the inertia value. That is a generalized formula I found at <a href="http://howard.nebrwesleyan.edu/hhmi/fellows/pgomez/inertforms.html">this
link</a>.</p>
<pre class="code">
//our simulation object
class RigidBody
{
  //linear properties
  private Vector m_position = new Vector();
  private Vector m_velocity = new Vector();
  private Vector m_forces = new Vector();
  private float m_mass;

  //angular properties
  private float m_angle;
  private float m_angularVelocity;
  private float m_torque;
  private float m_inertia;

  //graphical properties
  private Vector m_halfSize = new Vector();
  Rectangle rect = new Rectangle();
  private Color m_color;

  public RigidBody()
  { 
    //set these defaults so we dont get divide by zeros
    m_mass = 1.0f; 
    m_inertia = 1.0f; 
  }

  //intialize out parameters
  public void Setup(Vector halfSize, float mass, Color color)
  {
    //store physical parameters
    m_halfSize = halfSize;
    m_mass = mass;
    m_color = color;
    m_inertia = (1.0f / 12.0f) * (halfSize.X * halfSize.X)
       * (halfSize.Y * halfSize.Y) * mass;

    //generate our viewable rectangle
    rect.X = (int)-m_halfSize.X;
    rect.Y = (int)-m_halfSize.Y;
    rect.Width = (int)(m_halfSize.X * 2.0f);
    rect.Height = (int)(m_halfSize.Y * 2.0f);
  }

  public void SetLocation(Vector position, float angle)
  {
    m_position = position;
    m_angle = angle;
  }

  public Vector GetPosition()
  {
    return m_position;
  }

  public void Update(float timeStep)
  {
    //integrate physics
    //linear
    Vector acceleration = m_forces / m_mass;
    m_velocity += acceleration * timeStep;
    m_position += m_velocity * timeStep;
    m_forces = new Vector(0,0); //clear forces

    //angular
    float angAcc = m_torque / m_inertia;
    m_angularVelocity += angAcc * timeStep;
    m_angle += m_angularVelocity * timeStep;
    m_torque = 0; //clear torque
  }

  public void Draw(Graphics graphics, Size buffersize)
  {
    //store transform, (like opengl's glPushMatrix())
    Matrix mat1 = graphics.Transform;

    //transform into position
    graphics.TranslateTransform(m_position.X, m_position.Y);
    graphics.RotateTransform(m_angle/(float)Math.PI * 180.0f);

    try
    {
      //draw body
      graphics.DrawRectangle(new Pen(m_color), rect);

      //draw line in the "forward direction"
      graphics.DrawLine(new Pen(Color.Yellow), 1, 0, 1, 5);
    }
    catch(OverflowException exc)
    {
      //physics overflow :(
    }  

    //restore transform
    graphics.Transform = mat1;
  }

  //take a relative vector and make it a world vector
  public Vector RelativeToWorld(Vector relative)
  {
    Matrix mat = new Matrix();
    PointF[] vectors = new PointF[1];

    vectors[0].X = relative.X;
    vectors[0].Y = relative.Y;

    mat.Rotate(m_angle / (float)Math.PI * 180.0f);
    mat.TransformVectors(vectors);

    return new Vector(vectors[0].X, vectors[0].Y);
  }

  //take a world vector and make it a relative vector
  public Vector WorldToRelative(Vector world)
  {
    Matrix mat = new Matrix();
    PointF[] vectors = new PointF[1];

    vectors[0].X = world.X;
    vectors[0].Y = world.Y;

    mat.Rotate(-m_angle / (float)Math.PI * 180.0f);
    mat.TransformVectors(vectors);

    return new Vector(vectors[0].X, vectors[0].Y);
  }

  //velocity of a point on body
  public Vector PointVel(Vector worldOffset)
  {
    Vector tangent = new Vector(-worldOffset.Y, worldOffset.X);
    return tangent * m_angularVelocity + m_velocity;
  }

  public void AddForce(Vector worldForce, Vector worldOffset)
  {
    //add linar force
    m_forces += worldForce;
    //and it's associated torque
    m_torque += worldOffset % worldForce;
  }
}
</pre>
<h2>Testing</h2>
<p>To make sure your rigid body works, instantiate one in your <code>Init()</code> function and apply a force with some offset in the <code>DoFrame</code> function. If you apply a constant
worldOffset, the body will continue to accelerate its angular velocity. If you take your offset and run it through the <code>RelativeToWorld</code> function, the body will angularly accelerate in one
direction and then come back the other way, like a pendulum as the point the force is applied to changes. Play around with this for a while, this has to work and make sense in order for the next
section to work.</p>
<h1>Phase Three - The Vehicle</h1>
<p>Assuming everything has gone well above, you should have a rigid body actor in your scene that you can apply forces to and watch move around. Now all that&rsquo;s left is to calculate these forces
in a way that will simulate a vehicle. For that we are going to need a vehicle object. I recommend deriving directly from you rigid body object since the chassis is essentially a rigid body. In
addition to that we will need to construct a &ldquo;wheel" object. This wheel will handle the steering direction of each wheel, the velocity the wheel is spinning, and calculate the forces that that
particular wheel applies to the chassis (all in vehicle space). Since our wheel is known to be constrained to the vehicle, we don&rsquo;t need to simulate it as another rigid body (though you could,
but not in the 2D case.) We will simply duplicate the angular properties of the rigid body in the wheel object.</p>
<p>So we&rsquo;ll need: Wheel Velocity, Wheel Inertia, and and Wheel Torque. We&rsquo;ll also need the relative offset of the wheel in the vehicle space, and the angle the wheel is facing (this is
constant for the back wheels, unless you want 4 wheel steering.) Just like the rigid body, the wheel's torque function acts as an accumulator, we add torques to it and after it gets integrated the
torque is zeroed out. The <code>AddTorque</code> function is where you will apply a wheel torque from either the transmission (to make you go) or from the brakes (to make you stop). Internally the
wheel will generate a torque caused by the friction on the road.</p>
<p>The wheel object also needs a <code>SetSteering</code> function. This function calculates two vectors: an effective Side Direction, and an effective Forward Direction (both in vehicle space) that
the tire patch will act on. The force applied on the tire by the ground acting in the side direction will directly translate into the chassis. Meanwhile the force acting in the forward direction will
not only act on the chassis, but it will induce a rotation of the tire. Here is the <code>SetSteering</code> function; you will see I used the <code>Drawing2D.Matrix</code> to transform the initial
forward and side vectors by the steering angle (I had to convert the vectors to &ldquo;points" in order to transform them by the matrix.)</p>
<pre class="code">
public void SetSteeringAngle(float newAngle)
{
  Matrix mat = new Matrix();
  PointF[] vectors = new PointF[2];

  //foward vector
  vectors[0].X = 0;
  vectors[0].Y = 1;
  //side vector
  vectors[1].X = -1;
  vectors[1].Y = 0;

  mat.Rotate(newAngle / (float)Math.PI * 180.0f);
  mat.TransformVectors(vectors);

  m_forwardAxis = new Vector(vectors[0].X, vectors[0].Y);
  m_sideAxis = new Vector(vectors[1].X, vectors[1].Y);
}
</pre>
<h2>Force Calculation</h2>
<p>So, if the vehicle is sitting there not moving with its front wheels turned, and you push it, a force will be generated in the opposite direction you push. This force gets projected onto these two
directions. If the wheels were straight there would be no side force. So the vehicle would simply roll forward. But since the wheels are turned, there is a bit of the force that acts in the
&ldquo;effective side direction&rdquo; so we apply an opposite force to the chassis. This is what causes you to turn when you steer the wheels. To get this force that gets projected onto the two
directions, we need to first determine the velocity difference between the tire patch and the road. If the wheel is spinning at the same speed the ground is wizzing by, then there is effectively no
force acting on the vehicle. But as soon as you slam on the brakes and stop the wheel, there is a huge velocity difference and this is what causes the force that stops your car.</p>
<p>So here is the process broken down into 6 steps, for each wheel.</p>
<p><b>Step 1</b>, calculate the effective direction vectors (with steering function).</p>
<p><b>Step 2</b>, calculate velocity difference. The ground speed is determined via the &ldquo;PointVel&rdquo; function on the rigidbody, given the current wheel&rsquo;s world offset.</p>
<p><b>Step 3</b>, project this velocity onto the two effective directions.</p>
<p><b>Step 4</b>, generate an equal and opposite force for the two direction and call this the &ldquo;response force&rdquo;. This is what gets added to the chassis for each wheel.</p>
<p><b>Step 5</b>, calculate the torque that the forward response force created on the wheel, and add this to the wheel torque.</p>
<p><b>Step 6</b>, integrate the wheel torques into the wheel velocity.</p>
<p>That bit of code looks like this:</p>
<pre class="code">
public Vector CalculateForce(Vector relativeGroundSpeed, float timeStep)
{
  //calculate speed of tire patch at ground
  Vector patchSpeed = -m_forwardAxis * m_wheelSpeed *
    m_wheelRadius;

  //get velocity difference between ground and patch
  Vector velDifference = relativeGroundSpeed + patchSpeed;

  //project ground speed onto side axis
  float forwardMag = 0;
  Vector sideVel = velDifference.Project(m_sideAxis);
  Vector forwardVel = velDifference.Project(m_forwardAxis, out forwardMag);

  //calculate super fake friction forces
  //calculate response force
  Vector responseForce = -sideVel * 2.0f;
  responseForce -= forwardVel;

  //calculate torque on wheel
  m_wheelTorque += forwardMag * m_wheelRadius;

  //integrate total torque into wheel
  m_wheelSpeed += m_wheelTorque / m_wheelInertia * timeStep;

  //clear our transmission torque accumulator
  m_wheelTorque = 0;

  //return force acting on body
  return responseForce;
}
</pre>
<h2>Almost Done!</h2>
<p>We&rsquo;re in the home stretch here now. Now we have a way to calculate the force each wheel generates on the chassis. Every frame, all we have to do is set our transmission and brake torques,
our steering angle, calculate each wheel force, add these to the chassis, and integrate the rigid body. Badaboom badabing, vehicle done! :)</p>
<h1>Conclusion</h1>
<p>Here is the <a href="http://downloads.gamedev.net/features/programming/2dcarphys/racing%20simulation%202d.zip">entire source code</a> for the project. If you have any questions or comments please
feel free to post them here and either I can make things more clear or maybe someone else could offer some better expertise. If you&rsquo;d like you can email me at Kincaid05 on google's fine
emailing service.</p>
<p>Thanks for reading and I hope this was informative.<br>
-Matt Kincaid</p>

]]></description>
		<pubDate>Sat, 15 Dec 2007 02:36:46 +0000</pubDate>
		<guid isPermaLink="false">8e9cd191d3eaf58c4d262677292270e5</guid>
	</item>
	<item>
		<title>Randomness without Replacement</title>
		<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/randomness-without-replacement-r2206</link>
		<description><![CDATA[A blade spider is at your throat. It hits and you miss. It hits again and you miss again. And again and again, until there's nothing left of you to hit. You're dead and there's a two-ton arachnid gloating over your corpse. Impossible? No. Improbable? Yes. But given enough players and given enough time, the improbable becomes almost certain. It wasn't that the blade spider was hard, it was just bad luck. How frustrating. It's enough to make a player want to quit.<br />
<br />
 "Game mechanics" is one of those terms that every designer talks about. Everybody agrees that game mechanics is an important subject within game design. Yet almost nobody discusses, in detail, how the design of a mechanism may satisfy a player. In this article, I'm going to dissect a mechanism germane to role-playing games, the randomization function for determining whether a player's attack hits or misses its target. Roll up your sleeves for a modest amount of mathematics—just enough to demonstrate what a game mechanism is.<br />
<br />
 <br />
<strong class='bbc'>Reducing Frustration</strong><br />
 In the opening story, one way to prevent frustrating results is to reduce randomness. Several massively multiplayer role-playing games, such as <em class='bbc'>Lineage 2</em>, reduce variance of hits and misses and reduce the variance of damage. Reason? As Alex Chacha stated, if the probability for a string of failures is above zero, then the probability for that string occurring at least once in the lifespan of a long game is very high ("Randomness," <em class='bbc'><a href='http://www.kanga.nu' class='bbc_url' title='External link' rel='nofollow external'>MUD-Dev Mailing List</a></em>, February 2004.). And once it does, it is a frustrating experience. So, in this article, let us call such a long string of consecutive failures <em class='bbc'>frustration</em>.<br />
<br />
 To reduce the occurrence of frustration, one possibility is to change the mechanism that models the randomness. For instance, let's change the method from sampling with replacement to sampling without replacement.<br />
<br />
 But first, to understand this lingo, we need to know a little probability theory. It shouldn't be too hard for us, since probability theory was commissioned, in 1654, as the science of dice and card games. So we're in familiar territory: the mathematics of dice and cards. In probability, when a result of a random function is taken, it is called <em class='bbc'>sampling</em>. There are two basic methods for sampling: <em class='bbc'>with replacement</em> (as in a die roll), or <em class='bbc'>without replacement</em> (as in drawing cards from a deck). The difference seems simple, but the implications, as we shall see, may be dramatic.<br />
<br />
 Back to the problem at hand: To reduce frustration, change from sampling with replacement to sampling without replacement. Basically, instead of rolling a die, draw a card. Let's use Open Game Content (OGC) as shared vocabulary. This is the system that Wizards of the Coasts based <em class='bbc'>Dungeons & Dragons</em> 3.5 on. So, instead of rolling a twenty-sided die (1d20), draw from a deck of twenty cards, perfectly shuffled.<br />
<br />
 The key difference in the mechanism may be illustrated by a deck of cards alone. With replacement, after each draw, the card is shuffled back into the deck. Without replacement, the drawn cards are then discarded. Only after the deck has been consumed is the discard pile shuffled to reconstitute a full deck. To keep the analysis simple and further reduce frustration, remove one of the hit cards from the deck, and shuffle the remaining 19 cards. Then place this hit card on top of the shuffled deck.<br />
<br />
 Suppose, in OGC terms, that the player has a melee attack of +0, then he would hit armor class 11 about 50% of the time. This may be modeled, with replacement, as a probability of success of 50%. To model this probability, without replacement, imagine there are 10 hit cards and 10 miss cards. If details are required to account for modifiers, then there may be 20 cards, valued from 1 to 20. Either way, 10 of these cards will result in a hit, and 10 will result in a miss. Without replacement, the player could sample 10 misses in a row, but the probability of this frustration is much less than by sampling with replacement. But how much less probable is it?<br />
<br />
 <br />
<strong class='bbc'>Counting Cards</strong><br />
 Calculating the probability of frustration with replacement is simple. Suppose <em class='bbc'>f</em> equals the number of consecutive misses that will result in frustration, which we shall consider at 10 consecutive misses. With replacement, this is equivalent to a binomial distribution with a given probability of missing being the measure of consecutive trials. With a probability of a single failure being 50%, we may understand Equation 1. This logic is simple. The probability of failure ten times a row is the multiplication of the probability of failure ten times. So, in a sequence of ten attacks, the probability of frustration is about one in a thousand.<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/design/randomness/image001.gif' alt='Posted Image' class='bbc_img' /></span><br />
Equation 1. The probability of frustration, with replacement.<br />
<br />
 Calculating the probability of frustration without replacement is complicated, because the probability of each attack hitting depends on the success or failure of the previous attacks. A general method to solve problems of discrete probability is to count all the ways in which the event may occur, and divide this number by the count of all ways in which any outcome may occur.<br />
<br />
 In order to count possible occurrences of frustration, recall that the probability equals the number of ways to have a consecutive string of 10 misses out of 20 attacks. To simplify analysis and further limit frustration, set the first attack to be one of the hits. This corresponds to rolling a natural 20 in OGC. Since frustration (i.e., the string of 10 misses) is immutable, this is equivalent to the number of ways to select a single string of 1 out of 10. Recalling the basics of <em class='bbc'>combinatorics</em> (which is the mathematics of counting), this simplification makes computation trivial, as shown in Equation 2.<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/design/randomness/image002.gif' alt='Posted Image' class='bbc_img' /></span><br />
Equation 2. How many ways an attacker may be frustrated, without replacement.<br />
<br />
 Then count the total number of ways to have 9 hits and 10 misses in a sequence of 19 attacks, as shown in Equation 3.<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/design/randomness/image003.gif' alt='Posted Image' class='bbc_img' /></span><br />
Equation 3. How many ways an attacker may attack, without replacement.<br />
<br />
 By dividing the count of frustrations by the count of all attacks, we arrive at the probability of frustration, as demonstrated in Equation 4. So, the probability of frustration in the course of twenty attacks is about one in ten thousand.<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/design/randomness/image004.gif' alt='Posted Image' class='bbc_img' /></span><br />
Equation 4. The probability of frustration, without replacement.<br />
<br />
 By dividing the solution of Equation 4 by Equation 1, we see that the sample without replacement decreases the probability of frustration by an order of magnitude, shown in Equation 5. To keep the analysis simple, multiply the probability of frustration with replacement by 2 (or divide without replacement by 2), since the probability in a sequence of 20 attacks (without replacement) is being compared to a sequence of 10 attacks (with replacement).<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/design/randomness/image005.gif' alt='Posted Image' class='bbc_img' /></span><br />
Equation 5. Nonreplacement dramatically decreases frustration.<br />
<br />
 Clearly, this mechanism reduces frustration. Furthermore, the mechanism without replacement guarantees never to have more than 10 consecutive misses (since the 1+20<em class='bbc'>k</em>th occurrence always hits).<br />
<br />
 Although the above analysis is only a solution for one of the parameters that a player may have of hitting an opponent (i.e., melee attack of +0 versus armor class 11), the same analysis can be carried out on all possible parameters. Likewise, this analysis can be carried out for any given lower bound to frustration. If worst-case analysis of player satisfaction had predetermined 5 consecutive misses to be the maximum tolerance before frustration occurs, then the deck could be divided into two separate decks, each without replacement, so long as each deck had no more than 5 in it. For the sake of uniformity, two decks might be evenly divided (i.e., 75% success rate = 7 out of 10 and 8 out of 10).<br />
<br />
 <br />
<strong class='bbc'>God Does Not Play Dice—He Plays Cards</strong><br />
 This deck mechanism is not without its costs. A little detour from the mathematics department and into the computer science department will explain why. Each mechanism is implemented from an <em class='bbc'>algorithm</em> (which is a precise procedure for the rules of the game). Computing the amount of time required for the die mechanism is straightforward, as listed in Table 1.<br />
<br />
 <br />
<br />
   <strong class='bbc'>Step in the algorithm</strong> <strong class='bbc'>Computations</strong>   For 20 attacks: 20               Roll a die.             <em class='bbc'>d</em>   <strong class='bbc'>Total Time Complexity</strong> 20 <em class='bbc'>d</em>   <br />
Table 1. Algorithm outline of a die mechanism. The deck mechanism is not much more complicated. A naive shuffling algorithm can shuffle in linear time with one random call per element. So, this implies a running time not worse than 19 fold of the running time of the die mechanism. This shuffling only needs to be called once every 20 attacks. As listed in Table 2, the <em class='bbc'>time complexity</em> (which is an abstraction of the amount of time required to execute the algorithm) for a card mechanism is greater than the die mechanism, but not by much. Although there are two operations to perform instead of one, the drawing of a card (<em class='bbc'>c</em>) from a shuffled deck is a trivial operation. In addition, within an efficient shuffling algorithm, shuffling one card in a deck of 19 (<em class='bbc'>s</em>) is approximately comparable to rolling a die with 19 sides (<em class='bbc'>d</em>).<br />
<br />
 <br />
<br />
   <strong class='bbc'>Step in the algorithm</strong> <strong class='bbc'>Computations</strong>   Shuffle a deck of 19 cards. 19 <em class='bbc'>s</em>   For 19 attacks: 19               Draw a card.             <em class='bbc'>c</em>   <strong class='bbc'>Total Time Complexity</strong> 19 <em class='bbc'>c</em> + 19 <em class='bbc'>s</em> = 19 (<em class='bbc'>c</em> + <em class='bbc'>s</em>)   <br />
Table 2. Algorithm outline of a card mechanism. A more elegant algorithm may shuffle one card per attack, which means one randomization per attack, as listed in Table 3. This does not alter the total time complexity, but does distribute the computations more evenly, so that there is not a delay (for shuffling) after each 20th attack.<br />
<br />
 <br />
<br />
   <strong class='bbc'>Step in the algorithm</strong> <strong class='bbc'>Computations</strong>   For 19 attacks: 19               Draw a card.             <em class='bbc'>c</em>               Shuffle that card.             <em class='bbc'>s</em>   <strong class='bbc'>Total Time Complexity</strong> 19 (<em class='bbc'>c</em> + <em class='bbc'>s</em>)   <br />
Table 3. Algorithm outline of a gradually shuffled card mechanism. Of course, compared to the die, the deck requires memory, but this may be as little as an additional 19 bits per player to as much as 50 bytes per player.<br />
<br />
 Albert Einstein once remarked on another detailed mechanism, a mechanism for the elementary fabric of the universe. When presented with the random mechanism for modeling quantum physics, Einstein said, "God does not play dice." In the case of our RPG, maybe the Creator plays cards, instead.<br />
<br />
 <br />
<strong class='bbc'>Does it Matter?</strong><br />
 Does it matter whether a die or deck is used? Both probabilities are negligible, making it unlikely for a designer to encounter such frustration. Yet even small probabilities, such as one in a thousand, are worth considering given enough players.<br />
<br />
 To understand, first we need to learn another distribution common to discrete probability. We want to know how many instances of player frustration will occur. Each instance is rare, so the mean of a Poisson distribution, <em class='bbc'>E</em>(<em class='bbc'>X</em>), is a good approximation, as formulated in Equation 6.<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/design/randomness/image006.gif' alt='Posted Image' class='bbc_img' /></span><br />
Equation 6. Poisson distribution models the count of frustrations.<br />
<br />
 In general, the Poisson distribution is used to measure the number of occurrences (<em class='bbc'>λ</em>) per unit time. We have already calculated the probability of a single instance of frustration (<em class='bbc'>p</em>). What remains to be determined are the number of attack strings in which frustration may occur (<em class='bbc'>n</em>). Let's consider two scenarios with sufficient sequences of player attacks, both in massively multiplayer games and in single-player games.<br />
<br />
 <br />
<strong class='bbc'>Case Study: Massively Multiplayer RPG</strong><br />
 For a simple example in a massively multiplayer role-playing game (MMORPG), there could average 1000 attacks per player per hour. To be crude, this could be coarsened to 100 strings of 10 attacks (Actually, only one of the ten possible combinations of ten consecutive failures conform to this demarcation). If—admittedly oversimplified—there were, for a reasonably small MMORPG, an average of 100 simultaneous players per day with uniform distribution of attacks, and independence of attacks, then there would be 100 strings / hour (24 hours / day) 30 days / month. The arithmetic equals 72,000 strings per month. Since this is very large and the probability is very small, the Poisson distribution approximates, with a rate of <em class='bbc'>λ</em> = <em class='bbc'>n p</em>. The expected number of frustrations is solved in Equation 7.<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/design/randomness/image007.gif' alt='Posted Image' class='bbc_img' /></span><br />
Equation 7. Expected number of frustrations per month, with replacement.<br />
<br />
 So there's going to be, on average for a low-traffic MMP, given these simplistic preconditions, 70 strings of frustration (i.e., 10 consecutive misses) per month using a mechanism analogous to a 1d20 die roll. Whereas, without replacement (a mechanism analogous to a 20-card deck), the expected number of frustrations is computed in Equation 8. For approximation, the number of trials is divided by two, because this is a sequence of 20, instead of a sequence of 10.<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/design/randomness/image008.gif' alt='Posted Image' class='bbc_img' /></span><br />
Equation 8. Expected number of frustrations per month, without replacement.<br />
<br />
 So, there are about 18 times fewer occurrences of frustration. A distribution of the frustration may be estimated by the Poisson distribution, as shown in Figure 1. Because only whole numbers can occur, the distribution has been stepped at the rounded (midpoint) value of a continuous Poisson distribution.<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/design/randomness/image009.gif' alt='Posted Image' class='bbc_img' /></span><br />
Figure 1. Distribution of frustration without replacement (blue) or with replacement (magenta).<br />
<br />
 From comparing the distributions, it is obvious that without replacement, there are almost certainly going to be fewer cases of frustration.<br />
<br />
 <br />
<strong class='bbc'>Case Study: Single-Player RPG</strong><br />
 There's no theoretical or practical reason why such methods could not be applied to single-player and multiplayer RPG combat. The fact is, a game that sells a million copies, can expect similar figures to an MMP. It is a difference of penetration and time. The same Poisson distribution applies. Suppose the average player of a single-player RPG spends 10 hours with the game (since many more players quit sooner than those that play longer). If the rate of attacks remains constant (1000 attacks per hour), then only 7200 copies of the game need be sold to have the equivalent of a month of the modestly populated MMORPG above.<br />
<br />
 <br />
<strong class='bbc'>Every Mechanism Should be Designed as Simple as Possible, but Not Simpler</strong><br />
 Einstein also said, "Everything should be made as simple as possible, but not simpler." Don't let mathematical precision dominate your analysis of a mechanism. While understanding the subtleties of a mechanism can make or break the design of a game, the relevance of the number crunching must be maintained.<br />
<br />
 In this example, we computed the difference, not in terms of all kinds of player frustration that may occur, but only with one single variation to a mechanism within the game. We simplified the situation in order to keep the math brief. We did not consider players with probabilities to hit at above or below 50%, nor did we strictly adhere to the definition of independence for a Poisson distribution in the die mechanism. Astute readers will have also noted that the deck mechanism does not randomize the first card drawn. Doing so would further complicate the calculation of probability. Therefore, our result is only an approximation for a special deck.<br />
<br />
 A more precise analysis was not necessary to prove the fitness of the deck mechanism. Bear in mind that a designer can correctly solve a problem but fail to solve the right problem. In this article, we honed in on one mechanism, ignoring the rest of the game and its effect on the player's satisfaction. Even if it were mathematically tractable, computing the distribution of loss of players due to this careful definition of one type of frustration is a tougher problem.<br />
<br />
 <br />
<strong class='bbc'>About the Author</strong><br />
 David Kennerly directed five massively multiplayer games in the US and Korea. He localized Korea's first world, <em class='bbc'>The Kingdom of the Winds</em>, and designed the social system of <em class='bbc'>Dark Ages: Online Roleplaying</em>. Before joining Nexon in 1997, he designed <em class='bbc'>The X-Files Trivia Game</em> for 20th Century Fox, and troubleshot US Army networks in Korea.<br />
<br />
 David encourages creativity among developers and players. He helped organize MUD-Dev Conferences, and founded an online library of fan fiction. David has authored on game design for Charles River Media, ITT Tech, Westwood College, Gamasutra.com, and IGDA. To discuss this article with the author, please visit his website <a href='http://www.finegamedesign.com/' class='bbc_url' title='External link' rel='nofollow external'>www.finegamedesign.com</a><br />
<br />
 <br />
<strong class='bbc'>Further Reading</strong><br />
 Jay L. Devore, <em class='bbc'>Probability and Statistics for Engineering and the Sciences</em>. "Chapter 3: Discrete Random Variables and Probability Distributions." 6 ed. Brooks/Cole: USA, 2004.<br />
<br />
]]></description>
		<pubDate>Wed, 16 Feb 2005 16:11:45 +0000</pubDate>
		<guid isPermaLink="false">dfcebbaf79842c2e6fca7b77741de3a6</guid>
	</item>
	<item>
		<title>A Simple Time-Corrected Verlet Integration Method</title>
		<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/a-simple-time-corrected-verlet-integration-method-r2200</link>
		<description><![CDATA[<br />
<strong class='bbc'>Introduction</strong><br />
 Verlet integration is a nifty method for numerically integrating the equations of motion (typically linear, though you can use the same idea for rotational). It is a finite difference method that's popular with the Molecular Dynamics people. Actually, it comes in three flavors: the basic Position, the Leapfrog and the Velocity versions. We will be discussing the Position Verlet algorithm in this paper. It has the benefit of being quite stable, especially in the face of enforced boundary conditions (there is no explicit velocity term with which the position term can get out of sync). It is also very fast to compute (almost as fast as Euler integration), and under the right conditions it is 4<sup class='bbc'>th</sup> order accurate (by comparison, the Euler method is only 1<sup class='bbc'>st</sup> order accurate, and the second order Runge-Kutta method is only 2<sup class='bbc'>nd</sup> order accurate [go figure]).<br />
<br />
 The disadvantages of the Verlet method are that it handles changing time steps badly, it is not a self-starter (it requires 2 steps to get going, so initial conditions are crucial), and it is unclear from the formulation how it handles changing accelerations. In this paper we will discuss all of these shortcomings, and see how to minimize their impact. The modified Verlet integrator is referred to as the Time-Corrected Verlet (TCV) and is shown below with its original counterpart. The computations used to generate the graphs for this paper are included in <a href='http://downloads.gamedev.net/features/programming/verlet/TimeCorrectedVerlet.xls' class='bbc_url' title='External link' rel='nofollow external'>this Excel file</a>.<br />
<br />
 Original Verlet:<br />
x<sub class='bbc'>i+1</sub> = x<sub class='bbc'>i</sub> + (x<sub class='bbc'>i</sub> - x<sub class='bbc'>i-1</sub>) <sub class='bbc'>+</sub> a * dt * dt<br />
<br />
 Time-Corrected Verlet:<br />
x<sub class='bbc'>i+1</sub> = x<sub class='bbc'>i</sub> + (x<sub class='bbc'>i</sub> - x<sub class='bbc'>i-1)</sub> * (dt<sub class='bbc'>i</sub> / dt<sub class='bbc'>i-1</sub>) + a * dt<sub class='bbc'>i</sub> * dt<sub class='bbc'>i</sub><br />
<br />
 To see why the TCV is an improvement, we need to see the math behind the original Verlet method.<br />
<br />
 <br />
<strong class='bbc'>Math</strong><br />
 In this paper we will be talking exclusively about point masses, which are acted on by forces. Well, we all know about Newton's little equation: <em class='bbc'>Force=d(Momentum)/dt</em>. <em class='bbc'>Momentum=mass*velocity</em> and for non-relativistic speeds the mass is constant, removing our need for the chain rule, and yielding our familiar <em class='bbc'>F=ma</em>. So if all the forces acting on the point mass are summed (the vector <em class='bbc'>F</em>), then scaled by (<em class='bbc'>1.0/m</em>) we have the acceleration (<em class='bbc'>a</em>) of the point mass. Since we know how to go from force to acceleration, we will be starting from the acceleration term to keep the math less cluttered. In actual applications you will almost always be summing forces, then converting to accelerations.<br />
<br />
 Most of the graphs presented in this paper include the matching Euler simulation, just for reference. The Euler algorithm is extremely simple, and it will not be derived here. However, the equations are included below for your reference (order is important):<br />
<br />
 v = v + a * dt<br />
x = x + v * dt<br />
<br />
 There is a more accurate version, but it is not strictly the Euler method, so it will not be used for this paper. However it does give 2<sup class='bbc'>nd</sup> order accurate results, instead of merely 1<sup class='bbc'>st</sup> order:<br />
<br />
 x = x + v * dt + 0.5 * a * dt * dt<br />
v = v + a * dt<br />
<br />
 Please note that there is a faster way to derive the Verlet method's math* than what will be shown here, however it does not provide the insight needed to overcome the issues mentioned in the introduction. So we'll start from a few basic principles: <em class='bbc'>a=dv/dt</em>, and <em class='bbc'>v=dx/dt</em>. So for any given point mass, if we know the current position, velocity and acceleration (the acceleration must be constant over the given time step), we can compute exactly where it will be after the time step (<em class='bbc'>dt</em>) has elapsed.<br />
<br />
 (1)   x<sub class='bbc'>i+1</sub> = x<sub class='bbc'>i</sub> + v<sub class='bbc'>i</sub> * dt<sub class='bbc'>i</sub> + 0.5 * a<sub class='bbc'>i</sub> * dt<sub class='bbc'>i</sub> * dt<sub class='bbc'>i</sub><br />
<br />
 or<br />
<br />
 (1a)   x<sub class='bbc'>i+1</sub> - x<sub class='bbc'>i</sub> = v<sub class='bbc'>i</sub> * dt<sub class='bbc'>i</sub> + 0.5 * a<sub class='bbc'>i</sub> * dt<sub class='bbc'>i</sub> * dt<sub class='bbc'>i</sub><br />
<br />
 Now, if we wanted that equation formulated without the velocity term, we could replace it with some other known state variable, such as the position x.  But since we don't know x<sub class='bbc'>i+1</sub> yet, we shift the whole equation back a step:<br />
<br />
 (2)   x<sub class='bbc'>i</sub> - x<sub class='bbc'>i-1</sub> = v<sub class='bbc'>i-1</sub> * dt<sub class='bbc'>i-1</sub> + 0.5 * a<sub class='bbc'>i-1</sub> * dt<sub class='bbc'>i-1</sub> * dt<sub class='bbc'>i-1</sub><br />
<br />
 and we can use simple integration to see that:<br />
<br />
 (3)   v<sub class='bbc'>i</sub> = v<sub class='bbc'>i-1</sub> + a<sub class='bbc'>i-1</sub> * dt<sub class='bbc'>i-1</sub><br />
<br />
 or<br />
<br />
 (3a)   v<sub class='bbc'>i-1</sub> = v<sub class='bbc'>i</sub> - a<sub class='bbc'>i-1</sub> * dt<sub class='bbc'>i-1</sub><br />
<br />
 and we substitute that into equation (2):<br />
<br />
 (4)   x<sub class='bbc'>i</sub> - x<sub class='bbc'>i-1</sub> = (v<sub class='bbc'>i</sub> - a<sub class='bbc'>i-1</sub> * dt<sub class='bbc'>i-1</sub>) * dt<sub class='bbc'>i-1</sub> + 0.5 * a<sub class='bbc'>i-1</sub> * dt<sub class='bbc'>i-1</sub> * dt<sub class='bbc'>i-1</sub><br />
<br />
 or<br />
<br />
 (4a)   x<sub class='bbc'>i</sub> - x<sub class='bbc'>i-1</sub> = v<sub class='bbc'>i</sub> * dt<sub class='bbc'>i-1</sub> - 0.5 * a<sub class='bbc'>i-1</sub> * dt<sub class='bbc'>i-1</sub> * dt<sub class='bbc'>i-1</sub><br />
<br />
 For this next step we need to make a big assumption, the importance of which will be seen later: If we assume that neither the acceleration nor the time step vary between steps (i.e. that a<sub class='bbc'>i-1</sub> = a<sub class='bbc'>i</sub> = a and that dt<sub class='bbc'>i-1</sub> = dt<sub class='bbc'>i</sub> = dt) then we note that:<br />
<br />
 (5)   x<sub class='bbc'>i</sub> - x<sub class='bbc'>i-1 +</sub> a * dt * dt = v<sub class='bbc'>i</sub> * dt - 0.5 * a * dt * dt + a * dt * dt<br />
<br />
 or<br />
<br />
 (5a)   x<sub class='bbc'>i</sub> - x<sub class='bbc'>i-1 +</sub> a * dt * dt = v<sub class='bbc'>i</sub> * dt + 0.5 * a * dt * dt<br />
<br />
 You'll notice that the right hand side of equation (5a) is exactly the last half of equation (1), so we can work the modified equation (5a) back into equation (1):<br />
<br />
 (6)   x<sub class='bbc'>i+1</sub> = x<sub class='bbc'>i</sub> + (x<sub class='bbc'>i</sub> - x<sub class='bbc'>i-1</sub>) <sub class='bbc'>+</sub> a * dt * dt<br />
<br />
 and there you have the traditional Verlet Position integration method.<br />
<br />
 <br />
<strong class='bbc'>Fundamental Problems</strong><br />
 As you saw from the derivation's step (5), the two criteria needed to make the Verlet algorithm exact are constant acceleration and constant time step. For most practical cases we cannot guarantee either of these criteria. Of course, there are some simple cases where both criteria will be met. For example, simple projectile physics simulated by a physics engine which uses fixed time steps will yield perfect results. As soon as you add friction, springs or constraints of any kind you nullify the constant acceleration criterion, and adapting your time step to your game's framerate will nullify the constant time step criterion.<br />
<br />
 I am not going to address the constant acceleration criterion, mainly because explicit integrators (such as this one) must assume the constant acceleration principle, which is violated the instant you start simulating a complex system. Take the example of a point mass connected to a spring: as soon as it starts to move, the spring force, and thus the acceleration, changes. Even equation (1) required that the acceleration be constant throughout a time step. The error introduced by assuming that a<sub class='bbc'>i-1 =</sub> a<sub class='bbc'>i</sub> is actually implicit in our choosing an explicit scheme without knowing how the acceleration changes. We are effectively setting d(a)/dt (a.k.a. the "jerk") to 0.0. The other reason I will ignore this issue is that, empirically, the standard Verlet method already handles changing accelerations better than the Euler method (or even the improved variation on the Euler method), as long as the time step is fixed. Note that the Time-Corrected Verlet will be identical to the original Verlet when the time step is fixed. Observe the following graphs:<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/programming/verlet/proj-test.png' alt='Posted Image' class='bbc_img' /></span><br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/programming/verlet/poly-test.png' alt='Posted Image' class='bbc_img' /></span><br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/programming/verlet/sine-test.png' alt='Posted Image' class='bbc_img' /></span><br />
<br />
 The error introduced by the constant time step assumption is something that can be easily ameliorated. This will be shown in the section entitled "A Simple Time-Correction Scheme".<br />
<br />
 <br />
<strong class='bbc'>Implementation Problems</strong><br />
 A large source of inaccuracy when using the Verlet scheme stems from the improper specification of initial conditions. Looking at equation (6) and trying to fit it into the form of equation (1) (which may be more familiar) may yield (improper) reasoning like this: the first (x<sub class='bbc'>i</sub>) term is the position contribution, the second (x<sub class='bbc'>i</sub> - x<sub class='bbc'>i-1</sub>) term is basically the velocity contribution, and the (a * dt * dt) term is clearly the acceleration contribution. So when simulating the traditional projectile path, setting x<sub class='bbc'>0</sub> = 0.0, and x<sub class='bbc'>-1</sub>=x<sub class='bbc'>0</sub> - v<sub class='bbc'>0</sub> * dt<sub class='bbc'>0</sub>, and running the simulation from there will give the wrong results, as can be seen in the following graph:<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/programming/verlet/projectile-ic.png' alt='Posted Image' class='bbc_img' /></span><br />
<br />
 This is because both the second and third terms include acceleration information. So, when setting the current state explicitly (i.e. the position and velocity initial conditions), remember to use equation (2). Shooting simulations depend upon starting with accurate initial conditions. The larger the initial time step, the less accurate your computed initial state will be if you do not use equation (2).<br />
<br />
 <br />
<strong class='bbc'>A Simple Time-Correction Scheme</strong><br />
 The remaining fundamental problem with the Verlet integration method lies with its assumption of a constant time step. The (x<sub class='bbc'>i</sub> - x<sub class='bbc'>i-1</sub>) term from equation (4a) is the portion of the equation which is dependent on the constant acceleration and constant time step assumptions. It has been explained (OK, hand-waved away) why the usage of the last time step's acceleration will not be corrected, but we still have the problem of dt<sub class='bbc'>i-1</sub> being stale information. Rewriting equation (4) yet again, we see that:<br />
<br />
 (4b)   x<sub class='bbc'>i</sub> - x<sub class='bbc'>i-1</sub> = (v<sub class='bbc'>i</sub> - 0.5 * a<sub class='bbc'>i-1</sub> * dt<sub class='bbc'>i-1</sub>) * dt<sub class='bbc'>i-1</sub><br />
<br />
 so taking the easy way out and ignoring the dt<sub class='bbc'>i-1</sub> linked with the acceleration, I can swap out the old dt<sub class='bbc'>i-1</sub> for my new dt<sub class='bbc'>i</sub> by multiplying (4b) by (dt<sub class='bbc'>i</sub> / dt<sub class='bbc'>i-1</sub>). Plugging all of this in yields my final form of the Time-Corrected Verlet integration method:<br />
<br />
 (7)   x<sub class='bbc'>i+1</sub> = x<sub class='bbc'>i</sub> + (x<sub class='bbc'>i</sub> - x<sub class='bbc'>i-1)</sub> * (dt<sub class='bbc'>i</sub> / dt<sub class='bbc'>i-1</sub>) + a * dt<sub class='bbc'>i</sub> * dt<sub class='bbc'>i</sub><br />
<br />
 You will notice that when the last frame's time step equals the current frame's time step, the modifier term becomes 1.0, yielding the traditional form of the Verlet equation. As an optimization note, only one value needs to be stored per frame, as the dt was constant for all points in the last frame. So the term (dt<sub class='bbc'>i</sub> / dt<sub class='bbc'>i-1</sub>) can be computed once per frame and stored in a variable. At the end of the Verlet update subroutine simply store the current frame's dt as old_dt. Likewise, dt<sub class='bbc'>i</sub> * dt<sub class='bbc'>i</sub> can be computed once and stored in a variable, saving a multiplication.<br />
<br />
 To show how the Time-Corrected Verlet behaves, a spreadsheet was set up with the TCV, the original Verlet and Euler's method, each simulating three different problems with known solutions. These are the same tests as were performed earlier, but with randomized time steps. Of course since every time step (except the first) was random, the graph looked different each time a simulation was "run". Sometimes both the original Verlet and the TCV simulations were similar, however the original Verlet always fell further away from the exact solution than the TCV version eventually. Here are some sample graphs:<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/programming/verlet/proj-rand.png' alt='Posted Image' class='bbc_img' /></span><br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/programming/verlet/poly-rand.png' alt='Posted Image' class='bbc_img' /></span><br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/programming/verlet/sine-rand.png' alt='Posted Image' class='bbc_img' /></span><br />
<br />
 <br />
<strong class='bbc'>Conclusion</strong><br />
 Using the Time-Corrected form of the Verlet integration method with the proper equation for initializing the state makes the TCV integration scheme a simple, yet powerful method for doing game physics, even with changing frame rates.<br />
<br />
 It restores some of the accuracy of the method (still 4th order with constant time steps, between 2nd and 4th with changing dt), while maintaining its cheap numerical cost. I hope this helps a bit when implementing your own physics simulation code.<br />
<br />
 * Hint: remember the central difference 2<sup class='bbc'>nd</sup> derivative approximation?<br />
d<sup class='bbc'>2</sup>x / dt<sup class='bbc'>2</sup> = a<sub class='bbc'>i</sub><sup class='bbc'>2</sup>= (x<sub class='bbc'>i+1</sub> - 2*x<sub class='bbc'>i</sub> + x<sub class='bbc'>i+1</sub>) / dt<sup class='bbc'>2</sup><br />
<br />
]]></description>
		<pubDate>Sun, 06 Feb 2005 23:50:36 +0000</pubDate>
		<guid isPermaLink="false">b62973ddb1a4d7a0ea30a1052012af19</guid>
	</item>
	<item>
		<title>Opposing Face Geometry</title>
		<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/opposing-face-geometry-r2045</link>
		<description><![CDATA[<strong class='bbc'>Abstract:</strong><br />
OFG presents a new method for collision detection optimizations by performing a simple pre-calculation on both input objects. It is possible to reduce the number of faces necessary to check for intersection dramatically, from an order of <strong class='bbc'><em class='bbc'>O(mn)</em></strong> intersection tests to an order of <strong class='bbc'><em class='bbc'>O(k<sup class='bbc'>2</sup>)</em></strong>, or rather to a maximum of <strong class='bbc'><em class='bbc'>k<sup class='bbc'>2</sup> + 3k</em></strong> test operations, where <em class='bbc'>k</em> is a predetermined constant. The pre-calculation phase is of the order of <strong class='bbc'><em class='bbc'>O(m + n)</em></strong>. Therefore, for increasingly complex convex objects, the OFG method saves more and more processing time. The method's downside is that increasingly complex objects might need a very high constant and small faces are less suited for this type of optimization. The method is much better for relatively low detail 3D objects.<br />
<br />
 <br />
<strong class='bbc'>Introduction</strong><br />
 Collision detection is generalized as the means to detect whether any two objects in 3D space overlap. Over the years many models and ideas were suggested that attempt to either solve the problem entirely or approximate a solution. Of course, it has been shown that detecting collisions in a very accurate way is extremely computation intensive. Yet new ways and methods have been invented to optimize or accelerate the collision detection algorithms so those will be useable in real-time environments such as 3D simulations or 3D games. The method proposed here is called OFG and attempts to do the exact same thing - to optimize the collision detection algorithm by eliminating as many checks as possible.<br />
<br />
 This article assumes the reader knows simple vector notation and operations, namely the dot product and vector sizes.<br />
<br />
 <br />
<strong class='bbc'>The problem</strong><br />
 In real life, collision detection is a fact, it's simply how things work. Objects cannot occupy the same space, at least not usually. However, when dealing with computer programs it is clear that it's impossible to simulate the detail levels of the real world. In computer simulations the only way to actually define a 3D object is by defining the points from which its polygons are made. Each of these points is called a vertex, in plural - vertices. Defining a 3D object using only points connected by lines is the only way to represent a 3D object in a way that allows real-time simulations. This method is of course only an approximation, but when there are enough polygons making up an object, the approximation is very good.<br />
<br />
 The representation of a 3D object is very simple. Vertices can be connected by lines to create closed shapes called 'polygons'<sup class='bbc'>1</sup>(usually triangles). A collection of faces constitutes a closed 3D object and therefore the only information at our disposal for collision detection testing is the vertices information. The problem begins by trying to create a model for collision detection. It seems highly unlikely that objects collide at exactly their vertices, and this is logically correct as well. Consider two normal cubes the same size. The two cubes can collide in an infinite number of ways and orientations, even without their vertices touching each other's or any connecting line between vertices (edges)<sup class='bbc'>2</sup>. What is more logical is that either edges themselves pierce the other object's <em class='bbc'>faces</em>, or some variation to that effect. The question then arises, how to detect faces intersecting each other? or better yet, how to detect edges piercing other faces?<br />
<br />
 Well, the good news is that there are already good ways of testing for edges piercing faces. The bad news is that representing complex 3D objects requires a great deal of faces to look reasonably well, and since detecting intersection in an accurate way is slow in comparison to other optimized methods, this creates a big problem. In this article we will assume that detecting whether two faces intersect is a problem solved in a reasonable way and hence this article will not deal with methods for detecting actual intersection of a pair of faces, which is the most elementary test. For convenience a few methods are given in the appendix but it must be clear that OFG is a method for optimizing the entire process of object to object collision tests by dramatically reducing the number of faces needed for testing.<br />
<br />
 <br />
<strong class='bbc'>Basic assumptions and the most general case</strong><br />
 In order to simplify the problem some basic assumptions need to be made. Of course these might present some problems but it must be clear that the assumptions help solve the most simple case. Later on the algorithm will be improved to circumvent some of the problems arising from the assumptions.<br />
<br />
 The assumptions that we make are as follows:<br />
<br />
 <ul class='bbc'><li>The objects that the algorithm is dealing with are convex<sup class='bbc'>3</sup> 3D objects <em class='bbc'>only</em>. It is true that the algorithm will work for some concave<sup class='bbc'>4</sup> objects but care must be taken<sup class='bbc'>5</sup>. </li><li>Detection of any pair of faces colliding is a well-defined and solved problem. </li><li>Both objects have a pre-calculated center point. </li><li>The accuracy constant <em class='bbc'>k</em> is set to be <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img5.png' alt='Posted Image' class='bbc_img' /></span> (min/max estimates) </li><li>Object A has exactly <em class='bbc'>n</em> faces while object B has <em class='bbc'>m</em> faces.</li></ul> Under these assumptions, in order to detect a collision between objects, the most simple but inefficient method of checking every face in object A against every face in object B can be used. Actually, using the brute force method works for all types of objects, convex or concave. It makes no difference to the algorithm. For the brute force method therefore an order magnitude of <strong class='bbc'><em class='bbc'>O(nm)</em></strong> represents the algorithm's time complexity. The problem with this approach is obvious - detecting collision between complex objects becomes a very long operation. The more faces objects have, the more checks are needed. For two normal cubes, each with 6 sides (two faces per side, assuming each face is a triangle), the number of checks is: <strong class='bbc'>12 * 12 = 144</strong> tests between pairs of faces.<br />
<br />
 For two objects with 100 faces each, the number increases very fast: <strong class='bbc'>100 * 100 = 10,000</strong><br />
<br />
 For two objects with 200 faces each, the number increases again to: <strong class='bbc'>200 * 200 = 40,000</strong><br />
<br />
 It is clear that this method is highly inefficient when dealing with more and more complex objects.<br />
<br />
 <br />
<strong class='bbc'>The Opposing Face Geometry algorithm</strong><br />
 OFG is a method that at its basic level attempts to find in the simplest way the closest geometry elements two objects have. The algorithm attempts to find the closest faces both objects have in relation to one another while the number of desired faces to be found is determined by the accuracy constant <em class='bbc'>k</em>.<br />
<br />
 The OFG method consists of the following steps, each described in more detail in the following sections:<br />
<br />
 <ul class='bbcol decimal'><li>Optimization: check collision between object A's bounding sphere and object B's bounding sphere. </li><li>Find the closest <em class='bbc'>k</em> faces of object A relative to object B. </li><li>Calculate the geometric center of the new selection and the bounding sphere radius. </li><li>Find the closest <em class='bbc'>k</em> faces of object B relative to object A's <strong class='bbc'><em class='bbc'>new selection</em></strong> of <em class='bbc'>k</em> faces. </li><li>Calculate the geometric center of object B's new selection of faces and their maximal bounding sphere radius. </li><li>Optimization: check collision between spheres to determine if there is even a chance for face collisions. </li><li>Sort the two sets of faces by increasing distance (optional, might be replaces by a good insertion algorithm). </li><li>Test the two sets of faces against each other, starting with the closest pairs of faces.</li></ul> Analysis:<br />
<br />
 It's clear from the above steps that there are some preliminary preparations before any actual checks are done between faces. The time complexity of steps 1, 3, 5 and 6 is rather fixed: 2 operations, 3<em class='bbc'>k</em> operations, 3<em class='bbc'>k</em> operations and 2 operations again respectively and therefore contribute only little overhead to the entire process. Step 7 is basically a sorting operation for an array of <em class='bbc'>k</em> elements. If care is taken to insert the elements in an almost-sorted fashion, it is possible to use sorting algorithms that operate at almost O(<em class='bbc'>n</em>) on each of the arrays, or better. Since n=k in this case, O(2k) can be added to the overhead of the algorithm however up until now the overhead presented by these steps is rather constant no matter the complexity of the objects and is said to be geometry independent.<br />
<br />
 It will be shown that step 2 requires a time complexity of O(<em class='bbc'>n</em>) while step 4 requires a time complexity of O(<em class='bbc'>m</em>). Therefore the geometry dependant time complexity (and hence the most important one) is O(<em class='bbc'>n+m</em>).<br />
<br />
 As for step 8, the worst case scenario of testing <em class='bbc'>k</em> faces against <em class='bbc'>k</em> faces is <strong class='bbc'><em class='bbc'>O(k<sup class='bbc'>2</sup>)</em></strong>.<br />
<br />
 <em class='bbc'>Note: The accuracy constant</em> k plays a major role in the OFG algorithm. The higher <em class='bbc'>k</em> is, more faces are selected for testing and therefore more accurate collisions can be detected. Typical values are from 4 to 8 faces and the reasoning for this is explained later on in the appendix.<br />
<br />
 <br />
<strong class='bbc'>Step 1 - Checking for the <em class='bbc'>possibility</em> of a collision</strong><br />
 There is no real need to test <em class='bbc'>any</em> faces at all if the objects are far away from each other. This is logical but presents a problem: since objects are almost always non-spherical, one has to define a range from which no face testing will be performed and for a shorter range, face testing will be performed. But if the objects are non-spherical, what kind of range can be used that will also be efficient enough?<br />
<br />
 Well, the answer is of course, compounding each of the objects within their own bounding spheres. If the spheres don't overlap, it is certain that there is no collision. If the spheres overlap, there is the <em class='bbc'>possibility</em> of a collision and tests must be performed. It is quite simple creating a bounding sphere for each object and since a sphere is always the same when rotated (invariant when rotated), calculation of the bounding sphere and the object's geometrical center can be done at the initialization stage, usually when objects are loaded.<br />
<br />
 Calculating the geometric center is exactly finding the average of all the vertices that comprise an object:<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img9.png' alt='Posted Image' class='bbc_img' /></span><br />
<br />
 This relation gives the X coordinate of the object's center point by summing all X coordinates of all vertices in the object. Notice that in this relation <em class='bbc'>n</em> is NOT the number of faces but the number of vertices of the object. The same calculation can be done for the Y and Z coordinates. The weight functions W can be used to give different weights to vertices but in order to find the geometric center it is usually sufficient to use 1 for any W of any vertex.<br />
<br />
 After the center is found it is simply a matter of iterating the vertices again and finding the farthest vertex from the center and using that distance as the compound radius.<br />
<br />
 <br />
<strong class='bbc'>Step 2 - Finding the closest <em class='bbc'>k</em> faces of object A relative to B</strong><br />
 The first step in the OFG algorithm is to find the closest geometry object A has in relation to object B. In order to do this in an efficient manner, one very important assumption must be made:<br />
<br />
 <ul class='bbc'><li>Object B can be considered as a point object located at its center (object centers have been shown in step 1).</li></ul> This assumption is not a simple one, there is a lot of reasoning behind it. Mainly, in order to find the closest faces object A has relative to B, it is obvious that distances of faces must be considered. The problem is that finding the smallest distances between <em class='bbc'>every</em> face in A and <em class='bbc'>every</em> face in B has a time complexity of <strong class='bbc'><em class='bbc'>O(nm)</em></strong>, just as the easiest brute force method presented as the general case. Of course, this will not do.<br />
<br />
 The idea is to attempt to find distances of all faces in object A, relative to only <em class='bbc'>one</em> geometry property in B. That way, checking every face in A against only one geometry property of object B yields a time complexity of <strong class='bbc'><em class='bbc'>O(n)</em></strong>, where <em class='bbc'>n</em> is the number of faces in object A. The question then arises: what kind of geometric property an entire object has that can be used to represent the <em class='bbc'>entire</em> object?<br />
<br />
 Physicists sometimes assume very distant objects are a point object when trying to simplify problems in physics because when an object is very far, the contribution from any irregularities in the object's geometry are negligible.<br />
<br />
 For our purposes, this assumption is correct for <em class='bbc'>any</em> distance, mainly due to the fact that this algorithm deals strictly with convex 3D objects. For that reason, the closest faces an object can have to another object are the faces closest to the other object's center.<br />
<br />
 It is always true that if a certain face is closer to object B's center than another face, it is generally closer to object B than the other face.<br />
<br />
 Taking the 3 vertices (or more, depending on the engine involved) that constitute a face, it is possible to find that face's center in exactly the same way as finding an object's center. Using the center coordinate coupled with the two object's positions it is possible to automatically calculate a vector from the center of any face to the center of the other object.<br />
<br />
 In summary, the steps necessary to find the closest <em class='bbc'>k</em> faces of object A are:<br />
<br />
 <ul class='bbcol decimal'><li>Using both object's positions, calculate the relative position vector. Assuming <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img11.png' alt='Posted Image' class='bbc_img' /></span> is the center of object A (x,y,z - a 3D vector) and <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img12.png' alt='Posted Image' class='bbc_img' /></span> the center of object B, the vector connecting the center points is then: <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img13.png' alt='Posted Image' class='bbc_img' /></span> </li><li>Start looping through all faces of object A, find each face center relative to object A's center. Total time complexity is <strong class='bbc'><em class='bbc'>O(n)</em></strong>. It takes less operations to calculate the faces centers than to do it in the beginning and apply transformations on them. </li><li>For each face, find the vector connecting its center with object B's center, using the simple relation: <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img14.png' alt='Posted Image' class='bbc_img' /></span>, where <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img15.png' alt='Posted Image' class='bbc_img' /></span> is the vector connecting the center of face <strong class='bbc'><em class='bbc'>i</em></strong> with the center of object B, <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img17.png' alt='Posted Image' class='bbc_img' /></span> the relative positions of the two object's centers and <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img18.png' alt='Posted Image' class='bbc_img' /></span> is the position of the face relative to object A's center (the object it belongs to). Of course, <strong class='bbc'><em class='bbc'>i</em></strong> = 0,1,2,3...,<em class='bbc'>n</em>. </li><li>For each <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img15.png' alt='Posted Image' class='bbc_img' /></span>, find the vector's size: <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img19.png' alt='Posted Image' class='bbc_img' /></span> and store into selection*. Of course, the size itself is irrelevant, as is the direction of the vector. The only important quantity is the vector's size squared. Note that there is no need to take the square root because if a certain face's squared vector size is larger than another face's squared vector size, the same holds for the actual sizes themselves. </li><li>Depending on the insertion technique used to insert the distances (squared sizes of the relative position vectors), find the smallest <em class='bbc'>k</em> distances which should be straightforward if the insertion was done in an efficient way, and remember their corresponding faces.</li></ul> * Note: Several methods are available that create a semi-sorted array of <em class='bbc'>k</em> elements.<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/OFG_step1_gimped.png' alt='Posted Image' class='bbc_img' /></span><br />
Figure: Finding object A face vectors relative to object B's center<br />
<br />
 <br />
<strong class='bbc'>Step 3 - Calculate the geometric center of the selection and its bounding sphere</strong><br />
 After finding the closest <em class='bbc'>k</em> faces of object A relative to B it is important to be able to do quick tests in order to check the <em class='bbc'>possibility</em> of a collision between faces. For that reason and another reason outlined in step 4, the center of the new selection must be found and its bounding sphere.<br />
<br />
 Assuming the previous step has found the necessary <em class='bbc'>k</em> faces, finding the center is as simple as finding the average of all the selected faces centers. Remember, the selection itself is just a means to remember which faces are the closest, and each face has its center coordinate and a vector connecting the center of the face with the center of object B. Therefore we have:<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img20.png' alt='Posted Image' class='bbc_img' /></span><br />
<br />
 Where <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img21.png' alt='Posted Image' class='bbc_img' /></span> is of course the center of the new selection and <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img18.png' alt='Posted Image' class='bbc_img' /></span> is the position of the <em class='bbc'>i</em>'th face center relative to the object's center (as always). The resulting vector is the position of the new selection center relative to our object's (A) center.<br />
<br />
 Once the center is found, the farthest vertex from the new selection center gives the bounding sphere radius. This is a preparation phase for a later step where the possibility of face collision should be tested.<br />
<br />
 <br />
<strong class='bbc'>Step 4 - Finding the closest <em class='bbc'>k</em> faces of object B relative to the <em class='bbc'>new selection</em></strong><br />
 This part of the algorithm is very similar to step 2 in that it finds the closest faces in B relative to some point. However in this case the point that distances are calculated to is NOT object A's center. Rather, taking the center of the new selection found in step 2 and calculated in step 3 is better. True, for truly convex objects such as spheres there is no difference. Finding the faces in B that are closest to the generally closest faces in A yields better results. Not only is that more accurate but it helps the algorithm deal with objects that are not truly convex but only close to being convex.<br />
<br />
 Since this step is so similar to step 2, only the summary of the steps needed is presented:<br />
<br />
 <ul class='bbcol decimal'><li>Calculate the relative position vector between object B's center and the center of the new selection of <em class='bbc'>k</em> faces found earlier. Assuming <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img12.png' alt='Posted Image' class='bbc_img' /></span> is the center of object B and <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img22.png' alt='Posted Image' class='bbc_img' /></span> the center of the selection in object A, the vector connecting the center points is then: <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img23.png' alt='Posted Image' class='bbc_img' /></span> </li><li>Start looping through all faces of object B, find each face center relative to the center of the selection in object A. Total time complexity is <strong class='bbc'><em class='bbc'>O(m)</em></strong>. It takes less operations to calculate the faces centers than to do it in the beginning and apply transformations on them. </li><li>For each face, find the vector connecting its center with the center of the selection in object A, using the simple relation: <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img25.png' alt='Posted Image' class='bbc_img' /></span>, where <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img26.png' alt='Posted Image' class='bbc_img' /></span> is the vector connecting the center of face <strong class='bbc'><em class='bbc'>i</em></strong> with the center of the selection in object A, <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img27.png' alt='Posted Image' class='bbc_img' /></span> the relative positions of the center of object B and the center of the selection in object A and <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img18.png' alt='Posted Image' class='bbc_img' /></span> is the position of the face relative to object B's center (the object it belongs to). Of course, <strong class='bbc'><em class='bbc'>i</em></strong> = 0,1,2,3...,<em class='bbc'>m</em>. </li><li>For each <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img26.png' alt='Posted Image' class='bbc_img' /></span>, find the vector's size: <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img28.png' alt='Posted Image' class='bbc_img' /></span> and store into selection*. </li><li>Depending on the insertion technique used to insert the distances (squared sizes of the relative position vectors), find the smallest <em class='bbc'>k</em> distances which should be straightforward if the insertion was done in an efficient way, and remember their corresponding faces.</li></ul> * Note: Several methods are available that create a semi-sorted array of <em class='bbc'>k</em> elements.<br />
<br />
 <br />
<strong class='bbc'>Step 5 - Calculate the geometric center of the new selection and its bounding sphere</strong><br />
 In essence, step 5 is identical to step 3 only it operates on the newly selected faces in object B. Averaging the faces with the following relation:<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img20.png' alt='Posted Image' class='bbc_img' /></span><br />
<br />
 Will give the center of the newly selected faces in object B relative to B's center naturally. Once the bounding sphere radii of both the selection from object A and B are known it is a simple matter to accomplish the next step, step 6.<br />
<br />
 <br />
<strong class='bbc'>Step 6 - Test collision between the two selections' bounding spheres</strong><br />
 The last step before any accurate collision tests is the bounding sphere test for the two selections. Up until now the only test done is the bounding sphere test for the two objects that determine if there is a chance for a collision. Now that there are two sets of faces that have a bounding sphere, it is a simple matter of testing whether or not the spheres intersect in order to determine whether real geometry tests should be performed.<br />
<br />
 Denoting with <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img29.png' alt='Posted Image' class='bbc_img' /></span> the center of the selection in object A and <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img30.png' alt='Posted Image' class='bbc_img' /></span> the center of the selection in object B, the radii as <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img31.png' alt='Posted Image' class='bbc_img' /></span> and <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img32.png' alt='Posted Image' class='bbc_img' /></span> respectively, in order to determine if there is intersection the following relation holds:<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img33.png' alt='Posted Image' class='bbc_img' /></span><br />
<br />
 What this relation means is that if the size of the vector that connects the centers, squared, is smaller/equal to the sum of the radii, squared, there is the possibility of a collision between faces in the selections. Actually, the real check is against the square roots of both exp<b></b>ressi&#111;ns but it holds for the squares too. There is no need to waste valuable processing time in order to perform two square root operations. The size of the vector is naturally a dot product of it with itself.<br />
<br />
 <br />
<strong class='bbc'>Step 7 - Sort the two selections in ascending order</strong><br />
 This step can be omitted if wanted but it can help gain a small performance boost. Assuming two selections exist with <em class='bbc'>k</em> elements in each (the elements being the faces to be checked), this step just sorts each of the selections, from the face with the smallest distance to the face with the largest distance. The order of each sorting operation can vary depending on the algorithm and the insertion technique used earlier when building the selection sets. If the selections are <em class='bbc'>almost</em> sorted, even a simple algorithm such as bubble sort can work in a reasonable time (bubblesort works at <em class='bbc'>O</em>(<em class='bbc'>k</em>) for almost sorted arrays).<br />
<br />
 The algorithm to choose from is really up to the programmers implementing this step. It depends entirely on the insertion method used earlier and there are several good sorting algorithms.<br />
<br />
 <br />
<strong class='bbc'>Step 8 - Perform intersection tests on the two selection sets</strong><br />
 If the algorithm made it this far, it is now time to examine the geometry itself for collision. As input, there are two selections of <em class='bbc'>k</em> faces each, the closest faces between the two objects. Under the assumptions made earlier, the problem of testing for intersection of a pair of faces is a well solved problem (again, see the appendix for ways of doing this), therefore in this subsection a summary of the testing method is described. As mentioned earlier, <em class='bbc'>k</em> can be between 4 and 8.<br />
<br />
 It is possible to examine all the faces in one set against all the faces in the other set. After all, there are <em class='bbc'>k</em> faces in each set and there are two sets, thus the worst case time complexity is <strong class='bbc'><em class='bbc'>O(k<sup class='bbc'>2</sup>)</em></strong>. This holds true no matter what but certain optimizations on the order of the tests can make a difference.<br />
<br />
 <br />
<strong class='bbc'>Problems with the basic OFG algorithm</strong><br />
 The OFG algorithm suffers from three very serious problems:<br />
<br />
 <ul class='bbc'><li>The algorithm supports detection of mostly convex objects. Some concave objects will work as well but there are bound to be degenerate cases that cause the algorithm to fail. It hasn't been proven mathematically that there are any cases that will cause failure but assuming there aren't is not a good idea. </li><li>Moving objects in computer simulations are by nature problematic because time in computer systems is discrete. In numerical approximations, time is discrete and therefore object positions are calculated in time steps and are really "teleporting" in small steps to create the illusion of motion. The problem arises when the velocity of objects is very large and/or objects are very small. It is quite possible that an object will be close to another object while not colliding, yet at the next time step will be half intersecting with the other object. The problem is then what faces to test. After all, the "closest" faces the object previously had are now <em class='bbc'>inside</em> the other close object. Even more so, it's possible that if the velocity is large enough, the object might pass right through the other object without any way of us detecting this. </li><li>In a similar fashion, rotating objects pose another problem. If objects have an angular velocity (or momentum, whichever you prefer) it's possible that before the collision some faces are the closest selection while after a small time step, other faces should be the closest selection. For example, consider a normal cube floating above a table at a small height. The closest faces to the table are naturally the two faces (triangles) that comprise the base of the cube. If the cube is about to rotate 45 degrees in one time step (very fast rotation) it wouldn't be correct checking the base of the cube against the table.</li></ul> In the following subsections some solutions are presented that deal with said problems.<br />
<br />
 <br />
<strong class='bbc'>Solving the concavity problem</strong><br />
 Since some objects are almost convex and some are not even close to being convex, a method is required that can handle these objects. It just so happens that concave objects can be represented by a collection of convex objects. This is implied since any object can be approximated by triangles, which are convex polygons. If there is any doubt about whether an object will cause problems with the OFG algorithm, it is best to represent it using two or more convex objects.<br />
<br />
 This presents another slight difficulty: if an object is really a collection of objects, which object's geometry is used when building the selection set?<br />
<br />
 Well, the solution to this lies in the OFG method itself, but at the object level. Just as faces, it is possible to generalize the algorithm for objects. For example, if two concave objects exists that are made out of an assortment of convex objects each, consider the following scheme:<br />
<br />
 <ul class='bbcol decimal'><li>Find the closest object in collection A relative to the entire collection B. This implies each object in A has to have a center (this is mandatory for OFG anyway) and the entire collection has to have a center as well (averaging the centers of the objects, should be a part of initialization). </li><li>Find the closest object in collection B relative to the object found earlier in collection A. </li><li>Feed the two objects found to the OFG algorithm.</li></ul> <br />
<strong class='bbc'>Solving the discrete time problem</strong><br />
 A technique exists that makes this very easy to accomplish. Consider a 2D face passing <em class='bbc'>through</em> a wall straight to the other side. This is only possible in a computer simulation if the face is moving fast enough. If it is, it can find itself on the other side of the wall after a small time unit.<br />
<br />
 Consider connecting each vertex that comprise the face with the same vertex on an exact copy of the face but on the other side of the wall. Not only that, the copy face's position is in fact the position of the original face at the next time step (after one time unit has elapsed, this is easy to calculate). With this in mind, each pair of "connected" vertices make up an edge. Then, testing the new virtual edges created for intersection with the other object (in this case, the wall) will determine if there is a collision.<br />
<br />
 Actually, this is not enough. The following steps are in order:<br />
<br />
 <ul class='bbcol decimal'><li>Calculate the translation of object A after a time unit elapses. </li><li>Feed the two objects into the OFG algorithm, forgoing step 6 completely and without the bounding sphere calculations in steps 3 and 5. Also, there is no need to perform step 8 (the final step) of the OFG algorithm just yet. </li><li>Connect each vertex in selection A with the same vertex on the virtual selection of A that is translated by the amount calculated in step 1. This gives a vector that represents the edge to test against object B. </li><li>Test the newly created edges against the selection in object B found by the OFG algorithm. They are the most likely to be intersecting object B. </li><li>Test the original faces in selection A against the selection in B, as was intended in step 8 of the OFG algorithm. </li><li>Test the translated virtual selection of A against the selection of B using step 8 of the OFG algorithm.</li></ul> Naturally if any collision is found the entire process is stopped and action is taken. However, since objects are "teleporting", it isn't clear which faces should have collided provided time was not discrete. Figuring out which faces collided will help determine what action to take.<br />
<br />
 There are generally two ways of solving this, others may exists:<br />
<br />
 <ul class='bbcol decimal'><li>Using the translation found in step 1 earlier and given that it's easily possible to calculate the relative velocity of the two objects, it's possible to estimate the time of collision (therefore obtaining the delta time needed for the objects to collide). </li><li>Moving half of the distance (half a time unit) and checking for collisions. If collision occurred, great. If not, move another half, so on and so forth. This has a time complexity of log(<em class='bbc'>n</em>) times of performing all the collision tests.</li></ul> <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/OFG_step2_gimped.png' alt='Posted Image' class='bbc_img' /></span><br />
Figure: One face of the selection in A translated after one time unit.<br />
<br />
 These two methods should only be used in case a collision occurred in between time steps. If a collision occurred with the original selection or the virtual selection (the beginning position and the ending position respectively), there is no need to interpolate the collision time since the intersecting faces are known.<br />
<br />
 <br />
<strong class='bbc'>Solving for rotating objects</strong><br />
 For the general case of rotating objects, the same approach as in the discrete time solution can be applied. Instead of only translating the vertices and using them to create virtual edges, rotating and then translating the vertices solves the problem. Instead of having the selection in its starting position and ending position, have the virtual selection rotated before translation so it'll be rotated at its new position. Vertices are connected in exactly the same way and figuring the moment of collision if one occurred works in exactly the same way but with rotation in mind.<br />
<br />
 <br />
<strong class='bbc'>Appendix A - Detecting collision between two faces</strong><br />
 Up until now the problem of testing for collision between a pair of faces was a well solved problem. That meant that the algorithm assumed detecting if two faces intersect is a black box operation, the details weren't important for the algorithm itself. Still, in order to create a solid implementation of any collision detection scheme, the problem of intersecting faces must be solved. In this section two methods are presented that attempt this.<br />
<br />
 The first method is called the intersection-based collision detection and is basically an accurate way of detecting whether any two faces intersect each other. Other methods exist as well, however, the second method presented here is a hybrid method that incorporates bounding spheres and some basic geometry testing.<br />
<br />
 <br />
<strong class='bbc'>Intersection-based collision detection</strong><br />
 The problem of collision detection between faces can be broken down to two stages. A well known fact is that any two planes that are parallel don't intersect each other. A plane of course is a flat, infinitely thin, infinitely long surface in 3D space. Unless the planes that contain the faces are parallel, those two planes are going to intersect each other. The first stage would be to detect if any edges of the first face intersect the <em class='bbc'>plane</em> of the second face. That ensures that the first face at least intersects the plane that contains the second face, but it is not sufficient in order to determine if the first face intersects the actual second face. This will be dealt with in the second stage.<br />
<br />
 In order to determine if any edges in the first face pierce the second face's plane, the vertices making up the edges must be examined. For simplicity, if two points that define an edge fall on one side of the plane (containing the second face), the edge does not pierce that plane. Then, generalizing for the entire face, if all edges don't pierce the plane, the face does not pierce the plane. If any edge pierces the plane it is assured that at least one edge pierces the plane. For convex polygons there are <em class='bbc'>exactly</em> two edges piercing the plane.<br />
<br />
 The only thing left to solve is how to find whether an edge pierces the plane. It so happens that all points in space that satisfy the following equation fall on the plane:<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/columns/hardcore/ofg/img34.png' alt='Posted Image' class='bbc_img' /></span><br />
<br />
 This might be familiar to you. It is called the <em class='bbc'>plane equation</em>. Any point that lies on the plane itself will evaluate the equation to be true. It so happens that any points on one "side" of the plane produce a positive sign (instead of 0) and all the points on the other "side" produce a negative sign. Therefore, if an edge is defined by two points (vertices) and solving for both vertices gives the same sign, the edge is definitely not piercing the plane. The logical extension to this is to check all edges against the plane. The check becomes very simple:<br />
<br />
 <ul class='bbc'><li>Solve the plane equation of the second face for each vertex in the first face. If all vertices produce the same sign, the first face definitely doesn't pierce the plane in question. Creating the plane equation is easy given two vectors on that plane (three vertices of one face can give two vectors). If any vertex gives the other sign, there is a possibility of collision.</li></ul> If there was any piercing by any edge, the second stage should be used to actually detect whether the edges actually pierce the second face <em class='bbc'>itself</em>, unlike the plane tested against in the first step. Actually, this step is all that is needed in order to determine if two faces intersect. However, the second stage is much slower in comparison with stage one. Stage one can be used as an optimization to rule out any faces that definitely <em class='bbc'>don't</em> collide.<br />
<br />
 Because this algorithm deals with convex polygons (faces actually), this stage will assume the same. Since step one stopped when an edge that pierces the second plane was found, and there are actually two such edges (again, for convex polygons such as triangles), there must be exactly two intersection points between the face and the plane of the other face. Using the plane equation and solving for the x,y and z coordinates of the point that represent the intersection between the plane and the edge it is possible to find those two intersection points. Those points are naturally on the plane itself.<br />
<br />
 Once two intersection points are found, in order to determine whether the edge pierced the second face itself, at least one of the points must be <em class='bbc'>within</em> the second face!<br />
<br />
 What is left then is to determine whether a point is within a convex polygon or not. If one of them is within it, there is a definite collision. If both are not within it, there is definitely no collision. There is one very simple solution to this problem, called the <em class='bbc'>half-space</em> method. The halfspace method is a method to determine if a point lies within a convex polygon. For 2D polygons this is simple. Using the line equations of the edges and solving for the point gives either 0, a negative sign or a positive sign, just like in the previous step. However, our edges are vectors in 3D space so this doesn't apply here.<br />
<br />
 What can be done instead is create a plane that is perpendicular both to the normal of the face and the edge vector. That plane divides space into two parts and therefore the point must lie either on it, or on one of its sides. The same logic from the previous stage applies here as well:<br />
<br />
 <ul class='bbc'><li>Calculate the intersection points of the edges found piercing the plane in stage one using the second face's plane equation. </li><li>For each edge in the second face, take the cross product of the edge vector with the normal to the face, giving a perpendicular plane. </li><li>The points must lie either on the plane or on either side. Using the same logic as in stage one can determine this for each edge plane. </li><li>If the point lies in the same part of space ("side") for all planes corresponding to the edges of the face, the point is within the face and therefore a collision has occurred </li><li>If both points lie outside the planes of the edges (not all signs are the same for each point checked against the edge planes), there is definitely no collision.</li></ul> <br />
<strong class='bbc'>Hybrid collision detection between two faces</strong><br />
 This method is a proposed method that approximates intersection between a pair of faces. The idea is to find a bounding sphere for both faces. If the bounding spheres intersect (an easy and fast check), there is a need for a better check. If the bounding spheres do not intersect, there is definitely no intersection.<br />
<br />
 For intersecting bounding spheres, there is the possibility of collision. Consider using the logic in the previous method's stage one to determine whether edges on the first face pierce the second. Although this alone does not guarantee collision of course, coupled with the bounding spheres check it gives a reasonable chance for collision. That is, if the spheres collided AND an edge was found to be piercing the other face, most chances there is a collision. Of course, this method is only an approximation and will not give accurate results such as those provided by the intersection method. However, this method is by far much faster than the intersection based method.<br />
<br />
 Generally, the smaller the faces, the better this method works. This is because when the faces are smaller, there is less and less "free space" within the sphere. Less free space that can generate a collision between spheres but might not actually generate a collision between the faces themselves.<br />
<br />
 <br />
<strong class='bbc'>Appendix B - Determining <em class='bbc'>k</em>, the accuracy constant</strong><br />
 The reasoning behind assigning a proper <em class='bbc'>k</em> value are totally up to the engine in question. In most cases in a normal 3D surface, each vertex will share a maximum of four polygons (each made of two triangles). Of course, there are cases, such as the tip of a pyramid with <em class='bbc'>n</em> sides that do not satisfy this condition. For the first case, a normal 3D surface, each vertex can be shared by 8 triangles at most and 4 at the very minimum. Therefore those values are chosen as the default accuracy range for most purposes. Assigning a different value might serve different types of geometry better though, it has to be considered carefully.<br />
<br />
 For the cases where a vertex does not share only 8 triangles (such as the tip of an n-sided pyramid), it is a definite fact that if the vertex falls within another 3D object, all of the n-sides of the pyramid will intersect the other object. Therefore, any value for <em class='bbc'>k</em> that is one or more will suffice for this type of degenerate case. It happens that any 3D geometry can be represented either by the former representation or the latter. The latter has no bearing on the assignment of <em class='bbc'>k</em>. The former has and it has been shown that a value of 6 is the best average while 8 should give good accuracy.<br />
<br />
 <br />
<strong class='bbc'>About this &#100;ocument...</strong><br />
 <strong class='bbc'>Opposing Face Geometry<br />
A Collision Detection Optimization Scheme</strong> This document was generated using the <a href='http://www.latex2html.org/' class='bbc_url' title='External link' rel='nofollow external'><strong class='bbc'>LaTeX</strong>2HTML</a> translator Version 2002 (1.62)<br />
<br />
 Copyright © 1993, 1994, 1995, 1996, <a href='http://cbl.leeds.ac.uk/nikos/personal.html' class='bbc_url' title='External link' rel='nofollow external'>Nikos Drakos</a>, Computer Based Learning Unit, University of Leeds.<br />
Copyright © 1997, 1998, 1999, <a href='http://www.maths.mq.edu.au/%7Eross/' class='bbc_url' title='External link' rel='nofollow external'>Ross Moore</a>, Mathematics Department, Macquarie University, Sydney.<br />
<br />
 The translation was initiated by Lord Soth on 2004-01-05<br />
<br />
 <strong class='bbc'>Footnotes</strong><br />
<br />
   <a href="#tex2html1">1     In this article the term 'polygon' will be replaced by 'face'   2 Lines connecting two vertices are called 'edges'   3 Convex - A polygon (face) that has no "dents" in it.   4 Concave - A face that has "dents" in it. An edge connecting 2 vertices might fall outside the face.   5 Later on the problem of concave objects will be discussed    Lord Soth 2004-01-05<br />
<a href='mailto:lordsoth8@bigfoot.com' title='E-mail Link' class='bbc_email'>lordsoth8@bigfoot.com</a><br />
<a href='mailto:voguemaster@walla.co.il' title='E-mail Link' class='bbc_email'>voguemaster@walla.co.il</a><br />
ICQ: 5178515<br />
Copyright © 2003 All Rights Reserved]]></description>
		<pubDate>Thu, 19 Feb 2004 01:31:28 +0000</pubDate>
		<guid isPermaLink="false">fb598cb494b6e98253995d800fab908d</guid>
	</item>
	<item>
		<title>A Simple Quaternion-based Camera</title>
		<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/a-simple-quaternion-based-camera-r1997</link>
		<description><![CDATA[I looked through a thousand web pages for a good quaternion camera tutorial, and I could not find one. There is a good example on gametutorials.com that uses quaternions, but it uses them to rotate general objects and makes things a little more difficult than they actually need to be to use quaternions to make a camera. Therefore, in this article I am going to present a simple quaternion-based camera that can be used to rotate the view of your camera using the mouse.<br />
<br />
 <br />
<strong class='bbc'>So, what is a Quaternion?</strong><br />
 Quaternions aren't actually as scary as they sound. Everything I read regarding quaternions talked about imaginary numbers, hyper-complex numbers, spinors, and other scary sounding things. There was too much maths jargon for my liking. If you understand what a vector is, it isn't very hard to understand what a quaternion is. One way to represent a quaternion is<br />
<br />
  Q = xi + yj + zk + w  where <em class='bbc'>i,j</em> & <em class='bbc'>k</em> are coordinate basis vectors for three dimensions.<br />
<br />
 I don't particularly like this representation for computer graphics, especially where cameras are concerned. I prefer thinking of a quaternion as an object that contains a vector and a scalar. We'll call the vector <strong class='bbc'>v</strong> and keep the scalar as w.<br />
<br />
  Q = [ w, <strong class='bbc'>v</strong> ]  where <strong class='bbc'>v</strong> = x<em class='bbc'>i</em> + y<em class='bbc'>j</em> + z<em class='bbc'>k</em>.<br />
<br />
 For use in the sample code below, here's a quaternion data structure:<br />
<br />
  struct quaternion {   double x, y, z, w; };  This is a much easier representation to comprehend for me. Now for our purposes, quaternion addition, subtraction, etc., aren't needed. We only need to know how to normalize (scale to length=1), multiply and compute the conjugate of a quaternion in order to generate a rotation. These tasks are actually very simple and are described below.<br />
<br />
 <br />
<strong class='bbc'>Normalizing a quaternion</strong><br />
 Normalizing a quaternion is almost the same as normalizing a vector. We start by computing the length of the quaternion to be normalized, which is done using the Euclidean distance forumula:<br />
<br />
  |Q| = sqrt( w^2 + x^2 + y^2 + z^2)  A function to implement this formula might look like this:<br />
<br />
  double length(quaternion quat) {   return sqrt(quat.x * quat.x + quat.y * quat.y +           	quat.z * quat.z + quat.w * quat.w); }  Not too hard is it? Now to get the normalized vector Q, which we'll call Q*, we just divide every element of Q by |Q|.<br />
<br />
  Q* = Q/|Q| = [w/|Q|, <strong class='bbc'>v</strong>/|Q|]  Here's some sample code for this function:<br />
<br />
  quaternion normalize(quaternion quat) {   double L = length(quat);   quat.x /= L;   quat.y /= L;   quat.z /= L;   quat.w /= L;   return quat; }  This will give us a quaternion of length 1 (which is very important for rotations). Still nothing scary right? Well, it doesn't really get much harder than this.<br />
<br />
 <br />
<strong class='bbc'>The conjugate of a quaternion</strong><br />
 Let's compute the conjugate of a quaternion and call it Q'. The conjugate is simply<br />
<br />
  Q' = [ w, -<strong class='bbc'>v</strong> ]  Here's the code for the conjugate:<br />
<br />
  quaternion conjugate(quaternion quat) {   quat.x = -quat.x;   quat.y = -quat.y;   quat.z = -quat.z;   return quat; }  The last thing you need to know is quaternion multiplication. Then you'll be ready to make a quaternion based camera.<br />
<br />
 <br />
<strong class='bbc'>Multiplying quaternions</strong><br />
 Multiplication with quaternions is a little complicated as it involves dot-products cross-products. However, if you just use the following forumula that expands these operations, it isn't too hard. To multiply quaternion A by quaternion B, just do the following:<br />
<br />
  C = A * B  such that:<br />
<br />
  C.x = | A.w*B.x + A.x*B.w + A.y*B.z - A.z*B.y | C.y = | A.w*B.y - A.x*B.z + A.y*B.w + A.z*B.x | C.z = | A.w*B.z + A.x*B.y - A.y*B.x + A.z*B.w | C.w = | A.w*B.w - A.x*B.x - A.y*B.y - A.z*B.z |  Here's some code for multiplication:<br />
<br />
  quaternion mult(quaternion A, quaternion B) {   quaternion C;   C.x = A.w*B.x + A.x*B.w + A.y*B.z - A.z*B.y;   C.y = A.w*B.y - A.x*B.z + A.y*B.w + A.z*B.x;   C.z = A.w*B.z + A.x*B.y - A.y*B.x + A.z*B.w;   C.w = A.w*B.w - A.x*B.x - A.y*B.y - A.z*B.z;   return C; }  That's not too that hard is it? Now we'll look at how to use these operations to make a quaternion based camera.<br />
<br />
 <br />
<strong class='bbc'>The quaternion camera</strong><br />
 To make a camera you typically use three vectors: Position, View, and Up (or you may call them what you like). For a first person camera - which we will be using - we're only going to consider rotating the View vector. With quaternions we can rotate a vector around an arbitrary axis (same as with axis-angles) very easily.<br />
<br />
 To achieve this, first we need to turn our View vector into a quaternion, then define a rotation quaternion and lastly, apply the rotation quaternion to the View quaternion to make the rotation.<br />
<br />
 To make the View quaternion, V, the x, y, and z values are taken from the View vector and we simply add a 0 for the scalar component w. Thus,<br />
<br />
  V = [0, View]  Then you need to make a quaternion to represent the rotation. To do this, you need the vector you want to rotate about, and the angle you wish to rotate by. We'll just simply term the vector to rotate about A, and the angle theta. Here is the formula to build your rotation quaternion, which we'll call R.<br />
<br />
  vector A = [x, y, z]  R.x = A.x * sin(theta/2) R.y = A.y * sin(theta/2) R.z = A.z * sin(theta/2) R.w = cos(theta/2)  So now we have the vector (View) and its quaternion V that we want to rotate by an angle theta about the vector A. The rotation quaternion R defines this rotation. After the rotation, we'll have the new quaternion representing our view, given by W. The rotation operation is simply<br />
<br />
  W = R * V * R'  where R' is the conjugate of R. To get our new view vector, we just take the vector components out of W.<br />
<br />
  NewView = [W.x W.y W.z]  The following function (using SDL, use glut or whatever you like) sets the view based on the distance from the current mouse coordinates to the centre of the screen. I learned how to do this from gametutorials.com, and modified the code for my purposes. In this code, positive x is to the right and positive y is down the screen.<br />
<br />
  void Camera::SetViewByMouse(void) {   // the coordinates of our mouse coordinates   int MouseX, MouseY;   // the middle of the screen in the x direction   int MiddleX = SCREENWIDTH/2;   // the middle of the screen in the y direction   int MiddleY = SCREENHEIGHT/2;   // vector that describes mouseposition - center   Vector MouseDirection(0, 0, 0);   // static variable to store the rotation about the x-axis, since   // we want to limit how far up or down we can look.   // We don't need to cap the rotation about the y-axis as we   // want to be able to turn around 360 degrees   static double CurrentRotationAboutX = 0.0;   // The maximum angle we can look up or down, in radians   double maxAngle = 1;   // This function gets the position of the mouse   SDL_GetMouseState(&MouseX, &MouseY);   // if the mouse hasn't moved, return without doing   // anything to our view   if((MouseX == MiddleX) && (MouseY == MiddleY)) 	return;   // otherwise move the mouse back to the middle of the screen   SDL_WarpMouse(MiddleX, MiddleY);   // get the distance and direction the mouse moved in x (in   // pixels). We can't use the actual number of pixels in radians,   // as only six pixels  would cause a full 360 degree rotation.   // So we use a mousesensitivity variable that can be changed to   // vary how many radians we want to turn in the x-direction for   // a given mouse movement distance   // We have to remember that positive rotation is counter-clockwise.    // Moving the mouse down is a negative rotation about the x axis   // Moving the mouse right is a negative rotation about the y axis   MouseDirection.x = (MiddleX - MouseX)/MouseSensitivity;    MouseDirection.y = (MiddleY - MouseY)/MouseSensitivity;   CurrentRotationX += MouseDirection.y;      // We don't want to rotate up more than one radian, so we cap it.   if(CurrentRotationX > 1)   { 	CurrentRotationX = 1; 	return;   }   // We don't want to rotate down more than one radian, so we cap it.   if(CurrentRotationX < -1)   { 	CurrentRotationX = -1; 	return;   }   else   { 	// get the axis to rotate around the x-axis.      Vector Axis = CrossProduct(View - Position, Up); 	// To be able to use the quaternion conjugate, the axis to 	// rotate around must be normalized. 	Axis = Normalize(Axis); 	// Rotate around the y axis 	RotateCamera(MouseDirection.y, Axis.x, Axis.y, Axis.z); 	// Rotate around the x axis 	RotateCamera(MouseDirection.x, 0, 1, 0);   } }  This function actually rotates our view. After we are done, just plug your camera vectors (Position, View, and Up) into gluLookAt(Position.x, Position.y, Position.z, View.x, View.y, View.z, Up.x, Up.y, Up.z). Here is the code for the rotation.<br />
<br />
  void RotateCamera(double Angle, double x, double y, double z) {   quaternion temp, quat_view, result;   temp.x = x * sin(Angle/2);   temp.y = y * sin(Angle/2);   temp.z = z * sin(Angle/2);   temp.w = cos(Angle/2);   quat_view.x = View.x;   quat_view.y = View.y;   quat_view.z = View.z;   quat_view.w = 0;   result = mult(mult(temp, quat_view), conjugate(temp));   View.x = result.x;   View.y = result.y;   View.z = result.z; }  Again, at the end of the above functions, you should call<br />
<br />
  gluLookAt(Position.x, Position.y, Position.z,       	View.x, View.y, View.z, Up.x, Up.y, Up.z).  and your camera should work just perfectly. Maybe some other time, I'll do a third person camera tutorial, and explain how to use SLERP.<br />
<br />
]]></description>
		<pubDate>Mon, 22 Sep 2003 00:58:47 +0000</pubDate>
		<guid isPermaLink="false">e33d974aae13e4d877477d51d8bafdc4</guid>
	</item>
	<item>
		<title>Beat Detection Algorithms</title>
		<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/beat-detection-algorithms-r1952</link>
		<description><![CDATA[Beat Detection Algorithms<br />
by <a href='mailto:Frederic.Patin@supelec.fr' title='E-mail Link' class='bbc_email'>Frédéric Patin aka YOV408</a><br />
<a href='http://yov408.free.fr/' class='bbc_url' title='External link' rel='nofollow external'>http://yov408.free.fr</a><br />
<br />
 /reference/programming/features/beatdetection/image002.png<br />
<br />
 <br />
<strong class='bbc'>Disclaimer</strong><br />
 This document is to be distributed for free and without any modification from its original state. The author declines all responsibility in the damage this document or any of the things you will do with it might do to anyone or to anything. This document and any of its contents is not copyrighted and is free of all rights, you may thus use it, modify it or destroy it without breaking any international law. However according to the author's will, you may not use this document for commercial profit directly, but you may use indirectly its intellectual contents; in which case I would be pleased to receive a mail of notice or even thanks. This is my first tutorial and I am still a student, you must assume that this document is probably not free of small errors and bugs. In the same state of mind, those algorithms are not fully optimised, they are explained for pedagogical purposes and you may find some redundant computations or other voluntary clumsiness. Please be indulgent and self criticise everything you might read. Hopefully, lots of this stuff was taken in sources and books of reference; as for the stuff I did: it has proven some true efficiency in test programs I made and which work as wanted. As said in the introduction: If you have any question or any comment about this text, please send it to the above email address, I'll be happy to answer as soon as possible.<br />
<br />
 <br />
<strong class='bbc'>Introduction</strong><br />
 Simulating a physical phenomena which obeys to known mathematical equations is, with a number of approximations, always feasable. But what about more abstract concepts, such as feelings, which do not follow any laws? The simplest things we can feel are often the hardest things to capture in a program. Beat detection follows this rule : feeling the beat of a song comes naturally to humans or animals. Indeed it is only a feeling one gets when listening to a melody, a feeling which will make you dance in rhythm or hit a table with your hands on the melody beats. Therefore, how can we teach this beat detection to a machine that can only compute logical operations? In fact there are a number of algorithms which manage to approximate, more or less accurately, this beat detection. We will first study the statistical approach of beat detection on a streaming source and secondly a filtering approach of rhythm extraction on a static song.<br />
<br />
 This guide assumes the reader has basic signal processing understanding (FFT, convolutions and correlations should sound common) maybe some stuff in statistics will also help (Variance, Average, Principal Components Analysis, will be quoted among others). The point here is not to actually write the code of these algorithms, but more to understand how they work and to be able to adapt or create the appropriate algorithm to a situation. If you have a question or a comment about this text, please send it to the above email address, I'll be happy to answer as soon as possible. Anyway, the aim here is to give more precise ideas on the subject of beat detection to the reader. Enjoy.<br />
<br />
 <br />
<strong class='bbc'>I – Statistical streaming beat detection</strong><br />
 <br />
<strong class='bbc'>1 – Simple sound energy</strong><br />
 <br />
<strong class='bbc'>a - A first analysis</strong><br />
 The human listening system determines the rhythm of music by detecting a pseudo – periodical succession of beats. The signal which is intercepted by the ear contains a certain energy, this energy is converted into an electrical signal which the brain interprets. Obviously, The more energy the sound transports, the louder the sound will seem. But a sound will be heard as a <strong class='bbc'>beat</strong> only if his energy is largely superior to the sound's energy history, that is to say if the brain detects a <strong class='bbc'>brutal variation in sound energy</strong>. Therefore if the ear intercepts a monotonous sound with sometimes big energy peaks it will detect beats, however, if you play a continuous loud sound you will not perceive any beats. Thus, the beats are big variations of sound energy. This first analysis will bring us to our simplest model : <strong class='bbc'><em class='bbc'>Sound energy peaks</em></strong>.<br />
<br />
 In this model we will detect sound energy variations by computing <strong class='bbc'>the average sound energy</strong> of the signal and comparing it to the <strong class='bbc'>instant sound energy</strong>. Lets say we are working in stereo mode with two lists of values : (an) and (bn). (an) contains the list of sound amplitude values captured every Te seconds for the left channel, (bn) the list of sound amplitude values captured every Te seconds for the right channel. So we want to compute the instant energy and the average energy of the signal. The instant energy will in fact be the energy contained in 1024 samples (1024 values of a[n] and b[n]), 1024 samples represent about 5 hundreds of second which is pretty much 'instant'. The average energy should not be computed on the entire song, some songs have both intense passages and more calm parts. The instant energy must be compared to the nearby average energy, for example if a song has an intense ending, the energy contained in this ending shouldn't influence the beat detection at the beginning. <strong class='bbc'>We detect a beat only when the energy is superior to a local energy average.</strong> Thus we will compute the average energy on say : 44032 samples which is about 1 second, that is to say we will assume that the hearing system only remembers of 1 second of song to detect beat. This 1 second time (44032 samples) is what we could call the human ear energy persistence model; it is a compromise between being to big and taking into account too far away energies, and being too small and becoming to close to the instant energy to make a valuable comparison.<br />
<br />
 The history buffer where we will keep the last 44032 samples wil contain in fact too lists of samples (B[0]) and (B[1]) corresponding to the left (an) and to the right (bn) channels history.<br />
<br />
 Simple sound energy algorithm #1:<br />
<br />
  Every 1024 samples:<br />
<br />
 <ul class='bbc'><li>Use the 1024 new samples taken in a[n] and b[n] to compute the instant energy 'e', using the following formula (i0 is the position of the 1024 samples to process): /reference/programming/features/beatdetection/formula1.png<br />(R1) </li><li>Compute the local average energy '' on the 44100 samples of a history buffer (B): /reference/programming/features/beatdetection/formula2.png<br />(R2) </li><li>Shift the 44032 history buffer (B) of 1024 indexes to the right so that we make room for the 1024 new samples and evacuate the oldest 1024 samples. </li><li>Move the 1024 new samples on top of the history buffer. </li><li>Compare 'e' to 'C * ' where C is a constant which will determine the sensibility of the algorithm to beats. A good value for this constant is 1.3. If 'e' is superior to 'C * ' then we have a beat!</li></ul>  <br />
<strong class='bbc'>b - Some direct optimisations</strong><br />
 This was the basic version of the algorithm, its speed and accurecy can be improved quite easily. The algorithm can be optimised by <strong class='bbc'>keeping the energy values computed on 1024 samples in history instead of the samples themselves</strong>, so that we don't have to compute the average energy on the 44100 samples buffer (B) but on the instant energies history we will call (E). This sound energy history buffer (E) <strong class='bbc'>must</strong> correspond to approximately <strong class='bbc'>1 second of music</strong>, that is to say it must contain the energy history of 44032 samples (calculated on groups of 1024) if the sample rate is 44100 samples per second. Thus E[0] will contain the newest energy computed on the newest 1024 samples, and E[42] will contain the oldest energy computed on the oldest 1024 samples. We have 43 energy values in history, each computed on 1024 samples which makes 44032 samples energy history, which is equivalent to 1 second in real time. The count is good. The value of 1 second represents the persistance of the music energy in the human ear, it was obtain with experimentations but it may varry a little from a person to another, just adjust it as you feal. So here is what the algorithm becomes:<br />
<br />
 Simple sound energy algorithm #2:<br />
<br />
  Every 1024 samples:<br />
<br />
 <ul class='bbc'><li>Compute the instant sound energy 'e' on the 1024 new sample values taken in (an) and (bn) using the formula <strong class='bbc'>(R1)</strong> </li><li>Compute the average local energy  with (E) sound energy history buffer: /reference/programming/features/beatdetection/formula3.png<br />(R3) </li><li>Shift the sound energy history buffer (E) of 1 index to the right. We make room for the new energy value and flush the oldest. </li><li>Pile in the new energy value 'e' at E[0]. </li><li>Compare 'e' to 'C*'.</li></ul>  <br />
<strong class='bbc'>c - Sensitivity detection</strong><br />
 The imediate draw back of this algorithm is <strong class='bbc'>the choice of the 'C' constant</strong>. For example in techno and rap music beats are quite intense and precise so 'C' should be quite high (about 1.4); whereas for rock and roll, or hard rock which contains a lot of noise, the beats are more confused and 'C' should be low (about 1.1 or 1.0). There is a way, to make the algorithm determine automatically the good choice for the 'C' constant. We must compute <strong class='bbc'>the variance of the energies</strong> contained in the energy history buffer (E). This variance, which is nothing but the average of ( Energy Values – Energy average = (E) -  ), will quantify how marked the beats of the song are and thus will give us a way to compute the value of the 'C' constant. The formula to calculate the variance of the 43 E<em class='bbc'> values is described below <strong class='bbc'>(R4)</strong>. Finally, the greater the variance is the more sensitive the algorithm should be and thus the smaller 'C' will become. We can choose a linear decrease of 'C' with 'V' (the variance) and for example when V → 200, C → 1.0 and when V → 25, C → 1.45 <strong class='bbc'>(R5)</strong>. This is our new version of the sound energy beat detection algorithm:<br />
<br />
 Simple sound energy algorithm #3:<br />
<br />
  Every 1024 samples:<br />
<br />
 <ul class='bbc'><li>Compute the instant sound energy 'e' on the 1024 new samples taken in (an) and (bn) using the following formula <strong class='bbc'>(R1)</strong>. </li><li>Compute the average local energy  with (E) sound energy history buffer using formula <strong class='bbc'>(R3)</strong>. </li><li>Compute the variance 'V' of the energies in (E) using the following formula: /reference/programming/features/beatdetection/formula4.png<br />(R4) </li><li>Compute the 'C' constant using a linear degression of 'C' with 'V', using a linear regression with values <strong class='bbc'>(R5)</strong>: /reference/programming/features/beatdetection/formula5.png<br />(R6) </li><li>Shift the sound energy history buffer (E) of 1 index to the right. We make room for the new energy value and flush the oldest. </li><li>Pile in the new energy value 'e' at E[0]. </li><li>Compare 'e' to 'C*', if superior we have a beat!</li></ul>  Those three algorithms were tested with several types of music, among others : pop, rock, metal, techno, rap, classical, punk. The fact is the results are quite unpredictable. I will only talk about <em class='bbc'>Simple beat detection algorithm #3</em> as <em class='bbc'>#2</em> and <em class='bbc'>#1</em> are only pedagogical intermediates to get to the <em class='bbc'>#3</em>.<br />
<br />
 Clearly, <strong class='bbc'>the beat detection is very accurate and sounds right with techno and rap</strong>, the beats are very precise and the music contains very few noise. The algorithm is quite satisfying for that kind of music and if you aim to use beat detection on techno you can stop reading here, the rest won't change anything to your beat detection. However, even if the improvement of the dynamic 'C' calculations ameliorates things alot, <strong class='bbc'>the beat detection on punk, rock and hard rock, is sometimes quite approximate</strong>. We can feel it doesn't really get the rythm of the song. Indeed the algorithm detects energy peaks. Sometimes you can hear a drum beat which is sank among other noises and which goes trough the algorithm without being detected as a beat.<br />
<br />
 To explain this phenomena lets say a guitare and flute make alternatively an amplitude constant note. Each time the first finishes the other starts. The note made by the guitare and the note made by the flute have the same energy but the ear detects a certain rhythm because the notes of the instruments are at different pitch. For our algorithm (who is one might say colorblind) it is just an amplitude constant noise with no energy peaks. This partly explains why the algorithm doesn't detect precisely beats in songs with a lot of instruments playing at different rythms and simultaneously. Our next analysis will make us walk through this difficulty.<br />
<br />
 Comparing the results we have obtained with the <em class='bbc'>Simple beat detection algorithm #3</em> to its computing cost, this algorithm is very efficient. If you are not looking for a perfect beat detection than I recommend you use it. Here is a screenshot of a program I made using this algorithm. You fill find the binaries and the sources on my homepage.<br />
<br />
 /reference/programming/features/beatdetection/image020.png<br />
Figure 1: The spectrum analyser is not useful for the beat detection it is only for visual matters, but you can see at the top some of the parameters the program computes to execute the algorithm.<br />
<br />
 <br />
<strong class='bbc'>2 – Frequency selected sound energy</strong><br />
 <br />
<strong class='bbc'>a - The idea and the algorithm</strong><br />
 The issue with our last analysis of beat detection is that it is colorblind. We have seen that this could raise quite a few problems for noisy like songs in rock or pop music. What we must do is give our algorithm the abbility to determine on which frequency subband we have a beat and if it is powerful enough to take it into account. Basically we will try to detect <strong class='bbc'>big sound energy variations in particular frequency subbands</strong>, just like in our last analysis; unless this time we will be able to seperate beats regarding their color ( frequency subband ). Thus If we want to give more importants to low frequency beats or to high frequency beats it should be more easy. Notice that the energy computed in the time domain is the same as the energy computed in the frequency domain, so we don't have any difference between computing the energy in time domain or in frequency domain. For maths freaks this is called the Parseval Theorem.<br />
<br />
 Okay that was just a bit of sport, lets go back to the mainstream; Here is how the <strong class='bbc'><em class='bbc'>Frequency selected sound energy</em></strong> algorithm works: The source signals are still coming from (an) and (bn). (an) and (bn) can be taken from a wave file, or directly from a streaming microphon or line input. Each time we have accumulated 1024 new samples, we will pass to the frequency domain with a <strong class='bbc'>Fast Fourier Transform (FFT)</strong>. We will thus obtain a 1024 frequency spectrum. We then divide this spectrum into however many subbands we like, here I will take 32. The more subbands you have, the more sensitive the algorithm will be but the harder it will become to adapt it to lots of different kinds of songs. Then we compute the <strong class='bbc'>sound energy</strong> contained in <strong class='bbc'>each of the subbands</strong> and we compare it to the <strong class='bbc'>recent energy average corresponding to this subband</strong>. If one or more subbands have an energy superior to their average we have detected a beat.<br />
<br />
 The great progress with the last algorithm is that we now know more about our beats, and thus we can use this information to change an animation, for example. So here is more precisely the <em class='bbc'>Frequency selected sound energy algorithm #1:</em><br />
<br />
 Frequency selected sound energy algorithm #1:<br />
<br />
  Every 1024 samples:<br />
<br />
 <ul class='bbc'><li>Compute the FFT on the 1024 new samples taken in (an) and (bn). The FFT inputs a complex numeric signal. We will say (an) is the real part of the signal and (bn) the imagenary part. Thus the FFT will be made on the 1024 complex values of: /reference/programming/features/beatdetection/formula6.png<br /><br /> You can find FFT tutorials and codes in C, Visual Basic or C++ on my homepage in the 'tutorials' section or by typing 'FFT' on <a href='http://www.google.com' class='bbc_url' title='External link' rel='nofollow external'>Google</a>. </li><li>From the FFT we obtain 1024 complex numbers. We compute the square of their module and store it into a new 1024 buffer. This buffer (B) contains the 1024 frequency amplitudes of our signal. </li><li>Divide the buffer into 32 subbands, compute the energy on each of these subbands and store it at (Es). Thus (Es) will be 32 sized and Es<em class='bbc'> will contain the energy of subband 'i': /reference/programming/features/beatdetection/formula7.png<br />(R7) </li><li>Now, to each subband 'i' corresponds an energy history buffer called (Ei). This buffer contains the last 43 energy computations for the 'i' subband. We compute the average energy  for the 'i' subband simply by using: /reference/programming/features/beatdetection/formula8.png<br />(R8) </li><li>Shift the sound energy history buffers (Ei) of 1 index to the right. We make room for the new energy value of the subband 'i' and flush the oldest. </li><li>Pile in the new energy value of subband 'i' : Es<em class='bbc'> at Ei[0]. /reference/programming/features/beatdetection/formula9.png<br />(R9) </li><li>For each subband 'i' if Es<em class='bbc'> > (C*) we have a beat !</li></ul>  To help out visualising how the data piles work have a look at this scheme:<br />
<br />
 /reference/programming/features/beatdetection/image032.png<br />
Figure 2: This is how the energy data is organized.<br />
<br />
 Now the 'C' constant of this algorithm has nothing to do with the 'C' of the first algorithm, because we deal here with separated subbands the energy varies globally much more than with colorblind algorithms. Thus 'C' must be about 250. The results of this algorithm are convincing, it detects for example a symbal rhythm among other heavy noises in metal rock, and indeed the algorithm separates the signal into subbands, therefore the <strong class='bbc'>symbal rhythm cannot pass trough the algorithm without being recognized because it is isolated in the frequency domain from other sounds.</strong> However the complexity of the algorithm makes it useful only if you are dealing with very noisy sounds, in other cases, <em class='bbc'>Simple beat detection algorithm #3</em> will do the job.<br />
<br />
 <br />
<strong class='bbc'>b - Enhancements and beat decision factors.</strong><br />
 There are ways to enhance a bit more our <em class='bbc'>Frequency selected sound energy algorithm #1</em>.<br />
<br />
 First we will increase the <strong class='bbc'>number of subbands from 32 to 64</strong>. This will take obviously more computing time but it will also give us more precision in our beat detection. The second way to develop the accuracy of the algorithm uses the defaults of human ears. Human hearing system is not perfect; in fact its transfer function is more like a low pass filter. We hear more easily and more clearly low pitched noises than high pitch noises. This is why it is preferable to make a logarithmic repartition of the subbands. That is to say that subband 0 will contain only say 2 frequencies whereas the last subband, will contain say 20. <strong class='bbc'>More precisely the width 'wi' of the 'n' subbands indexed 'i' can be obtained using this argument:</strong><br />
<br />
  <ul class='bbc'><li>Linear increase of the width of the subband with its index: /reference/programming/features/beatdetection/formula10.png<br />(R10) </li><li>We can choose for example the width of the first subband: /reference/programming/features/beatdetection/formula11.png<br />(R11) </li><li>The sum of all the widths must not exceed 1024 ((B)'s size): /reference/programming/features/beatdetection/formula12.png<br />(R12)</li></ul>  Once you have equations <strong class='bbc'>(R11)</strong> and <strong class='bbc'>(R12)</strong> it is fairly easy to extract 'a' and 'b', and thus to find the law of the 'wi'. This calculus of 'a' and 'b' must be made manually and 'a' and 'b' defined as constants in the source; indeed they do not vary during the song.<br />
<br />
 So in fact in <em class='bbc'>Frequency selected sound energy algorithm #1</em>, all we have to modify is the number of subbands we will take equal to 64 and the <strong class='bbc'>(R7)</strong> relation. This relation becomes:<br />
<br />
 /reference/programming/features/beatdetection/forumla7-2.png<br />
(R7)'<br />
<br />
 It may seem rather complicated but in fact it is not. Replacing this relation <strong class='bbc'>(R7)</strong> with <strong class='bbc'>(R7)'</strong> we have created <em class='bbc'>Frequency selected sound energy algorithm #2.</em> If you have musics with very tight and rapid beats, you may want to compute the stuff more frequently than every 1024 samples, but this is only for special cases, normally the beat should not be shorter than 1/40 of second.<br />
<br />
 Using the advantages of Frequency selected beat detection you can also enhance the beat decision factor. Up to now it was based on a simple comparison between the instant energy of the subband and the average energy of the subband. This algorithm enables you to decide beats differently. You may want for examples to cut beats which correspond to high pitch sounds if you run techno music or you may want to keep only [50-4000Hz] beats if you are working with speech signal. This algorithm has the advantage of being perfectly adaptable to any kind or category of signal which was not the case of <em class='bbc'>Simple beat detection algorithm #3</em>. Notice that the correspondants between index 'i' of the FFT transform and real frequency is given by formula :<br />
<br />
  <ul class='bbc'><li>If 'i' < 'N/2' then: /reference/programming/features/beatdetection/formula13.png<br />(R13) </li><li>Else 'i' >= 'N/2' then: /reference/programming/features/beatdetection/formula14.png<br />(R14)</li></ul>  So 'i' is the index of the value in the FFT output buffer, N is the size of the FFT transform (here 1024), fe is the sample frequency (here 44100). Thus index 256 corresponds to 10025 Hz. This formula may be useful if you want to create your own subbands and you want to know what the correspondants <strong class='bbc'>between indexes and real frequency</strong> are.<br />
<br />
 Another way of filtering the beats, or selecting them, is choosing only those which are marked and precise enough. As we have seen before, <strong class='bbc'>to detect the accuracy of beats we must compute the variance of the energy histories for each subband</strong>. If this variance is high it means that we have great differences of energy and thus that the beat are very intense. Thus all we have to do is compute this variance for each subband and add a test in the beat detection decision. To the "Es<em class='bbc'> > (C*)" condition we will add "and V((Ei))>V0". V0 will be the variance limit, with experience 150 is a reasonable value. Now the V((Ei)) value is easy to compute, just follow the following equality if you don't see how :<br />
<br />
 /reference/programming/features/beatdetection/formula15.png<br />
(R15)<br />
<br />
 The last (finally) way to enhance your beat detection, is to make the source signal pass through a <strong class='bbc'>derivation filter.</strong> Indeed differentiating the signal makes big variations of amplitude more marked and thus makes energy variations more marked and recognisable later in the algorithm. I haven't tried this optimisation but according to some sources this is quite useful. If you try it please give me your opinion on it!<br />
<br />
 Concerning the results of the <em class='bbc'>Frequency selected sound energy algorithm #2</em> I must admit they are way more satisfying than the <em class='bbc'>Simple sound energy algorithm #3</em>. In a song the algorithm catches the bass beats as well as the tight cymbals hits. I insist on the fact that you may also select the beats in very different ways, which becomes quite useful if you know you are going to run techno music with low pitch beats for example. You may also select the beats differently according to there accuracy with the variance criteria. There are many other ways to decide beats; it is up to you to explore them and find the one which fits the most your needs.<br />
<br />
 I used <em class='bbc'>Frequency selected sound energy algorithm #2</em>algorithm in a demo program of which you can see some screenchots just below. One can see quite clearly that there is a beat in low frequencies (probably a bass or drum hit) and also a high pitch beat (probably a cymbal or such):<br />
<br />
 /reference/programming/features/beatdetection/image052.png<br />
Figure 3: The histogram represents the instant energy of the 128 subbands.<br />
<br />
 /reference/programming/features/beatdetection/image054.png<br />
Figure 4: On this screenshot you can see the 128 subbands E/ ratios, and the bandwidth of the subbands. When the algorithm detects a beat in a subband, it overwrites the ratio in red.<br />
<br />
 The reason why I called this part of the document, 'Statistical streaming beat detection', is that the energy can be considered as a random variable, of which we have been calculating values over time. Thus we could interpret those values as a sampling for the statistical analysis of a random variable. But one can push this approach further. When we have separated the energies histories into 128 subbands we created in fact 128 random energy variables. We can then apply some of the general statistical methods of analysis. For example, the principal components analysis method will enable you to determine if some of the subbands are directly linked or independent. This would help us to regroup some subbands which are directly linked and thus make the beat decision more efficient. However, this method is basically just far too computing expensive and maybe just too hard to implement comparing to the results we want. If you are looking for a really good challenge in beat detection you could push in this direction.<br />
<br />
 <br />
<strong class='bbc'>II – Filtering rhythm detection</strong><br />
 <br />
<strong class='bbc'>1 – Derivation and Comb filters</strong><br />
 <br />
<strong class='bbc'>a - Intercorrelation and train of impulses</strong><br />
 While in the first part of this document we had seen beat detection as a statistical sound energy problem, we will approach it here as a <strong class='bbc'>signal processing issue</strong>. I haven't tried myself this algorithm but I greatly inspired myself of some work which was done and tested with this algorithm (see the sources section), so it really works but I won't detail so much its implementation as I did in the first part. The basic idea is the following. <strong class='bbc'>If we have two signals x(t) and y(t)</strong>, we can evaluate a function which will give us an idea of how <strong class='bbc'>much those two signals are similar</strong>. This function called 'inter correlation function' is the following:<br />
<br />
 /reference/programming/features/beatdetection/formula16.png<br />
(R16)<br />
<br />
 For our purposes we will always take alpha=1. This function quantifies the energy that can be exchanged between the signal x(t) and the signal y(t – β), it gives an evaluation of how much those two functions look like each other. The role of the 'β' is to eliminate the time origin problem; two signals should be compared without regarding their possible time axis translation. As you may have noticed, we are creating this algorithm for a computer to execute; basically we have to re-write this formula in discrete mode, it becomes:<br />
<br />
 /reference/programming/features/beatdetection/formula17.png<br />
(R17)<br />
<br />
 Now the point is we can valuate the similarity of our song and of a train of impulses using this function. <strong class='bbc'>The train of impulses being at a known frequency</strong> (the beats per minute we want to test) is what we call a comb filter. The energy of the γ function gives us an evaluation of the similarity between our song and this train of impulses, thus it quantifies how much the rhythm of the train of impulses is present in the song. If we compute the energy of the γ function for different train of impulses, we will be able to see for which of them the energy is the biggest, and thus we will know what is the principal Betas Per Minute rate. This is called <strong class='bbc'>combfilter processing</strong>. We will note 'Ey' this energy, where x[k] is our song signal and y[k] our train of impulses:<br />
<br />
 /reference/programming/features/beatdetection/formula18.png<br />
(R18)<br />
<br />
 By the way, here is what a train of impulses looks like:<br />
<br />
 /reference/programming/features/beatdetection/image067.png<br />
Figure 5: This is the train of impulses function, it is caracterised by its period Ti.<br />
<br />
 So the period Ti of the impulses must correspond to the beats per minutes we want to test on our song. The formula that links a beat per minute value with the Ti in discrete time is the following:<br />
<br />
  /reference/programming/features/beatdetection/formula19.png<br />
(R19)<br />
<br />
 fs is the sample frequency, if you are using good quality wave files, it is usually of 44100. BPM is the beats per minute rate. Finally, Ti is the number of indexes between each impulse.<br />
<br />
  Now because it is quite computing expensive to compute the <strong class='bbc'>(R17)</strong> formula, <strong class='bbc'>we pass to the frequency domain with a FFT and compute the product of the X[v] and Y[v]</strong> (FFT's of x[k] and y[k]). Then we compute the energy of the γ function directly in the frequency domain, thus Ey is given with by the following formula:<br />
<br />
 /reference/programming/features/beatdetection/formula17-2.png<br />
(R17)'<br />
<br />
 <br />
<strong class='bbc'>b - The algorithm</strong><br />
 Note that this algorithm is much too computing expensive to be ran on a streaming source, or on a song in a whole. It is executed on a part of the song, like 5 seconds taken somewhere in the middle. Thus we assume that the tempo of the song is overall constant and that the middle of the song is tempo-representative of the rest of the song. So finally here are the steps of our algorithm:<br />
<br />
 Derivation and Combfilter algorithm #1:<br />
<br />
  <ul class='bbc'><li>Choose roughly 5 seconds of data in the middle of the song and copy it to the 'a[k]' and 'b[k]' lists. The dimension of those lists is noted N. As usual 'a[k]' is the array for the left values, and 'b[k]' is the array for the right values. </li><li>Compute the FFT of the complex signal made with a[k] for the real part of the complex signal and b[k] the imaginary part of the complex signal as seen in <em class='bbc'>Frequency selected sound energy algorithm #1.</em> Store the real part of the result in ta[k] and the imaginary in tb[k]. </li><li>For all the beats per minute you want to test, for example from 60 BPM to 180 BPM per step of 10, we will note BPMc the current BPM tested:<ul class='bbc'><li>Compute the Ti value corresponding to BPMc using formula <strong class='bbc'>(R19)</strong>. </li><li>Compute the train of impulses signal and store it in (l) and (j). (l) and (j) are purely identical, we take two lists of values to have a stereo signal so that we don't have dimension issues further on. Here is how the train of impulses is generated: [indent]  for (k = 0; k < N; k++) {   if ((k % Ti) == 0) 	l[k] = j[k] = AmpMax;   else 	l[k] = j[k] = 0; } [/indent] </li><li>Compute the FFT of the complex signal made of (l) and (j). Store the result in tl[k] and tj[k]. </li><li>Finally compute the energy of the correlation between the train of impulses and the 5 seconds signal using <strong class='bbc'>(R17)'</strong> which becomes: /reference/programming/features/beatdetection/formula20.png<br />(R20) </li><li>Save E(BPMc) in a list.</li></ul>  </li><li>The rhythm of the song is given by the BPMmax, where the max of all the E(BPMc) is taken. We have the beat rate of the song!</li></ul>  The AmpMax constant which appears in the train of impulse generation, is given by the sample size of the source file. Usually the sample size is 16 bits, for a good quality .wav. If you are working in non-signed mode, the AmpMax value will be of 65535, and more often if you work with 16 bits signed samples the AmpMax will be 32767.<br />
<br />
 One of the first ameliorations that could be given to <em class='bbc'>Derivation and Combfilter algorithm #1</em> is indeed adding a <strong class='bbc'>derivation filter</strong> before the combfilter processing. <strong class='bbc'>To make beats more detectable, we differentiate the signal</strong>. This accentuates when the sound amplitude changes. So instead of dealing with a[k] and b[k] directly we first transform them using the formula below. This modification added before the second step of <em class='bbc'>Derivation and Combfilter algorithm #1</em> constitutes <em class='bbc'>Derivation and Combfilter algorithm #2.</em><br />
<br />
 /reference/programming/features/beatdetection/formula21.png<br />
(R21)<br />
<br />
 As I said before, I haven't tested this algorithm myself; I can't compare its results with the algorithms of the first part. However, throughout the researches I made this seems to be the algorithm universally accepted as being the most accurate. It does have disadvantages: Great computing power consumption, can only be done on a small part of a song, assumes the rhythm is constant throughout the song, no possible streaming input (for example from a microphone), the signal needs to be known in advance. However it returns a deeper analysis than the first part algorithms, indeed for each BPM rate you have a value of its importance in the song.<br />
<br />
 <br />
<strong class='bbc'>2 – Frequency selected processing</strong><br />
 <br />
<strong class='bbc'>a - Curing colorblindness</strong><br />
 As in the first part of the tutorial, we have the same problem our last algorithm doesn't make the difference between cymbals beat or a drum beat, so the beat detection becomes a bit dodgy on very noisy music like hard rock. To heal our algorithm we will proceed as we had done in [i]Frequency selected sound energy algorithm #1</em> <strong class='bbc'>we will separate our source signal into several subbands</strong>. Only this time we have much more computing to do on each subband so we will be much more limited in their number. I think that 16 is a good value. <strong class='bbc'>We will use a logarithmic repartition of these subbands</strong> as we had done before.<br />
<br />
 Let's modify the [i]Derivation and Combfilter algorithm #2</em>. The values particular to a subband will be characterized with a little 's' at the end of the name of the variable. So we will separate ta[k] and tb[k] into 16 subbands. Each subbands values array will be called tas[k] and tbs[k] ('s' varies from 1 to 16).<br />
<br />
 Frequency selected processing combfilters algorithm #1:<br />
<br />
  <ul class='bbc'><li>Choose roughly 5 seconds of data in the middle of the song and copy it to the 'a[k]' and 'b[k]' lists. The dimension of those lists is noted N. As usual 'a[k]' is the array for the left values, and 'b[k]' is the array for the right values. </li><li>Differentiate the a[k] and b[k] signals using <strong class='bbc'>(R21)</strong>. </li><li>Compute the FFT of the complex signal made with a[k] for the real part of the complex signal and b[k] the imaginary part of the complex signal as seen in [i]Frequency selected sound energy algorithm #1.</em> Store the real part of the result in ta[k] and the imaginary in tb[k]. </li><li>Generate the 16 subband array values tas[k] and tbs[k] by cutting ta[k] and tb[k] with a logarithmic rule. </li><li>For all the subbands tas[k] and tbs[k] (s goes from 1 to 16). Ws is the length of the 's' subband. </li><li>For all the beats per minute you want to test, for example from 60 BPM to 180 BPM per step of 10, we will note BPMc the current BPM tested :<ul class='bbc'><li>Compute the Ti value corresponding to BPMc using formula <strong class='bbc'>(R19)</strong>. </li><li>Compute the train of impulses signal and store it in (l) and (j). (l) and (j) are purely identical, we take two lists of values to have a stereo signal so that we don't have dimension issues further on. Here is how the train of impulses is generated: [indent]  for (k = 0; k < ws; k++) {   if ((k % Ti) == 0) 	l[k] = k[k] = AmpMax;   else 	l[k] = j[k] = 0; } [/indent] </li><li>Compute the FFT of the complex signal made of (l) and (j). Store the result in tl[k] and tj[k]. </li><li>Finally compute the energy of the correlation between the train of impulses and the 5 seconds signal using <strong class='bbc'>(R17)'</strong> which becomes: /reference/programming/features/beatdetection/formula22.png<br />(R22) </li><li>Save E(BPMc,s) in a list.</li></ul>  </li><li>The rhythm of the subband is given by the BPMmaxs, where the max of all the E(BPMc,s) is taken (s is fixed). We will call this max EBPMmaxs. We have the beat rate of the subband we store it in a list. </li><li>We do this for all the subbands, we have a list of BPMmaxs for all subbands, we can than decide which one to consider.</li></ul>  As in [i]Frequency selected sound energy algorithm #2</em> we will then be able to decide the rhythm according to frequency bandwidth criteria. Or, if you want to take all the subbands into account you can compute the final BPM of the song, by calculating the barycentre of all the BPMmaxs affected with their max of E(BPMc,s). Like this:<br />
<br />
 /reference/programming/features/beatdetection/formula23.png<br />
(R23)<br />
<br />
 I must admit I haven't concretely tested this algorithm. Others have done this already and here an overview of the results for [i]Derivation and Combfilter algorithm #2</em> (source: <a href='http://www.owlnet.rice.edu/%7Eelec301/Projects01/beat_sync/beatalgo.html' class='bbc_url' title='External link' rel='nofollow external'>http://www.owlnet.rice.edu/~elec301/Projects01/beat_sync/beatalgo.html</a>).<br />
<br />
 /reference/programming/features/beatdetection/image090.png<br />
Figure 6: This is plot of the EBPMc values function of BPMc. The algorithm will take the max of the EBPMc value to find the final BPM of the song. Here we see this max is reached for BPMc=75. The final BPM is 75!<br />
<br />
 <br />
<strong class='bbc'>Conclusion</strong><br />
 Finding algorithms for beat detection is very frustrating. It seems so obvious to us, humans, to hear those beats and somehow so hard to formalise it. We managed to approximate more or less accurately and more or less efficiently this beat detection. But the best algorithms are always the ones you make yourself, the ones which are adapted to your problem. The more the situation is precise and defined the easier it is! This guide should be used as a source of ideas. Even if beat detection is far from being a crucial topic in the programming scene, it has the advantage of using lots of signal processing and mathematical concepts. More than an end in itself, for me, beat detection was a way to train to signal processing. I hope you will find some of this stuff useful.<br />
<br />
 <br />
<strong class='bbc'>Sources and Links</strong><br />
 <ul class='bbc'><li><a href='http://www.owlnet.rice.edu/%7Eelec301/Projects01/beat_sync/beatalgo.html' class='bbc_url' title='External link' rel='nofollow external'>http://www.owlnet.rice.edu/~elec301/Projects01/beat_sync/beatalgo.html</a> : This site greatly inspired me for the second part of the tutorial, very well explained. </li><li><a href='http://www.cs.princeton.edu/%7Egessl/papers/amta2001.pdf' class='bbc_url' title='External link' rel='nofollow external'>http://www.cs.princeton.edu/~gessl/papers/amta2001.pdf</a> : Audio analysis using the discrete wavelet transform. </li><li><a href='http://web.media.mit.edu/%7Eeds/beat.pdf' class='bbc_url' title='External link' rel='nofollow external'>Tempo and beat analysis of acoustic musical signals</a> by Eric D. Scheirer </li><li><a href='http://www.sunpoint.net/%7Eoparviai/pacemaker/' class='bbc_url' title='External link' rel='nofollow external'>Pacemaker</a> by Olli Parviainen</li></ul>]]></description>
		<pubDate>Sat, 07 Jun 2003 20:39:13 +0000</pubDate>
		<guid isPermaLink="false">b8c78ee23d4f42c6c58cede44fedb0cd</guid>
	</item>
	<item>
		<title>Vectors and Matrices: A Primer</title>
		<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/vectors-and-matrices-a-primer-r1832</link>
		<description><![CDATA[<span style='font-size: 18px;'><strong class='bbc'>Preface</strong></span><br />
<br />
Hey there! This tutorial is for those who are new to 3D programming, and need to brush up on that math. I will teach you two primary things here, Vectors and Matrices (with determinants). I'm not going to go into everything, so this isn't designed as a standalone reference. A lot of mathematics books can probably discuss this much better, but anyway, without further ado, lets get on with it shall we?<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Vectors</strong></span><br />
 <br />
<span style='font-size: 12px;'><strong class='bbc'>Vector basics – What is a vector?</strong></span><br />
<br />
Vectors are the backbone of games. They are the foundation of graphics, physics modelling, and a number of other things. Vectors can be of any dimension, but are most commonly seen in 2 or 3 dimensions. I will focus on 2D and 3D vectors in this text. Vectors are derived from hyper-numbers, a sub-set of hyper-complex numbers. But enough of that, you just want to know how to use them right? Good.<br />
<br />
 The notation for a vector is that of a bold lower-case letter, like <strong class='bbc'>i</strong>, or an italic letter with an underscore, like <em class='bbc'><span class='bbc_underline'>i</span></em>. I'll use the former in this text. You can write vectors in a number of ways, and I will teach you 2 of them: <em class='bbc'>vector equations</em> and <em class='bbc'>column vectors</em>. Vectors can also be written using the two end points with an arrow above them. So, if you have a vector between the two points A and B, you can write that as <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4331-0-59343600-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4331" title="image002.gif - Size: 240bytes, Downloads: 37"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-74933000-1311406833_thumb.gif" id='ipb-attach-img-4331-0-59343600-1330210056' style='width:59;height:25' class='attach' width="59" height="25" alt="Attached Image: image002.gif" /></a>.<br />
<br />
 A vector equation takes the form <strong class='bbc'>a=</strong> <em class='bbc'>x</em><strong class='bbc'>i</strong> + <em class='bbc'>y</em><strong class='bbc'>j</strong> + <em class='bbc'>z</em><strong class='bbc'>k</strong><br />
<br />
 <strong class='bbc'>i</strong>, <strong class='bbc'>j</strong> and <strong class='bbc'>k</strong> are unit vectors in the 3 standard Cartesian directions. <strong class='bbc'>i</strong> is a unit vector aligned with the x axis, <strong class='bbc'>j</strong> is a unit vector aligned with the y axis, and <strong class='bbc'>k</strong> is a unit vector aligned with the z axis. Unit vectors are discussed later.<br />
<br />
 The coefficients of the <strong class='bbc'>i</strong>, <strong class='bbc'>j</strong> and <strong class='bbc'>k</strong> parts of the equation are the vector's <em class='bbc'>components</em>. These are how long each vector is in each of the 3 axes. This may be easier to understand with the aid of a diagram.<br />
<br />
<p class='bbc_center'> <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4332-0-59363200-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4332" title="image003.gif - Size: 1.93K, Downloads: 42"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-74324700-1311406850_thumb.gif" id='ipb-attach-img-4332-0-59363200-1330210056' style='width:203;height:200' class='attach' width="203" height="200" alt="Attached Image: image003.gif" /></a><br />
</p><br />
 This diagram shows a vector from the origin to the point ( 3, 2, 5 ) in 3D space. The <em class='bbc'>components</em> of this vector are the <strong class='bbc'>i</strong>, <strong class='bbc'>j</strong> and <strong class='bbc'>k</strong> coefficients ( 2, 3 and 5 ). So, in the above example, the vector equation would be:<br />
<br />
 <strong class='bbc'>a</strong> = 2<strong class='bbc'>i</strong> + 3<strong class='bbc'>j</strong> + 5<strong class='bbc'>k</strong><br />
<br />
 This can also be related to the deltas of a line going through 2 points.<br />
<br />
 The second way of writing vectors is as <em class='bbc'>column vectors</em>. These are written in the following form<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4333-0-59383100-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4333" title="image005.gif - Size: 397bytes, Downloads: 40"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-13322100-1311406871_thumb.gif" id='ipb-attach-img-4333-0-59383100-1330210056' style='width:53;height:75' class='attach' width="53" height="75" alt="Attached Image: image005.gif" /></a><br />
<br />
 where <em class='bbc'>x</em>, <em class='bbc'>y</em> and <em class='bbc'>z</em> are the components of that vector in the respective directions. These are exactly the same as the components of the vector equation. So in column vector form, the above example could be written as:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4334-0-59401400-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4334" title="image007.gif - Size: 402bytes, Downloads: 33"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-41119900-1311406881_thumb.gif" id='ipb-attach-img-4334-0-59401400-1330210056' style='width:52;height:75' class='attach' width="52" height="75" alt="Attached Image: image007.gif" /></a><br />
<br />
 There are various advantages to both of the above forms, but I will continue to use the column vector form, as it is easier when it comes to matrices. <em class='bbc'>Position vectors</em> are those that originate from the origin. These can define points in space, relative to the origin.<br />
<br />
 <span style='font-size: 12px;'><strong class='bbc'>Vector Math</strong></span><br />
<br />
You can manipulate vectors in various ways, including scalar multiplication, addition, scalar product and vector product. The latter two are extremely useful in 3D applications.<br />
<br />
 There are a few things you should know before moving to the methods above. The first is finding the <em class='bbc'>modulus</em> (also called the <em class='bbc'>magnitude</em>) of a vector. This is basically its length. This can be easily found using Pythagorean theorem, using the vector components. The modulus of <strong class='bbc'>a</strong> is written |<strong class='bbc'>a</strong>|.<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4335-0-59418900-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4335" title="image009.gif - Size: 368bytes, Downloads: 37"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-18438000-1311406906_thumb.gif" id='ipb-attach-img-4335-0-59418900-1330210056' style='width:127;height:31' class='attach' width="127" height="31" alt="Attached Image: image009.gif" /></a> in 3D and <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4336-0-59436300-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4336" title="image011.gif - Size: 330bytes, Downloads: 33"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-71439500-1311406918_thumb.gif" id='ipb-attach-img-4336-0-59436300-1330210056' style='width:95;height:31' class='attach' width="95" height="31" alt="Attached Image: image011.gif" /></a> in 2D, where <em class='bbc'>x</em>, <em class='bbc'>y</em> and <em class='bbc'>z</em> are the components of the vector in the 3 axes of movement. <em class='bbc'>Unit vectors</em> are vectors with a magnitude of 1, so |<strong class='bbc'>a</strong>| = 1.<br />
<br />
 <strong class='bbc'>Addition</strong><br />
<br />
 Vector addition is pretty easy. All you do is add the respective components together. So for instance, take the vectors:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4337-0-59453600-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4337" title="image013.gif - Size: 404bytes, Downloads: 33"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-39555400-1311406937_thumb.gif" id='ipb-attach-img-4337-0-59453600-1330210056' style='width:52;height:75' class='attach' width="52" height="75" alt="Attached Image: image013.gif" /></a>    <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4338-0-59472900-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4338" title="image015.gif - Size: 441bytes, Downloads: 37"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-52337300-1311406947_thumb.gif" id='ipb-attach-img-4338-0-59472900-1330210056' style='width:65;height:75' class='attach' width="65" height="75" alt="Attached Image: image015.gif" /></a><br />
<br />
 The addition of these vectors would be:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4339-0-59490700-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4339" title="image017.gif - Size: 951bytes, Downloads: 34"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-28558500-1311406958_thumb.gif" id='ipb-attach-img-4339-0-59490700-1330210056' style='width:200;height:75' class='attach' width="200" height="75" alt="Attached Image: image017.gif" /></a><br />
<br />
 Get it? This can also be represented very easily in a diagram, but I will only consider this in 2D, because it's easier to draw.<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4340-0-59508400-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4340" title="image019.gif - Size: 338bytes, Downloads: 40"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-12549800-1311406970_thumb.gif" id='ipb-attach-img-4340-0-59508400-1330210056' style='width:52;height:48' class='attach' width="52" height="48" alt="Attached Image: image019.gif" /></a>    <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4341-0-59526100-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4341" title="image021.gif - Size: 346bytes, Downloads: 38"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-52518500-1311406982_thumb.gif" id='ipb-attach-img-4341-0-59526100-1330210056' style='width:65;height:48' class='attach' width="65" height="48" alt="Attached Image: image021.gif" /></a><br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4342-0-59543800-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4342" title="image022.gif - Size: 1.25K, Downloads: 39"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-25839100-1311406994_thumb.gif" id='ipb-attach-img-4342-0-59543800-1330210056' style='width:104;height:104' class='attach' width="104" height="104" alt="Attached Image: image022.gif" /></a><br />
<br />
 This works in the same way as moving the second vector so that its beginning is at the first vector's end, and taking the vector from the beginning of the first vector to the end of the second one. So, in a diagram, using the above example, this would be:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4343-0-59562000-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4343" title="image023.gif - Size: 1.21K, Downloads: 37"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-06202600-1311407005_thumb.gif" id='ipb-attach-img-4343-0-59562000-1330210056' style='width:76;height:95' class='attach' width="76" height="95" alt="Attached Image: image023.gif" /></a><br />
<br />
 This means that you can add multiple vectors together to get the <em class='bbc'>resultant</em> vector. This is used extensively in mechanics for finding resultant forces.<br />
<br />
 <strong class='bbc'>Subtracting</strong><br />
<br />
 Subtracting is very similar to adding, and is also quite helpful. All you do is subtract the components in one vector from the components in the other. The geometric representation however is very different.<br />
<br />
 Let <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4344-0-59582000-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4344" title="image025.gif - Size: 331bytes, Downloads: 35"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-83651900-1311407019_thumb.gif" id='ipb-attach-img-4344-0-59582000-1330210056' style='width:52;height:48' class='attach' width="52" height="48" alt="Attached Image: image025.gif" /></a> and <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4345-0-59600500-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4345" title="image027.gif - Size: 341bytes, Downloads: 38"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-31746600-1311407031_thumb.gif" id='ipb-attach-img-4345-0-59600500-1330210056' style='width:53;height:48' class='attach' width="53" height="48" alt="Attached Image: image027.gif" /></a><br />
<br />
 Then <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4346-0-59618400-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4346" title="image029.gif - Size: 682bytes, Downloads: 40"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-13826600-1311407045_thumb.gif" id='ipb-attach-img-4346-0-59618400-1330210056' style='width:189;height:48' class='attach' width="189" height="48" alt="Attached Image: image029.gif" /></a><br />
<br />
 The visual representation of this is:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4347-0-59636400-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4347" title="image030.gif - Size: 1.31K, Downloads: 42"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-75087900-1311407058_thumb.gif" id='ipb-attach-img-4347-0-59636400-1330210056' style='width:142;height:104' class='attach' width="142" height="104" alt="Attached Image: image030.gif" /></a><br />
<br />
 Here, <strong class='bbc'>a</strong> and <strong class='bbc'>b</strong> are set to be from the same origin. The vector <strong class='bbc'>c</strong> is the vector from the end of the second vector to the end of the first, which in this case is from the end of <strong class='bbc'>b</strong> to the end of <strong class='bbc'>a</strong>. It may be easier to think of this as a vector addition.<br />
<br />
 Where instead of having:<br />
<br />
 <strong class='bbc'>c</strong> = <strong class='bbc'>a</strong> – <strong class='bbc'>b</strong><br />
<br />
 we have<br />
<br />
 <strong class='bbc'>c</strong> = -<strong class='bbc'>b</strong> + <strong class='bbc'>a</strong><br />
<br />
 which, according to what was said about the addition of vectors would produce:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4348-0-59655000-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4348" title="image031.gif - Size: 1.32K, Downloads: 39"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-65773600-1311407075_thumb.gif" id='ipb-attach-img-4348-0-59655000-1330210056' style='width:141;height:104' class='attach' width="141" height="104" alt="Attached Image: image031.gif" /></a><br />
<br />
 You can see that putting <strong class='bbc'>a</strong> on the end of –<strong class='bbc'>b</strong> has the same result.<br />
<br />
 <strong class='bbc'>Scalar multiplication</strong><br />
<br />
 Scalar multiplication is easy to come to grips with. All you do is multiply each component by that scalar.<br />
<br />
 So, say you had the vector <strong class='bbc'>a</strong> and a scalar <em class='bbc'>k</em>, you would multiply each component by the scalar, getting this result:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4349-0-59675000-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4349" title="image033.gif - Size: 397bytes, Downloads: 40"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-89365300-1311407094_thumb.gif" id='ipb-attach-img-4349-0-59675000-1330210056' style='width:53;height:75' class='attach' width="53" height="75" alt="Attached Image: image033.gif" /></a>    <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4350-0-59693600-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4350" title="image035.gif - Size: 478bytes, Downloads: 38"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-84633600-1311407105_thumb.gif" id='ipb-attach-img-4350-0-59693600-1330210056' style='width:67;height:75' class='attach' width="67" height="75" alt="Attached Image: image035.gif" /></a><br />
<br />
 This has the effect of lengthening or shortening the vector by the amount <em class='bbc'>k</em>. For instance, take <em class='bbc'>k</em> = 2; this would make the vector <strong class='bbc'>a</strong> twice as long. Multiplying by a negative scalar reverses the direction of the vector. You can use scalar multiplication to find the unit vector of another vector. So, take the following example:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4351-0-59711700-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4351" title="image037.gif - Size: 402bytes, Downloads: 35"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-32990100-1311407143_thumb.gif" id='ipb-attach-img-4351-0-59711700-1330210056' style='width:52;height:75' class='attach' width="52" height="75" alt="Attached Image: image037.gif" /></a><br />
<br />
 To find the unit vector of this, we would divide <strong class='bbc'>a</strong> by |<strong class='bbc'>a</strong>|. Calling the unit vector "<strong class='bbc'>b</strong>":<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4352-0-59730000-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4352" title="image039.gif - Size: 725bytes, Downloads: 41"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-93077400-1311407155_thumb.gif" id='ipb-attach-img-4352-0-59730000-1330210056' style='width:250;height:21' class='attach' width="250" height="21" alt="Attached Image: image039.gif" /></a><br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4353-0-59748400-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4353" title="image041.gif - Size: 1.16K, Downloads: 35"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-58857500-1311407165_thumb.gif" id='ipb-attach-img-4353-0-59748400-1330210056' style='width:168;height:133' class='attach' width="168" height="133" alt="Attached Image: image041.gif" /></a><br />
<br />
 That is the unit vector <strong class='bbc'>b</strong> in the direction of <strong class='bbc'>a</strong>. This just scales each of the components, so that the magnitude is equal to 1.<br />
<br />
 Scalar multiplication is also used in the vector equation discussed earlier. The constants <em class='bbc'>x</em>, <em class='bbc'>y</em> and <em class='bbc'>z</em> are the scalars that scale the <strong class='bbc'>i</strong>, <strong class='bbc'>j</strong> and <strong class='bbc'>k</strong> vectors, before adding them to find the resultant vector.<br />
<br />
 <strong class='bbc'>The Scalar Product (Dot Product)</strong><br />
<br />
 The <em class='bbc'>scalar product</em>, also known as the <em class='bbc'>dot product</em>, is very useful in 3D graphics applications. The scalar product is written <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4354-0-59767200-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4354" title="image043.gif - Size: 198bytes, Downloads: 39"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-51442000-1311407185_thumb.gif" id='ipb-attach-img-4354-0-59767200-1330210056' style='width:31;height:19' class='attach' width="31" height="19" alt="Attached Image: image043.gif" /></a> and is read "<strong class='bbc'>a</strong> dot <strong class='bbc'>b</strong>".<br />
<br />
 The definition the scalar product is the following:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4355-0-59787500-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4355" title="image045.gif - Size: 354bytes, Downloads: 38"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-52876200-1311407198_thumb.gif" id='ipb-attach-img-4355-0-59787500-1330210056' style='width:107;height:27' class='attach' width="107" height="27" alt="Attached Image: image045.gif" /></a><br />
<br />
 Where q is the angle between the 2 vectors <strong class='bbc'>a</strong> and <strong class='bbc'>b</strong>. This produces a scalar result, hence the name scalar product. From this you can see that the scalar product of 2 parallel unit vectors is 1, as |<strong class='bbc'>a</strong>||<strong class='bbc'>b</strong>| = 1, and cos(0) also is 1. You should also have seen that the scalar product of two perpendicular vectors is 0, as cos(90) = 0, which makes the rest of the exp<b></b>ressi&#111;n 0. The geometric interpretation is:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4356-0-59806000-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4356" title="image046.gif - Size: 1.12K, Downloads: 38"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-98098700-1311407218_thumb.gif" id='ipb-attach-img-4356-0-59806000-1330210056' style='width:67;height:86' class='attach' width="67" height="86" alt="Attached Image: image046.gif" /></a><br />
<br />
 The scalar product can also be written in terms of Cartesian components., I will not go into how this is derived, but the final, simplified formula of <strong class='bbc'>a</strong>.<strong class='bbc'>b</strong> is:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4357-0-59824900-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4357" title="image048.gif - Size: 428bytes, Downloads: 39"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-11366200-1311407231_thumb.gif" id='ipb-attach-img-4357-0-59824900-1330210056' style='width:59;height:75' class='attach' width="59" height="75" alt="Attached Image: image048.gif" /></a>    <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4358-0-59843600-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4358" title="image050.gif - Size: 441bytes, Downloads: 37"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-25055400-1311407243_thumb.gif" id='ipb-attach-img-4358-0-59843600-1330210056' style='width:61;height:75' class='attach' width="61" height="75" alt="Attached Image: image050.gif" /></a><br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4359-0-59862100-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4359" title="image052.gif - Size: 365bytes, Downloads: 37"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-12617400-1311407255_thumb.gif" id='ipb-attach-img-4359-0-59862100-1330210056' style='width:161;height:23' class='attach' width="161" height="23" alt="Attached Image: image052.gif" /></a><br />
<br />
 We can now put these two equations equal to each other, yielding the equation:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4360-0-59882500-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4360" title="image054.gif - Size: 475bytes, Downloads: 39"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-33111200-1311407287_thumb.gif" id='ipb-attach-img-4360-0-59882500-1330210056' style='width:197;height:27' class='attach' width="197" height="27" alt="Attached Image: image054.gif" /></a><br />
<br />
 With this, we can find angles between vectors. This is used extensively in the lighting part of the graphics pipeline, as it can see whether a polygon is facing towards or away from the light source. This is also used in deciding what side of planes points are on, which is also used extensively for culling.<br />
<br />
<strong class='bbc'>The Vector Product (Cross Product)</strong><br />
 <br />
The <em class='bbc'>vector product</em>, which is also commonly known as the <em class='bbc'>cross product</em> is also useful. The vector product basically finds a vector perpendicular to two other vectors. Great for finding normal vectors to surfaces.<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4361-0-59901600-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4361" title="image055.gif - Size: 1.47K, Downloads: 42"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-74723000-1311407304_thumb.gif" id='ipb-attach-img-4361-0-59901600-1330210056' style='width:152;height:161' class='attach' width="152" height="161" alt="Attached Image: image055.gif" /></a><br />
<br />
 For those that are already familiar with determinants, the vector product is basically the expansion of the following determinant:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4362-0-59921000-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4362" title="image057.gif - Size: 468bytes, Downloads: 41"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-41178500-1311407317_thumb.gif" id='ipb-attach-img-4362-0-59921000-1330210056' style='width:82;height:71' class='attach' width="82" height="71" alt="Attached Image: image057.gif" /></a><br />
<br />
 For those that aren't, the vector product in expanded form is:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4363-0-59939900-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4363" title="image059.gif - Size: 1.38K, Downloads: 38"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-86172900-1311407330_thumb.gif" id='ipb-attach-img-4363-0-59939900-1330210056' style='width:250;height:14' class='attach' width="250" height="14" alt="Attached Image: image059.gif" /></a><br />
<br />
 Read "<strong class='bbc'>a</strong> cross <strong class='bbc'>b</strong>".<br />
<br />
 Since the cross product finds the perpendicular vector, we can say that:<br />
<br />
 <strong class='bbc'>i</strong> x <strong class='bbc'>j</strong> = <strong class='bbc'>k</strong><br />
<br />
 <strong class='bbc'>j</strong> x <strong class='bbc'>k</strong> = <strong class='bbc'>i</strong><br />
<br />
 <strong class='bbc'>k</strong> x <strong class='bbc'>i</strong> = <strong class='bbc'>j</strong><br />
<br />
 Using scalar multiplication along with the vector product we can find the "normal" vector to a plane. A plane can be defined by two vectors, <strong class='bbc'>a</strong> and <strong class='bbc'>b</strong>. The normal vector is a vector that is perpendicular to a plane and is also a unit vector. Using the formulas discussed earlier, we have:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4364-0-59959300-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4364" title="image061.gif - Size: 231bytes, Downloads: 43"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-54267700-1311407346_thumb.gif" id='ipb-attach-img-4364-0-59959300-1330210056' style='width:59;height:19' class='attach' width="59" height="19" alt="Attached Image: image061.gif" /></a><br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4365-0-59979900-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4365" title="image063.gif - Size: 263bytes, Downloads: 40"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-47469800-1311407367_thumb.gif" id='ipb-attach-img-4365-0-59979900-1330210056' style='width:44;height:47' class='attach' width="44" height="47" alt="Attached Image: image063.gif" /></a><br />
<br />
 This first finds the vector perpendicular to the plane made by <strong class='bbc'>a</strong> and <strong class='bbc'>b</strong> then scales that vector so it has a magnitude of 1. Note however, that there are 2 possible normals to the plane defined by <strong class='bbc'>a</strong> and <strong class='bbc'>b</strong>. You will get different results by swapping <strong class='bbc'>a</strong> and <strong class='bbc'>b</strong> in the vector product. That is:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4366-0-59999400-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4366" title="image065.gif - Size: 263bytes, Downloads: 38"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-65487900-1311407379_thumb.gif" id='ipb-attach-img-4366-0-59999400-1330210056' style='width:79;height:19' class='attach' width="79" height="19" alt="Attached Image: image065.gif" /></a><br />
<br />
 This is a very important point. If you put the inputs the wrong way round, the graphics API will not produce the desired lighting, as the normal will be facing in the opposite direction.<br />
<br />
 <strong class='bbc'>The Vector Equation of a Straight Line</strong><br />
<br />
 The vector equation of a straight line is very useful, and is given by a point on the line and a vector parallel to it:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4367-0-60018500-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4367" title="image067.gif - Size: 313bytes, Downloads: 39"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-26869600-1311407396_thumb.gif" id='ipb-attach-img-4367-0-60018500-1330210056' style='width:91;height:24' class='attach' width="91" height="24" alt="Attached Image: image067.gif" /></a><br />
<br />
 Where <strong class='bbc'>p</strong><sub class='bbc'>0</sub> is a point on the line and <strong class='bbc'>v</strong> is the vector. <em class='bbc'>t</em> is called the parameter, and scales <strong class='bbc'>v</strong>. From this it is easy to see that as <em class='bbc'>t</em> varies, a line is formed in the direction of <strong class='bbc'>v</strong>. If <em class='bbc'>t</em> only takes positive values, then <strong class='bbc'>p</strong><sub class='bbc'>0</sub> is the starting point of the line. Diagrammatically, this is:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4368-0-60037700-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4368" title="image068.gif - Size: 2.06K, Downloads: 35"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-46310300-1311407412_thumb.gif" id='ipb-attach-img-4368-0-60037700-1330210056' style='width:250;height:196' class='attach' width="250" height="196" alt="Attached Image: image068.gif" /></a><br />
<br />
 In expanded form, the equation becomes:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4369-0-60057400-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4369" title="image070.gif - Size: 259bytes, Downloads: 36"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-92978700-1311407426_thumb.gif" id='ipb-attach-img-4369-0-60057400-1330210056' style='width:81;height:24' class='attach' width="81" height="24" alt="Attached Image: image070.gif" /></a><br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4370-0-60078300-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4370" title="image072.gif - Size: 272bytes, Downloads: 35"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-41873900-1311407439_thumb.gif" id='ipb-attach-img-4370-0-60078300-1330210056' style='width:83;height:25' class='attach' width="83" height="25" alt="Attached Image: image072.gif" /></a><br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4371-0-60098100-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4371" title="image074.gif - Size: 259bytes, Downloads: 35"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-94295200-1311407450_thumb.gif" id='ipb-attach-img-4371-0-60098100-1330210056' style='width:80;height:23' class='attach' width="80" height="23" alt="Attached Image: image074.gif" /></a><br />
<br />
 This is called the <em class='bbc'>parametric</em> form of a straight line.<br />
<br />
 Using this to find the vector equation of a line through two points is easy:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4372-0-60117500-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4372" title="image076.gif - Size: 382bytes, Downloads: 34"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-39434100-1311407462_thumb.gif" id='ipb-attach-img-4372-0-60117500-1330210056' style='width:140;height:24' class='attach' width="140" height="24" alt="Attached Image: image076.gif" /></a><br />
<br />
 If <em class='bbc'>t</em> is confined to values between 0 and 1, then what you have is a <em class='bbc'>line segment</em> between the points <strong class='bbc'>p</strong><sub class='bbc'>0</sub> and <strong class='bbc'>p</strong><sub class='bbc'>1</sub>.<br />
<br />
 Using the vector equation we can define planes, and test for intersections. I won't go into planes much here, as there are many tutorials on them elsewhere, I'll just skim over it.<br />
<br />
 A plane can be defined as a point on the plane, and two vectors that are parallel to the plane, or:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4373-0-60136900-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4373" title="image078.gif - Size: 345bytes, Downloads: 34"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-74851200-1311407475_thumb.gif" id='ipb-attach-img-4373-0-60136900-1330210056' style='width:136;height:24' class='attach' width="136" height="24" alt="Attached Image: image078.gif" /></a><br />
<br />
 where <em class='bbc'>s</em> and <em class='bbc'>t</em> the parameters and <strong class='bbc'>u</strong> and <strong class='bbc'>v</strong> are the vectors that are parallel to the plane. Using this, it becomes easy to find the intersection of a line and a plane, because the point of intersection must lie on both the line and the plane, so we simply make the two equations equal to each other.<br />
<br />
 Take the line:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4374-0-60156500-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4374" title="image080.gif - Size: 323bytes, Downloads: 34"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-27028600-1311407486_thumb.gif" id='ipb-attach-img-4374-0-60156500-1330210056' style='width:101;height:24' class='attach' width="101" height="24" alt="Attached Image: image080.gif" /></a><br />
<br />
 and the plane:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4375-0-60177900-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4375" title="image082.gif - Size: 357bytes, Downloads: 37"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-05625300-1311407497_thumb.gif" id='ipb-attach-img-4375-0-60177900-1330210056' style='width:133;height:23' class='attach' width="133" height="23" alt="Attached Image: image082.gif" /></a><br />
<br />
 To find the intersection point we simply equate, so that:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4376-0-60198000-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4376" title="image084.gif - Size: 340bytes, Downloads: 34"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-81188500-1311407507_thumb.gif" id='ipb-attach-img-4376-0-60198000-1330210056' style='width:147;height:24' class='attach' width="147" height="24" alt="Attached Image: image084.gif" /></a><br />
<br />
 Ed. note: The <strong class='bbc'>v</strong> on the left in the above equation is not the same vector as the <strong class='bbc'>v</strong> on the right.<br />
<br />
 We then solve for <em class='bbc'>w</em>, <em class='bbc'>s</em> and <em class='bbc'>t</em>, and then plug into either the line or plane equation to find the point. When testing for a line segment intersection, <em class='bbc'>w</em> must be between 0 and 1.<br />
<br />
 There are many benefits for using the normal-distance form of a plane too. It's especially useful for testing what sides of a plane points or other shaped objects are. To do this, you dot the normal vector and the position vector of the point being tested, and add the distance of the plane from the origin.<br />
<br />
 So, if you have the plane<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4377-0-60217700-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4377" title="image086.gif - Size: 243bytes, Downloads: 38"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-79430400-1311407522_thumb.gif" id='ipb-attach-img-4377-0-60217700-1330210056' style='width:64;height:21' class='attach' width="64" height="21" alt="Attached Image: image086.gif" /></a><br />
<br />
 and the point <em class='bbc'>( x, y, z )</em>, the point is in front of the plane if<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4378-0-60237500-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4378" title="image088.gif - Size: 364bytes, Downloads: 38"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-44983900-1311407537_thumb.gif" id='ipb-attach-img-4378-0-60237500-1330210056' style='width:151;height:25' class='attach' width="151" height="25" alt="Attached Image: image088.gif" /></a><br />
<br />
 and behind if it is < 0. If the result equals zero, the point is on the plane. This is used heavily in culling and BSP trees.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Matrices</strong></span><br />
 <br />
<span style='font-size: 12px;'><strong class='bbc'>What is a Matrix anyway?</strong></span><br />
<br />
A matrix can be considered a 2D array of numbers. They take the form:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4379-0-60257400-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4379" title="image090.gif - Size: 565bytes, Downloads: 37"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-61157600-1311407567_thumb.gif" id='ipb-attach-img-4379-0-60257400-1330210056' style='width:101;height:75' class='attach' width="101" height="75" alt="Attached Image: image090.gif" /></a><br />
<br />
 Matrices are very powerful, and form the basis of all modern computer graphics, the advantage of them being that they are so fast. We define a matrix with an upper-case bold type letter. Look at the above example. The dimension of a matrix is its height followed by its width, so the above example has dimension 3x3. Matrices can be of any dimensions, but in terms of computer graphics, they are usually kept to 3x3 or 4x4. There are a few types of special matrices; these are the <em class='bbc'>column matrix</em>, <em class='bbc'>row matrix</em>, <em class='bbc'>square matrix</em>, <em class='bbc'>identity matrix</em> and <em class='bbc'>zero matrix</em>. A column matrix is one that has a width of 1, and a height of greater than 1. A row matrix is a matrix that has a width of greater than 1, and a height of 1. A square matrix is when the dimensions are the same. For instance, the above example is a square matrix, because the width equals the height. The identity matrix is a special type of matrix that has values in the diagonal from top left to bottom right as 1 and the rest as 0. The identity matrix is known by the letter <span style='font-family: Times New Roman'><strong class='bbc'>I</strong></span>, where<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4380-0-60278800-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4380" title="image092.gif - Size: 546bytes, Downloads: 34"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-35181600-1311407600_thumb.gif" id='ipb-attach-img-4380-0-60278800-1330210056' style='width:96;height:75' class='attach' width="96" height="75" alt="Attached Image: image092.gif" /></a><br />
<br />
 The identity matrix can be any dimension, as long as it is also a square matrix. The zero matrix is a matrix that has all its elements set to 0.<br />
<br />
 The <em class='bbc'>elements</em> of a matrix are all the numbers in it. They are numbered by the row/column position so that :<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4381-0-60298900-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4381" title="image094.gif - Size: 613bytes, Downloads: 35"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-86930600-1311407611_thumb.gif" id='ipb-attach-img-4381-0-60298900-1330210056' style='width:109;height:75' class='attach' width="109" height="75" alt="Attached Image: image094.gif" /></a><br />
<br />
 Vectors can also be used in column or row matrices. I will use column matrices here so that it is easier to understand. A 3D vector <strong class='bbc'>a</strong> in matrix form will use a matrix <strong class='bbc'>A</strong> with dimension 3x1 so that:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4382-0-60319100-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4382" title="image096.gif - Size: 415bytes, Downloads: 39"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-72535500-1311407625_thumb.gif" id='ipb-attach-img-4382-0-60319100-1330210056' style='width:57;height:75' class='attach' width="57" height="75" alt="Attached Image: image096.gif" /></a><br />
<br />
 which you can see is the same layout as using column vectors.<br />
<br />
 <span style='font-size: 12px;'><strong class='bbc'>Matrix arithmetic</strong></span><br />
<br />
I won't go into every matrix manipulation, but instead I'll focus on the ones that are used extensively in computer graphics.<br />
<br />
<strong class='bbc'>Matrix Multiplication</strong><br />
 <br />
There are two ways to multiply a matrix: by a scalar, and by another conformable matrix. First, let's deal with the matrix/scalar multiplication.<br />
<br />
 This is pretty easy, all you do is multiply each element by the scalar. So, let <strong class='bbc'>A</strong> be the original matrix, <strong class='bbc'>B</strong> be the matrix after multiplication, and <em class='bbc'>k</em> the constant. We perform:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4384-0-60339000-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4384" title="image098.gif - Size: 257bytes, Downloads: 34"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-96283500-1311407655_thumb.gif" id='ipb-attach-img-4384-0-60339000-1330210056' style='width:59;height:25' class='attach' width="59" height="25" alt="Attached Image: image098.gif" /></a> where <em class='bbc'>i</em> and <em class='bbc'>j</em> are the positions in the matrix.<br />
<br />
 this can also be written as:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4385-0-60358900-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4385" title="image100.gif - Size: 1.34K, Downloads: 37"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-60416100-1311407669_thumb.gif" id='ipb-attach-img-4385-0-60358900-1330210056' style='width:250;height:59' class='attach' width="250" height="59" alt="Attached Image: image100.gif" /></a><br />
<br />
 Multiplying a matrix by another matrix is more difficult. First, we need to know if the two matrices are <em class='bbc'>conformable</em>. For a matrix to be conformable with another matrix, the number of rows in <strong class='bbc'>A</strong> needs to equal the number of columns in <strong class='bbc'>B</strong>. For instance, take matrix <strong class='bbc'>A</strong> as having dimension 3x3 and matrix <strong class='bbc'>B</strong> having dimension 3x2. These two matrices are conformable because the number of rows in <strong class='bbc'>A</strong> is the same as the number of columns in <strong class='bbc'>B</strong>. This is important as you'll see later. The product of these two matrices is another matrix with dimension 3x2. So, in general terms:<br />
<br />
 Take three matrices <strong class='bbc'>A</strong>, <strong class='bbc'>B</strong> and <strong class='bbc'>C</strong> where <strong class='bbc'>C</strong> is the product of <strong class='bbc'>A</strong> and <strong class='bbc'>B</strong>. <strong class='bbc'>A</strong> and <strong class='bbc'>B</strong> have dimension <em class='bbc'>m</em>x<em class='bbc'>n</em> and <em class='bbc'>p</em>x<em class='bbc'>q</em> respectively. They are conformable if <em class='bbc'>n=p</em>. The matrix <strong class='bbc'>C</strong> has dimension <em class='bbc'>m</em>x<em class='bbc'>q</em>.<br />
<br />
 You perform the multiplication by multiplying each row in <strong class='bbc'>A</strong> by each column in <strong class='bbc'>B</strong>. So let <strong class='bbc'>A</strong> have dimension 3x3 and <strong class='bbc'>B</strong> have dimension 3x2.<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4386-0-60381000-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4386" title="image102.gif - Size: 709bytes, Downloads: 41"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-58828200-1311407689_thumb.gif" id='ipb-attach-img-4386-0-60381000-1330210056' style='width:137;height:75' class='attach' width="137" height="75" alt="Attached Image: image102.gif" /></a>        <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4387-0-60401900-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4387" title="image104.gif - Size: 609bytes, Downloads: 49"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-75807400-1311407700_thumb.gif" id='ipb-attach-img-4387-0-60401900-1330210056' style='width:100;height:75' class='attach' width="100" height="75" alt="Attached Image: image104.gif" /></a><br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4388-0-60422300-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4388" title="image106.gif - Size: 2.43K, Downloads: 56"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-93812800-1311407713_thumb.gif" id='ipb-attach-img-4388-0-60422300-1330210056' style='width:250;height:33' class='attach' width="250" height="33" alt="Attached Image: image106.gif" /></a><br />
<br />
 So, with that in mind, let's try an example:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4389-0-60443200-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4389" title="image108.gif - Size: 700bytes, Downloads: 45"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-79987200-1311407726_thumb.gif" id='ipb-attach-img-4389-0-60443200-1330210056' style='width:108;height:96' class='attach' width="108" height="96" alt="Attached Image: image108.gif" /></a>        <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4390-0-60463600-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4390" title="image110.gif - Size: 487bytes, Downloads: 45"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-00678700-1311407738_thumb.gif" id='ipb-attach-img-4390-0-60463600-1330210056' style='width:76;height:75' class='attach' width="76" height="75" alt="Attached Image: image110.gif" /></a><br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4391-0-60486100-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4391" title="image112.gif - Size: 2.75K, Downloads: 50"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-91982600-1311407747_thumb.gif" id='ipb-attach-img-4391-0-60486100-1330210056' style='width:250;height:43' class='attach' width="250" height="43" alt="Attached Image: image112.gif" /></a><br />
<br />
 It's as simple as that! Some things to note:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4392-0-60507100-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4392" title="image114.gif - Size: 252bytes, Downloads: 48"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-29109000-1311407760_thumb.gif" id='ipb-attach-img-4392-0-60507100-1330210056' style='width:68;height:17' class='attach' width="68" height="17" alt="Attached Image: image114.gif" /></a><br />
<br />
 A matrix multiplied by the identity matrix is the same, so:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4393-0-60528000-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4393" title="image116.gif - Size: 265bytes, Downloads: 33"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-52847700-1311407772_thumb.gif" id='ipb-attach-img-4393-0-60528000-1330210056' style='width:88;height:17' class='attach' width="88" height="17" alt="Attached Image: image116.gif" /></a><br />
<br />
 The <em class='bbc'>transpose</em> of a matrix is it flipped on the diagonal from the top left to the bottom right, so for example:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4394-0-60548500-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4394" title="image118.gif - Size: 561bytes, Downloads: 37"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-93459600-1311407784_thumb.gif" id='ipb-attach-img-4394-0-60548500-1330210056' style='width:101;height:75' class='attach' width="101" height="75" alt="Attached Image: image118.gif" /></a><br />
<br />
 The transpose of this matrix would be:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4395-0-60570600-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4395" title="image120.gif - Size: 576bytes, Downloads: 34"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-35495300-1311407805_thumb.gif" id='ipb-attach-img-4395-0-60570600-1330210056' style='width:111;height:75' class='attach' width="111" height="75" alt="Attached Image: image120.gif" /></a><br />
<br />
 Simple enough eh? And you thought it was going to be hard!<br />
<br />
 <span style='font-size: 12px;'><strong class='bbc'>Determinants</strong></span><br />
<br />
I'm going to talk a little bit about determinants now, as they are useful for solving certain types of equations. I will discuss easy 2x2 determinants first.<br />
<br />
 Take a 2x2 matrix:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4396-0-60591700-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4396" title="image122.gif - Size: 474bytes, Downloads: 37"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-76083400-1311407842_thumb.gif" id='ipb-attach-img-4396-0-60591700-1330210056' style='width:103;height:51' class='attach' width="103" height="51" alt="Attached Image: image122.gif" /></a><br />
<br />
 The determinant of a matrix <strong class='bbc'>A</strong> is written |<strong class='bbc'>A</strong>| and is:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4397-0-60612400-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4397" title="image124.gif - Size: 362bytes, Downloads: 33"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-61430500-1311407863_thumb.gif" id='ipb-attach-img-4397-0-60612400-1330210056' style='width:128;height:27' class='attach' width="128" height="27" alt="Attached Image: image124.gif" /></a><br />
<br />
 For higher dimension matrices, the determinant gets more complicated. Let's discuss a 3x3 matrix. You pass along the first row, and at each element, you discount the row and column that intersects it, and calculate the determinant of the resultant 2x2 matrix multiplied by that value.<br />
<br />
 So, for example, take this 3x3 matrix:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4398-0-60633200-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4398" title="image126.gif - Size: 709bytes, Downloads: 33"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-93920700-1311407878_thumb.gif" id='ipb-attach-img-4398-0-60633200-1330210056' style='width:137;height:75' class='attach' width="137" height="75" alt="Attached Image: image126.gif" /></a><br />
<br />
 Ok then, Step 1: move to the first value in the top row, <em class='bbc'>a</em><sub class='bbc'>11</sub> . Take out the row and column that intersects with that value. Step 2: multiply that determinant by <em class='bbc'>a</em><sub class='bbc'>11</sub>. So, using diagrams:<br />
<br />
 Step1:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4399-0-60654000-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4399" title="image128.gif - Size: 542bytes, Downloads: 35"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-41315500-1311407890_thumb.gif" id='ipb-attach-img-4399-0-60654000-1330210056' style='width:108;height:75' class='attach' width="108" height="75" alt="Attached Image: image128.gif" /></a><br />
<br />
 Step2:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4400-0-60676500-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4400" title="image130.gif - Size: 420bytes, Downloads: 39"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-76373600-1311407901_thumb.gif" id='ipb-attach-img-4400-0-60676500-1330210056' style='width:84;height:51' class='attach' width="84" height="51" alt="Attached Image: image130.gif" /></a><br />
<br />
 We repeat this all along the top row, with the sign in front of the value of the top row alternating between a "+" and a "-", so the determinant of <strong class='bbc'>A</strong> would be:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4401-0-60697800-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4401" title="image132.gif - Size: 958bytes, Downloads: 32"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-62269500-1311407916_thumb.gif" id='ipb-attach-img-4401-0-60697800-1330210056' style='width:250;height:42' class='attach' width="250" height="42" alt="Attached Image: image132.gif" /></a><br />
<br />
 Now, how do we use these for equation solving? Good question. I will first show you how to solve a pair of equations with 2 unknowns.<br />
<br />
 Take the two equations:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4402-0-60719100-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4402" title="image134.gif - Size: 429bytes, Downloads: 35"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-36208700-1311407930_thumb.gif" id='ipb-attach-img-4402-0-60719100-1330210056' style='width:96;height:48' class='attach' width="96" height="48" alt="Attached Image: image134.gif" /></a><br />
<br />
 We first <em class='bbc'>push</em> the coefficients of the variables into a determinant, producing:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4403-0-60740300-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4403" title="image136.gif - Size: 332bytes, Downloads: 32"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-95740300-1311407941_thumb.gif" id='ipb-attach-img-4403-0-60740300-1330210056' style='width:55;height:51' class='attach' width="55" height="51" alt="Attached Image: image136.gif" /></a><br />
<br />
 You can see it's laid out in the same way, which makes it easy. Now, to solve the equation in terms of <em class='bbc'>x</em>, we replace the x coefficients in the determinant with the constants <em class='bbc'>k<sub class='bbc'>1</sub></em> and <em class='bbc'>k<sub class='bbc'>2</sub></em>, dividing the result by the original determinant. So, that would be:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4404-0-60761600-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4404" title="image138.gif - Size: 608bytes, Downloads: 39"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-46880800-1311407957_thumb.gif" id='ipb-attach-img-4404-0-60761600-1330210056' style='width:145;height:51' class='attach' width="145" height="51" alt="Attached Image: image138.gif" /></a><br />
<br />
 To solve for <em class='bbc'>y</em> we replace the y coefficients with the constants instead.<br />
<br />
 Let's try an example to see this working:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4405-0-60784800-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4405" title="image140.gif - Size: 368bytes, Downloads: 35"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-74094200-1311407970_thumb.gif" id='ipb-attach-img-4405-0-60784800-1330210056' style='width:88;height:45' class='attach' width="88" height="45" alt="Attached Image: image140.gif" /></a><br />
<br />
 We push the coefficients into a determinant, and solve:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4406-0-60806300-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4406" title="image142.gif - Size: 540bytes, Downloads: 35"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-03371400-1311407986_thumb.gif" id='ipb-attach-img-4406-0-60806300-1330210056' style='width:189;height:48' class='attach' width="189" height="48" alt="Attached Image: image142.gif" /></a><br />
<br />
 To find <em class='bbc'>x</em> substitute constants into <em class='bbc'>x</em> co-efficients, and divide by <strong class='bbc'>D</strong>:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4407-0-60827900-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4407" title="image144.gif - Size: 776bytes, Downloads: 35"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-34552100-1311407997_thumb.gif" id='ipb-attach-img-4407-0-60827900-1330210056' style='width:228;height:72' class='attach' width="228" height="72" alt="Attached Image: image144.gif" /></a><br />
<br />
 To find <em class='bbc'>y</em> substitute constants into <em class='bbc'>y</em> co-efficients and divide by <strong class='bbc'>D</strong>:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4408-0-60849500-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4408" title="image146.gif - Size: 790bytes, Downloads: 38"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-60848100-1311408028_thumb.gif" id='ipb-attach-img-4408-0-60849500-1330210056' style='width:229;height:72' class='attach' width="229" height="72" alt="Attached Image: image146.gif" /></a><br />
<br />
 See, it's as simple as that! Just for good measure, I'll do an example using 3 unknowns in 3 equations:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4409-0-60872700-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4409" title="image148.gif - Size: 534bytes, Downloads: 39"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-66491000-1311408041_thumb.gif" id='ipb-attach-img-4409-0-60872700-1330210056' style='width:109;height:69' class='attach' width="109" height="69" alt="Attached Image: image148.gif" /></a><br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4410-0-60894700-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4410" title="image150.gif - Size: 1.32K, Downloads: 38"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-60304700-1311408056_thumb.gif" id='ipb-attach-img-4410-0-60894700-1330210056' style='width:250;height:59' class='attach' width="250" height="59" alt="Attached Image: image150.gif" /></a><br />
<br />
 Solve for <em class='bbc'>x</em>:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4411-0-60916900-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4411" title="image152.gif - Size: 1.51K, Downloads: 38"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-07028100-1311408071_thumb.gif" id='ipb-attach-img-4411-0-60916900-1330210056' style='width:250;height:57' class='attach' width="250" height="57" alt="Attached Image: image152.gif" /></a><br />
<br />
 Solve for <em class='bbc'>y</em>:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4412-0-60939200-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4412" title="image154.gif - Size: 1.51K, Downloads: 38"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-35264300-1311408084_thumb.gif" id='ipb-attach-img-4412-0-60939200-1330210056' style='width:250;height:58' class='attach' width="250" height="58" alt="Attached Image: image154.gif" /></a><br />
<br />
 Solve for <em class='bbc'>z</em>:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4413-0-60961500-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4413" title="image156.gif - Size: 1.42K, Downloads: 36"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-88537000-1311408097_thumb.gif" id='ipb-attach-img-4413-0-60961500-1330210056' style='width:250;height:61' class='attach' width="250" height="61" alt="Attached Image: image156.gif" /></a><br />
<br />
 And there we have it, how to solve a series of simultaneous equations using determinants, something that can be very useful.<br />
<br />
 <strong class='bbc'>Matrix Inversion</strong><br />
<br />
 Equations can also be solved by inverting a matrix. Take the following equations again:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4414-0-60985600-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4414" title="image157.gif - Size: 534bytes, Downloads: 39"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-56571200-1311408118_thumb.gif" id='ipb-attach-img-4414-0-60985600-1330210056' style='width:109;height:69' class='attach' width="109" height="69" alt="Attached Image: image157.gif" /></a><br />
<br />
 We push these into 3 matrices to solve:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4415-0-61007600-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4415" title="image159.gif - Size: 865bytes, Downloads: 38"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-90083900-1311408131_thumb.gif" id='ipb-attach-img-4415-0-61007600-1330210056' style='width:157;height:75' class='attach' width="157" height="75" alt="Attached Image: image159.gif" /></a><br />
<br />
 Let's give these names such that:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4416-0-61029600-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4416" title="image161.gif - Size: 233bytes, Downloads: 41"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-02710700-1311408147_thumb.gif" id='ipb-attach-img-4416-0-61029600-1330210056' style='width:56;height:17' class='attach' width="56" height="17" alt="Attached Image: image161.gif" /></a><br />
<br />
 We need to solve for B, and since there is no "matrix divide" operation, we need to invert the matrix <strong class='bbc'>A</strong> and multiply it by <strong class='bbc'>D</strong>, such that:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4417-0-61051600-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4417" title="image163.gif - Size: 254bytes, Downloads: 36"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-35483900-1311408160_thumb.gif" id='ipb-attach-img-4417-0-61051600-1330210056' style='width:68;height:20' class='attach' width="68" height="20" alt="Attached Image: image163.gif" /></a><br />
<br />
 Now we need to know how to actually do the matrix inversion. There are many ways to do this, and the way I am going to show you is by no means the fastest.<br />
<br />
 To find the inverse of a matrix, we need to first find its <em class='bbc'>co-factor</em>. We use a method similar to what we used when finding the determinant. What you do is this: at every element, eliminate the row and column that intersects it, and make it equal the determinant of the remaining part of the matrix. Let's find the first element in a 3x3 matrix. Let's call it c<sub class='bbc'>11</sub>. We need to get rid of the row and column that intersects this, so that:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4418-0-61075400-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4418" title="image164.gif - Size: 542bytes, Downloads: 36"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-44070200-1311408176_thumb.gif" id='ipb-attach-img-4418-0-61075400-1330210056' style='width:108;height:75' class='attach' width="108" height="75" alt="Attached Image: image164.gif" /></a><br />
<br />
 c<sub class='bbc'>11</sub> will then take the value of the following determinant:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4419-0-61097800-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4419" title="image166.gif - Size: 366bytes, Downloads: 35"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-22853200-1311408190_thumb.gif" id='ipb-attach-img-4419-0-61097800-1330210056' style='width:65;height:51' class='attach' width="65" height="51" alt="Attached Image: image166.gif" /></a><br />
<br />
 The sign in front of c<sub class='bbc'>11</sub> is decided by the exp<b></b>ressi&#111;n:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4420-0-61120000-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4420" title="image168.gif - Size: 234bytes, Downloads: 37"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-42517300-1311408207_thumb.gif" id='ipb-attach-img-4420-0-61120000-1330210056' style='width:47;height:24' class='attach' width="47" height="24" alt="Attached Image: image168.gif" /></a><br />
<br />
 Where <em class='bbc'>i</em> and <em class='bbc'>j</em> are the positions of the element in the matrix.<br />
<br />
 That's easy enough isn't it? Thought so J. Just do the same for every element, and build up the co-factor matrix. Done? Good. Now that the co-factor matrix has been found, the inverse matrix can be calculated using the following equation:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4421-0-61142300-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4421" title="image170.gif - Size: 338bytes, Downloads: 35"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-23509400-1311408221_thumb.gif" id='ipb-attach-img-4421-0-61142300-1330210056' style='width:69;height:49' class='attach' width="69" height="49" alt="Attached Image: image170.gif" /></a><br />
<br />
 Taking the previous example and equations, let's find the inverse matrix of <strong class='bbc'>A</strong>.<br />
<br />
 First, the co-factor matrix <strong class='bbc'>C</strong> would be:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4422-0-61164600-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4422" title="image172.gif - Size: 2.28K, Downloads: 37"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-40859400-1311408235_thumb.gif" id='ipb-attach-img-4422-0-61164600-1330210056' style='width:250;height:115' class='attach' width="250" height="115" alt="Attached Image: image172.gif" /></a><br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4423-0-61189400-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4423" title="image174.gif - Size: 632bytes, Downloads: 35"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-53635100-1311408248_thumb.gif" id='ipb-attach-img-4423-0-61189400-1330210056' style='width:139;height:75' class='attach' width="139" height="75" alt="Attached Image: image174.gif" /></a><br />
<br />
 and |<strong class='bbc'>A</strong>| is:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4424-0-61212000-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4424" title="image176.gif - Size: 253bytes, Downloads: 40"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-60668100-1311408264_thumb.gif" id='ipb-attach-img-4424-0-61212000-1330210056' style='width:56;height:27' class='attach' width="56" height="27" alt="Attached Image: image176.gif" /></a><br />
<br />
 So <strong class='bbc'>A</strong>­­<sup class='bbc'>-1</sup> is:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4425-0-61234600-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4425" title="image178.gif - Size: 2.08K, Downloads: 36"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-22468900-1311408277_thumb.gif" id='ipb-attach-img-4425-0-61234600-1330210056' style='width:250;height:61' class='attach' width="250" height="61" alt="Attached Image: image178.gif" /></a><br />
<br />
 To solve the equations, we then do:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4426-0-61257700-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4426" title="image163.gif - Size: 254bytes, Downloads: 41"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-36524500-1311408291_thumb.gif" id='ipb-attach-img-4426-0-61257700-1330210056' style='width:68;height:20' class='attach' width="68" height="20" alt="Attached Image: image163.gif" /></a><br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4427-0-61282200-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4427" title="image182.gif - Size: 1.26K, Downloads: 41"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-70122200-1311408302_thumb.gif" id='ipb-attach-img-4427-0-61282200-1330210056' style='width:250;height:69' class='attach' width="250" height="69" alt="Attached Image: image182.gif" /></a><br />
<br />
 We can then find the values of <em class='bbc'>x</em>,<em class='bbc'>y</em> and <em class='bbc'>z</em> by pulling them out of the last matrix, such that x = -62, y = 39 and z = 3, which is what the other method using determinants found.<br />
<br />
 A matrix is called <em class='bbc'>orthogonal</em> if its inverse equals its transpose.<br />
<br />
 <span style='font-size: 12px;'><strong class='bbc'>Matrices in computer graphics</strong></span><br />
<br />
All graphics APIs use a set of matrices to define transformations in space. A transformation is a change, be it translation, rotation, or whatever. Using column a matrix to define a point in space, a <em class='bbc'>vertex</em>, we can define matrices that alter that point in some way.<br />
<br />
 <strong class='bbc'>Transformation Matrices</strong><br />
<br />
 Most graphics APIs use 3 different types of primary transformations. These are:<br />
 <ul class='bbcol decimal'><li>Translation</li><li>Scale</li><li>Rotation</li></ul> I won't go into the derivation of the matrices for these transformations, as that will take up far too much space. Any good math book that explains affine space transformations will explain their derivations. You have to pre-multiply points by the transformation matrix, as it is impossible to post-multiply because of the dimensions.<br />
<br />
 Therefore, a point <strong class='bbc'>p</strong> can be transformed to point <strong class='bbc'>p'</strong> using a transformation matrix <strong class='bbc'>T</strong> so that:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4428-0-61305800-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4428" title="image184.gif - Size: 232bytes, Downloads: 34"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-21418000-1311408329_thumb.gif" id='ipb-attach-img-4428-0-61305800-1330210056' style='width:49;height:21' class='attach' width="49" height="21" alt="Attached Image: image184.gif" /></a><br />
<br />
 <strong class='bbc'>Translation</strong><br />
<br />
 To translate a point onto another point, there needs to be a vector of movement, so that<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4429-0-61329500-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4429" title="image185.gif - Size: 2.08K, Downloads: 38"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-33354500-1311408346_thumb.gif" id='ipb-attach-img-4429-0-61329500-1330210056' style='width:250;height:132' class='attach' width="250" height="132" alt="Attached Image: image185.gif" /></a><br />
<br />
 where <strong class='bbc'>p</strong><sup class='bbc'>'</sup> is the translated point, <strong class='bbc'>p</strong> is the original point, and <strong class='bbc'>v</strong> is the vector along which to translate.<br />
<br />
 In matrix form, this turns into:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4430-0-61352800-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4430" title="image187.gif - Size: 819bytes, Downloads: 41"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-82034400-1311408360_thumb.gif" id='ipb-attach-img-4430-0-61352800-1330210056' style='width:131;height:96' class='attach' width="131" height="96" alt="Attached Image: image187.gif" /></a><br />
<br />
 Where <em class='bbc'>dx</em>, <em class='bbc'>dy</em> and <em class='bbc'>dz</em> are the components of the vector in the respective axis of movement. Note that a 4D vertex is used. These are called <em class='bbc'>homogeneous</em> co-ordinates, BUT I will not discuss them here.<br />
<br />
 <strong class='bbc'>Scaling</strong><br />
<br />
 You can scale a vertex by multiplying it by a scalar value, so that<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4431-0-61378300-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4431" title="image188.gif - Size: 2.8K, Downloads: 39"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-08438100-1311408378_thumb.gif" id='ipb-attach-img-4431-0-61378300-1330210056' style='width:250;height:102' class='attach' width="250" height="102" alt="Attached Image: image188.gif" /></a><br />
<br />
 where <em class='bbc'>k</em> is the scalar constant. You can multiply each component of <strong class='bbc'>p</strong> by a different constant. This will make it so you can scale each axis by a different amount.<br />
<br />
 In matrix form this is:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4432-0-61402500-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4432" title="image190.gif - Size: 846bytes, Downloads: 49"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-03040100-1311408393_thumb.gif" id='ipb-attach-img-4432-0-61402500-1330210056' style='width:140;height:96' class='attach' width="140" height="96" alt="Attached Image: image190.gif" /></a><br />
<br />
 <strong class='bbc'>Rotation</strong><br />
<br />
 Rotation is the most complex transformation. Rotation can be performed around the 3 Cartesian axes.<br />
<br />
 The rotation matrices around these axis are:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4433-0-61426600-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4433" title="image192.gif - Size: 2.38K, Downloads: 46"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-30845900-1311408411_thumb.gif" id='ipb-attach-img-4433-0-61426600-1330210056' style='width:132;height:200' class='attach' width="132" height="200" alt="Attached Image: image192.gif" /></a><br />
<br />
 To find out more about how these matrices are derived, please pick up a good math book, I haven't got the time to write it here. Some things about these matrices though:<br />
<br />
 Any rotation about an axis by q can be undone by a successive rotation by -q. So:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4434-0-61450100-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4434" title="image194.gif - Size: 332bytes, Downloads: 43"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-63177900-1311408429_thumb.gif" id='ipb-attach-img-4434-0-61450100-1330210056' style='width:109;height:24' class='attach' width="109" height="24" alt="Attached Image: image194.gif" /></a><br />
<br />
 Also, notice that the cosine terms are always on the top-left to bottom-right diagonal, and the sine terms are always on the top-right to bottom-left diagonal, we can also say that:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4435-0-61475900-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4435" title="image196.gif - Size: 337bytes, Downloads: 45"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-56985200-1311408443_thumb.gif" id='ipb-attach-img-4435-0-61475900-1330210056' style='width:109;height:24' class='attach' width="109" height="24" alt="Attached Image: image196.gif" /></a><br />
<br />
 Rotations matrices that act about the origin are orthogonal.<br />
<br />
 Note that these transformations are cumulative. That is, if you multiplied a vertex by a translation matrix, then by a scale matrix, it would have the effect of moving the vertex, then scaling it. The order that you multiply becomes very important when you multiply rotation and translation matrices together, as <strong class='bbc'>RT</strong> does NOT equal <strong class='bbc'>TR</strong>!<br />
<br />
 <strong class='bbc'>Projection Matrices</strong><br />
<br />
 These are also complicated matrices. They come in two flavours, <em class='bbc'>perspective correct</em> and <em class='bbc'>orthographic</em>. There are some very good books that derive these matrices in an understandable way, so I won't cover it here. Since I don't work with projection matrices very often, I had to look a lot of this material up using the book <a href='http://www.gamedev.net/columns/books/featuredbook.asp?ProductID=111' class='bbc_url' title=''>Interactive Computer Graphics</a> by Edward Angel. A very good book that I suggest you buy.<br />
<br />
 Anyway, on to the matrices.<br />
<br />
 The orthographic projection matrix:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4436-0-61499500-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4436" title="image198.gif - Size: 1.77K, Downloads: 46"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-55531000-1311408467_thumb.gif" id='ipb-attach-img-4436-0-61499500-1330210056' style='width:250;height:97' class='attach' width="250" height="97" alt="Attached Image: image198.gif" /></a><br />
<br />
 The <em class='bbc'>x</em>, <em class='bbc'>y</em> and <em class='bbc'>z</em> <em class='bbc'>max/min</em> variables define the viewing volume.<br />
<br />
 The perspective correct projection matrix is:<br />
<br />
 <a class='resized_img' rel='lightbox[a8270dc4702b462f801bfae27a070d86]' id='ipb-attach-url-4437-0-61524100-1330210056' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=4437" title="image200.gif - Size: 1.92K, Downloads: 48"><img src="http://public.gamedev.net/uploads/monthly_07_2011/ccs-8549-0-56064000-1311408486_thumb.gif" id='ipb-attach-img-4437-0-61524100-1330210056' style='width:250;height:94' class='attach' width="250" height="94" alt="Attached Image: image200.gif" /></a><br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Conclusion</strong></span><br />
<br />
Well, that's it for this tutorial. I hope that I've helped you understand vectors and matrices including how to use them. For further reading I can recommend a few books that I have found really useful, these are:<br />
<br />
 <a href='http://www.gamedev.net/columns/books/featuredbook.asp?ProductID=111' class='bbc_url' title=''>Interactive Computer Graphics – A Top Down Approach with OpenGL" –</a> Edward Angel: Covers a lot of theory in computer graphics, including how we perceive the world around us. This book covers a lot of the matrix derivations that I left out. All in all, a very good book on graphics programming and theory. With exercises too, which is nice.<br />
<br />
 <a href='http://www.gamedev.net/columns/books/featuredbook.asp?productid=135' class='bbc_url' title=''>Mathematics for Computer Graphics Applications – Second Edition</a> – M.E Mortenson: This is solely about the mathematics behind computer graphics, and explains a lot of material in a very easy to understand manner. There are loads of exercises to keep you occupied. The book explains things such as vectors, matrices, transformations, topology and continuity, symmetry, polyhedra, half-spaces, constructive solid geometry, points, lines, curves, surfaces, and more! A must for anyone serious in graphics programming. You won't see a line of code or pseudo-code though.<br />
<br />
 <span class='bbc_underline'>Advanced National Certificate Mathematics Vol.: 2</span> – Pedoe: I don't know whether you can actually get this book anymore, but if you can get a copy! This book explains mathematical concepts well, and is easy to learn from. This book is about general mathematics though, each volume expands on the other. So vol. 1 introduces concepts, vol. 2 expands on them. A book well worth the money (although I have no idea how much it is, as I got my copy off my dad ).<br />
<br />
 That's about it! I hope I haven't scared you off graphics programming. Most APIs, including Direct3D and OpenGL, will hide some of this away from you.<br />
<br />
 If you need to contact me at all, my email address is: <a href='mailto:phil.dadd@btinternet.com' title='E-mail Link' class='bbc_email'>phil.dadd@btinternet.com</a>. I don't want any abuse though - if you don't like this tutorial I accept constructive advice only.<br />
<br />
 <br />
<strong class='bbc'><span style='font-size: 18px;'>Credits</span><br />
<br />
</strong> I'd like to give credit to "Advanced National Certificate Mathematics Vol.: 2" as that's where I got the simultaneous equations from in the part on determinants, so I knew the answers were whole, and that they worked out. I would also like to give credit to Miss. A Miller who proof read this tutorial for me.]]></description>
		<pubDate>Tue, 04 Jun 2002 23:47:26 +0000</pubDate>
		<guid isPermaLink="false">d20d9896e5f7a733d09c07acb323154f</guid>
	</item>
	<item>
		<title>The Matrix and Quaternions FAQ</title>
		<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/the-matrix-and-quaternions-faq-r1691</link>
		<description><![CDATA[<span style='font-family: Courier New'><strong class='bbc'>(Editor's Note - This article requires additional formatting work and is incomplete)</strong><br />
<br />
Version 1.21&nbsp;&nbsp;30th November 2003<br />
-------------------------------<br />
Please mail feedback to <a href='mailto:matrix_faq@j3d.org' title='E-mail Link' class='bbc_email'>matrix_faq@j3d.org</a><br />
with a subject starting with&nbsp;&nbsp;<strong class='bbc'>MATRIX-FAQ </strong><br />
<br />
(otherwise my spam filter will simply kill your message).<br />
Any additional suggestions or related questions are welcome.<br />
Just send E-mail to the above address.<br />
The latest copy of this FAQ can be found at the following web page:<br />
<br />
<a href='http://www.j3d.org/matrix_faq/matrfaq_latest.html' class='bbc_url' title='External link' rel='nofollow external'>http://www.j3d.org/m...faq_latest.html</a><br />
Feel free to distribute or copy this FAQ as you please.<br />
<br />
Contributions<br />
-------------<br />
<br />
&nbsp;&nbsp;<a href='#I1'>Introduction I1</a>: <a href='mailto:steve@%28no-spam%29mred.bgm.link.com' title='E-mail Link' class='bbc_email'>Steve ?????</a><br />
&nbsp;&nbsp;Correction to <a href='#Q55'>Q55</a> until <a href='#Q59'>Q59</a>:<br />
&nbsp;&nbsp;<a href='mailto:andreas.junghanns@%28no-spam%29dcx.com' title='E-mail Link' class='bbc_email'>Andreas Junghanns</a><br />
<br />
&nbsp;&nbsp;Correction to <a href='#Q50'>Q50</a>: <a href='mailto:morten@%28no-spam%29innerloop.no' title='E-mail Link' class='bbc_email'>Morten Ofstad</a><br />
&nbsp;&nbsp;Note to <a href='#Q39'>Q39</a>: <a href='mailto:t.nuydens@%28no-spam%29vrcontext.com' title='E-mail Link' class='bbc_email'>Tom Nuydens</a><br />
&nbsp;&nbsp;Corrections to <a href='#Q29'>Q29</a> and <a href='#Q37'>Q37</a>: </span><a href='mailto:eric@%28no-spam%29ee.pitt.edu' title='E-mail Link' class='bbc_email'><span style='font-family: Courier New'>Eric Reiss</span> </a><span style='font-family: Courier New'><br />
&nbsp;&nbsp;Clarification to <a href='#Q56'>Q56</a>: <a href='mailto:murdoch@%28no-spam%29fisher.stats.uwo.ca' title='E-mail Link' class='bbc_email'>Duncan Murdoch</a><br />
&nbsp;&nbsp;Clarification to <a href='#Q37'>Q37</a>: <a href='mailto:avitzur@%28no-spam%29PacificT.com' title='E-mail Link' class='bbc_email'>Ron Avitzur</a><br />
&nbsp;&nbsp;Correction to <a href='#Q1'>Q1</a>: <a href='mailto:mona@%28no-spam%29ncmir.ucsd.edu' title='E-mail Link' class='bbc_email'>Mona Wong</a><br />
<br />
&nbsp;&nbsp;Corrections to <a href='#Q36'>Q36</a> and <a href='#Q37'>Q37</a>: <a href='mailto:eric@%28no-spam%29ee.pitt.edu' title='E-mail Link' class='bbc_email'>Eric Reiss</a><br />
&nbsp;&nbsp;Improvement to <a href='#Q34'>Q34</a> and <a href='#Q38'>Q38</a>: <a href='mailto:hplus-mail@%28no-spam%29mindcontrol.org' title='E-mail Link' class='bbc_email'>Jon Watte</a><br />
<br />
&nbsp;&nbsp;Warning and alternative to <a href='#Q58'>Q58</a> and <a href='#Q59'>Q59</a>: <a href='mailto:PPedriana@%28no-spam%29maxis.com' title='E-mail Link' class='bbc_email'>Paul Pedriana</a><br />
&nbsp;&nbsp;Correction (and optimization [Lee]) to <a href='#Q53'>Q53</a>: <a href='mailto:ellieg@%28no-spam%29cableinet.co.uk' title='E-mail Link' class='bbc_email'>Eleanor Groundwater</a> and <a href='mailto:LeeMorgan@%28no-spam%29lee-morgan.net' title='E-mail Link' class='bbc_email'>Lee Morgan</a><br />
<br />
&nbsp;&nbsp;Improvement to <a href='#Q39'>Q39</a>: <a href='mailto:jhunpingco@%28no-spam%29yahoo.com' title='E-mail Link' class='bbc_email'>jhunpingco</a><br />
&nbsp;&nbsp;Corrections to <a href='#Q11'>Q11</a> and optimization to <a href='#Q12'>Q12</a>: <a href='mailto:GDW33@%28no-spam%29student.canterbury.ac.nz' title='E-mail Link' class='bbc_email'>Gordon</a><br />
&nbsp;&nbsp;Corrections to <a href='#Q54'>Q54</a> to <a href='#Q60'>Q60</a>: <a href='mailto:eleanorg@%28no-spam%29owl.co.uk' title='E-mail Link' class='bbc_email'>Eleanor Groundwater</a><br />
<br />
&nbsp;&nbsp;Corrections and improvements to <a href='#Q23'>Q23</a> and <a href='#Q24'>Q24</a>: <a href='mailto:ben@%28no-spam%29exocortex.org' title='E-mail Link' class='bbc_email'>Ben Houston</a><br />
&nbsp;&nbsp;Addition to <a href='#Q39'>Q39</a>: <a href='mailto:hplus@%28no-spam%29mindcontrol.org' title='E-mail Link' class='bbc_email'>Jon Watte</a><br />
&nbsp;&nbsp;Correction to <a href='#Q61'>Q61</a>: <a href='mailto:adam@%28no-spam%29gimp.org' title='E-mail Link' class='bbc_email'>Adam D. Moss</a><br />
<br />
&nbsp;&nbsp;Addition of <a href='#Q63'>Q63</a>: <a href='mailto:cline@%28no-spam%29cs.ubc.ca' title='E-mail Link' class='bbc_email'>Mike Cline</a><br />
&nbsp;&nbsp;Addition of <a href='#I2'>I2</a>: <a href='mailto:jacob@%28no-spam%29marner.dk' title='E-mail Link' class='bbc_email'>Jacob Marner</a><br />
&nbsp;&nbsp;Correction to <a href='#Q38'>Q38</a> and inception of <a href='#I2'>I2</a>: <a href='mailto:armuller@%28no-spam%29ira.uka.de' title='E-mail Link' class='bbc_email'>Armin M?ller</a><br />
<br />
&nbsp;&nbsp;Addition of <a href='#Q60'>Q60</a>: <a href='mailto:pfiguero@%28no-spam%29cs.ualberta.ca' title='E-mail Link' class='bbc_email'>Pablo Figueroa</a><br />
&nbsp;&nbsp;Correntions and additions to <a href='#Q14'>Q14</a>, <a href='#Q16'>Q16</a>, <a href='#Q21'>Q21</a> and <a href='#Q34'>Q34</a>: <a href='mailto:tronster321@%28no-spam%29hotmail.com' title='E-mail Link' class='bbc_email'>Tronster Hartley</a><br />
<br />
&nbsp;&nbsp;Correction to <a href='#Q12'>Q12</a> and <a href='#Q54'>Q54</a>: <a href='mailto:frankdj@%28no-spam%29mailhost.ph.tn.tudelft.nl' title='E-mail Link' class='bbc_email'>Frank DJ</a><br />
&nbsp;&nbsp;Correction to <a href='#Q34'>Q34</a>: <a href='mailto:robert.funnell@i%28no-spam%29mcgill.ca' title='E-mail Link' class='bbc_email'>Robert Funnell</a><br />
<br />
<br />
History<br />
-------<br />
I (Andreas) tried to find "<a href='mailto:hexapod@%28no-spam%29netcom.com' title='E-mail Link' class='bbc_email'>hexapod@(no-spam)netcom.com</a>" who seemed to have maintained<br />
this for a while, but the site at netcom.com doesn't exist anymore,<br />
emails bounce.&nbsp;&nbsp;Since I (and colleques) wasted quite some time figuring out<br />
what was wrong with some of the algorithms given in the earlier versions of<br />
this document, I decided to correct it and put it back on the web.<br />
The formerly given sites for the location of these documents do<br />
not exist anymore:<br />
&nbsp;&nbsp;ftp://ftp.netcom.com/pub/he/hexapod/index.html<br />
&nbsp;&nbsp;http://www.glue.umd.edu/~rsrodger<br />
&nbsp;&nbsp;Versions, dates and links to local copies (so you can compare):<br />
matrfaq_1.02.html: Version 1.2&nbsp;&nbsp;2nd September 1997<br />
matrfaq_1.04.html: Version 1.4&nbsp;&nbsp;26th December 1998<br />
matrfaq_1.06.html: Version 1.6&nbsp;&nbsp;30th September 2000<br />
matrfaq_1.07.html: Version 1.7&nbsp;&nbsp;20th December 2000<br />
matrfaq_1.08.html: Version 1.8&nbsp;&nbsp;21th December 2000<br />
matrfaq_1.09.html: Version 1.9&nbsp;&nbsp;16th January 2001<br />
matrfaq_1.10.html: Version 1.10&nbsp;&nbsp;30th January 2001<br />
<br />
matrfaq_1.11.html: Version 1.11&nbsp;&nbsp;9th February 2001<br />
matrfaq_1.12.html: Version 1.12&nbsp;&nbsp;26th March 2001<br />
matrfaq_1.13.html: Version 1.13&nbsp;&nbsp;20th July 2001<br />
matrfaq_1.14.html: Version 1.14&nbsp;&nbsp;17th August 2001<br />
matrfaq_1.15.html: Version 1.15&nbsp;&nbsp;20th August 2001<br />
matrfaq_1.16.html: Version 1.16&nbsp;&nbsp;2nd October 2001<br />
matrfaq_1.17.html: Version 1.17&nbsp;&nbsp;30th November 2001<br />
matrfaq_1.18.html: Version 1.18&nbsp;&nbsp;27th January 2002<br />
matrfaq_1.19.html: Version 1.19&nbsp;&nbsp;20th March 2002<br />
<br />
matrfaq_1.20.html: Version 1.20&nbsp;&nbsp;31st January 2002<br />
matrfaq_1.21.html: Version 1.21&nbsp;&nbsp;30th November 2003<br />
 <br />
<br />
Please refrain from asking me math questions. I am only maintaining this FAQ<br />
and have very little knowledge about the subject. But, if you have a<br />
question that is not answered by this FAQ and later happen to find the<br />
answer and believe it to be relevant for this FAQ (or its readers), please<br />
send all relevant information, hopefully in a pre-digested form, to me to<br />
be included here. Thanks!<br />
If you prefer to appear as "anonymous" in the contributions list, let me<br />
know, otherwise I'll just put you down with whatever name I can gather from<br />
your email header.<br />
<br />
Introduction<br />
------------<br />
<a href='#I1'>I1.&nbsp;&nbsp;Important note relating to OpenGL and this document</a><br />
<a href='#I2'>I2.&nbsp;&nbsp;Important note with respect to normalized inputs</a><br />
<br />
Questions<br />
---------<br />
<br />
BASICS<br />
======<br />
&nbsp;<a href='#Q1'>Q1. What is a matrix?</a><br />
&nbsp;<a href='#Q2'>Q2. What is the order of a matrix?</a><br />
<br />
&nbsp;<a href='#Q3'>Q3. How do I represent a matrix using the C/C++ programming languages?</a><br />
&nbsp;<a href='#Q4'>Q4. What are the advantages of using matrices?</a><br />
&nbsp;<a href='#Q5'>Q5. How do matrices relate to coordinate systems?</a><br />
<br />
ARITHMETIC<br />
==========<br />
&nbsp;<a href='#Q6'>Q6. What is the identity matrix?</a><br />
&nbsp;<a href='#Q7'>Q7. What is the major diagonal matrix of a matrix?</a><br />
<br />
&nbsp;<a href='#Q8'>Q8. What is the transpose of a matrix?</a><br />
&nbsp;<a href='#Q9'>Q9. How do I add two matrices together?</a><br />
<a href='#Q10'>Q10. How do I subtract two matrices?</a></span><span style='font-family: Courier New'><br />
<a href='#Q11'>Q11. How do I multiply two matrices together?</a><br />
<a href='#Q12'>Q12. How do I square or raise a matrix to a power?</a><br />
<a href='#Q13'>Q13. How do I multiply one or more vectors by a matrix?</a><br />
<br />
DETERMINANTS AND INVERSES<br />
=========================<br />
<a href='#Q14'>Q14. What is the determinant of a matrix?</a><br />
<br />
<a href='#Q15'>Q15. How do I calculate the determinant of a matrix?</a><br />
<a href='#Q16'>Q16. What are Isotropic and Anisotropic matrices?</a><br />
<a href='#Q17'>Q17. What is the inverse of a matrix?</a><br />
<a href='#Q18'>Q18. How do I calculate the inverse of an arbitrary matrix?</a><br />
<a href='#Q19'>Q19. How do I calculate the inverse of an identity matrix?</a><br />
<a href='#Q20'>Q20. How do I calculate the inverse of a rotation matrix?</a><br />
<a href='#Q21'>Q21. How do I calculate the inverse of a matrix using Kramer's rule?</a><br />
<a href='#Q22'>Q22. How do I calculate the inverse of a 2x2 matrix?</a><br />
<a href='#Q23'>Q23. How do I calculate the inverse of a 3x3 matrix?</a><br />
<br />
<a href='#Q24'>Q24. How do I calculate the inverse of a 4x4 matrix?</a><br />
<a href='#Q25'>Q25. How do I calculate the inverse of a matrix using linear equations?</a><br />
<br />
TRANSFORMS<br />
==========<br />
<a href='#Q26'>Q26. What is a rotation matrix?</a><br />
<a href='#Q27'>Q27. How do rotation matrices relate to coordinate systems?</a><br />
<a href='#Q28'>Q28. How do I generate a rotation matrix in the X-axis?</a><br />
<a href='#Q29'>Q29. How do I generate a rotation matrix in the Y-axis?</a><br />
<a href='#Q30'>Q30. How do I generate a rotation matrix in the Z-axis?</a><br />
<a href='#Q31'>Q31. What are Euler angles?</a><br />
<br />
<a href='#Q32'>Q32. What are yaw, roll and pitch?</a><br />
<a href='#Q33'>Q33. How do I combine rotation matrices?</a><br />
<a href='#Q34'>Q34. What is Gimbal Lock?</a><br />
Q35. What is the correct way to combine rotation matrices?<br />
Q36. How do I generate a rotation matrix from Euler angles?<br />
Q37. How do I generate Euler angles from a rotation matrix?<br />
Q38. How do I generate a rotation matrix for a selected axis and angle?<br />
Q39. How do I generate a rotation matrix to map one vector onto another?<br />
Q40. How do I use matrices to convert between two coordinate systems?<br />
<br />
Q41. What is a translation matrix?<br />
Q42. What is a scaling matrix?<br />
Q43. What is a shearing matrix?<br />
Q44. How do I perform linear interpolation between two matrices?<br />
Q45. How do I perform cubic interpolation between four matrices?<br />
Q46. How can I render a matrix?<br />
<br />
QUATERNIONS<br />
===========<br />
Q47.&nbsp;&nbsp;What are quaternions?<br />
Q48.&nbsp;&nbsp;How do quaternions relate to 3D animation?<br />
<br />
Q49.&nbsp;&nbsp;How do I calculate the conjugate of a quaternion?<br />
Q50.&nbsp;&nbsp;How do I calculate the inverse of a quaternion?<br />
Q51.&nbsp;&nbsp;How do I calculate the magnitude of a quaternion?<br />
Q52.&nbsp;&nbsp;How do I normalise a quaternion?<br />
Q53.&nbsp;&nbsp;How do I multiply two quaternions together?<br />
Q54.&nbsp;&nbsp;How do I convert a quaternion to a rotation matrix?<br />
Q55.&nbsp;&nbsp;How do I convert a rotation matrix to a quaternion?<br />
Q56.&nbsp;&nbsp;How do I convert a rotation axis and angle to a quaternion?<br />
Q57.&nbsp;&nbsp;How do I convert a quaternion to a rotation axis and angle?<br />
<br />
Q58.&nbsp;&nbsp;How do I convert spherical rotation angles to a quaternion?<br />
Q59.&nbsp;&nbsp;How do I convert a quaternion to spherical rotation angles?<br />
Q60.&nbsp;&nbsp;How do I convert Euler rotation angles to a quaternion?<br />
Q61.&nbsp;&nbsp;How do I use quaternions to perform linear interpolation between matrices?<br />
Q62.&nbsp;&nbsp;How do I use quaternions to perform cubic interpolation between matrices?<br />
Q63.&nbsp;&nbsp;How do I use quaternions to rotate a vector?<br />
</span><br />
<span style='font-family: Courier New'>Introduction<br />
------------ <br />
<br />
<a name='I1'></a>I1. Important note relating to OpenGl and this document<br />
-------------------------------------------------------<br />
&nbsp;&nbsp;In this document (as in most math textbooks), all matrices are drawn<br />
&nbsp;&nbsp;in the standard mathematical manner.&nbsp;&nbsp;Unfortunately graphics libraries<br />
&nbsp;&nbsp;like IrisGL, OpenGL and SGI's Performer all represent them with the<br />
&nbsp;&nbsp;rows and columns swapped.<br />
&nbsp;&nbsp;Hence, in this document you will see (for example) a 4x4 Translation<br />
&nbsp;&nbsp;matrix represented as follows:<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| 1&nbsp;&nbsp;0&nbsp;&nbsp;0&nbsp;&nbsp;X |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| 0&nbsp;&nbsp;1&nbsp;&nbsp;0&nbsp;&nbsp;Y |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;M = |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| 0&nbsp;&nbsp;0&nbsp;&nbsp;1&nbsp;&nbsp;Z |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| 0&nbsp;&nbsp;0&nbsp;&nbsp;0&nbsp;&nbsp;1 |<br />
<br />
&nbsp;&nbsp;In Performer (for example) this would be populated as follows:<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;M[0][1] = M[0][2] = M[0][3] =<br />
&nbsp;&nbsp;&nbsp;&nbsp;M[1][0] = M[1][2] = M[1][3] =<br />
&nbsp;&nbsp;&nbsp;&nbsp;M[2][0] = M[2][1] = M[2][3] = 0 ;<br />
&nbsp;&nbsp;&nbsp;&nbsp;M[0][0] = M[1][1] = M[2][2] = m[3][3] = 1 ;<br />
&nbsp;&nbsp;&nbsp;&nbsp;M[3][0] = X ;<br />
&nbsp;&nbsp;&nbsp;&nbsp;M[3][1] = Y ;<br />
&nbsp;&nbsp;&nbsp;&nbsp;M[3][2] = Z ;<br />
<br />
&nbsp;&nbsp;ie, the matrix is stored like this:<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| M[0][0]&nbsp;&nbsp;M[1][0]&nbsp;&nbsp;M[2][0]&nbsp;&nbsp;M[3][0] |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| M[0][1]&nbsp;&nbsp;M[1][1]&nbsp;&nbsp;M[2][1]&nbsp;&nbsp;M[3][1] |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;M = |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| M[0][2]&nbsp;&nbsp;M[1][2]&nbsp;&nbsp;M[2][2]&nbsp;&nbsp;M[3][2] |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| M[0][3]&nbsp;&nbsp;M[1][3]&nbsp;&nbsp;M[2][3]&nbsp;&nbsp;M[3][3] |<br />
<br />
&nbsp;&nbsp;OpenGL uses a one-dimensional array to store matrices - but fortunately,<br />
&nbsp;&nbsp;the packing order results in the same layout of bytes in memory - so<br />
&nbsp;&nbsp;taking the address of a pfMatrix and casting it to a float* will allow<br />
&nbsp;&nbsp;you to pass it directly into routines like glLoadMatrixf.<br />
&nbsp;&nbsp;In the code snippets scattered throughout this document, a one-dimensional<br />
&nbsp;&nbsp;array is used to store a matrix. The ordering of the array elements is<br />
&nbsp;&nbsp;transposed with respect to OpenGL.<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;This Document&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OpenGL<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| 0&nbsp;&nbsp;1&nbsp;&nbsp;2&nbsp;&nbsp;3&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| 0&nbsp;&nbsp;4&nbsp;&nbsp;8&nbsp;&nbsp;12 |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| 4&nbsp;&nbsp;5&nbsp;&nbsp;6&nbsp;&nbsp;7&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| 1&nbsp;&nbsp;5&nbsp;&nbsp;9&nbsp;&nbsp;13 |<br />
&nbsp;&nbsp;&nbsp;&nbsp;M = |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;M = |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| 8&nbsp;&nbsp;9&nbsp;&nbsp;10 11 |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| 2&nbsp;&nbsp;6&nbsp;&nbsp;10 14 |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| 12 13 14 15 |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| 3&nbsp;&nbsp;7&nbsp;&nbsp;11 15 |<br />
<br />
<a name='I2'></a>I2. Important note with respect to normalized inputs<br />
----------------------------------------------------<br />
&nbsp;&nbsp;Note that most algorithms assume normalized inputs, such as vectors of<br />
&nbsp;&nbsp;union length, or matrices with normalized main diagonal etc. It is possible,<br />
&nbsp;&nbsp;and often enough the case, that algorithms (and the code snippets provided here)<br />
&nbsp;&nbsp;work correctly with arbitrary inputs, but it is usually considered bad practise<br />
&nbsp;&nbsp;(and you will pay in debugging time if you fail to observe this suggestion) to<br />
&nbsp;&nbsp;rely on this property.<br />
&nbsp;&nbsp;<br />
<br />
Answers<br />
-------<br />
<br />
BASICS<br />
======<br />
<br />
<a name='Q1'></a>Q1.&nbsp;&nbsp;What is a matrix?<br />
----------------------<br />
&nbsp;&nbsp;A matrix is a two dimensional array of numeric data, where each<br />
&nbsp;&nbsp;row or column consists of one or more numeric values.<br />
&nbsp;&nbsp;Arithmetic operations which can be performed with matrices include<br />
&nbsp;&nbsp;addition, subtraction, multiplication and division.<br />
&nbsp;&nbsp;The size of a matrix is defined in terms of the number of rows<br />
&nbsp;&nbsp;and columns.<br />
&nbsp;&nbsp;A matrix with M rows and N columns is defined as a MxN matrix.<br />
&nbsp;&nbsp;Individual elements of the matrix are referenced using two index<br />
&nbsp;&nbsp;values. Using mathematical notation these are usually assigned the<br />
&nbsp;&nbsp;variables 'i' and 'j'. The order is row first, column second<br />
&nbsp;&nbsp;For example, if a matrix M with order 4x4 exists, then the elements<br />
&nbsp;&nbsp;of the matrix are indexed by the following row:column pairs:<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| 00 01 02 03 |<br />
&nbsp;&nbsp;&nbsp;&nbsp;M = | 10 11 12 13 |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| 20 21 22 23 |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| 30 31 32 33 |<br />
<br />
&nbsp;&nbsp;The element at the top right of the matrix has i=0 and j=3<br />
&nbsp;&nbsp;This is referenced as follows:<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;M&nbsp;&nbsp;&nbsp;&nbsp;= M<br />
&nbsp;&nbsp;&nbsp;&nbsp; i,j&nbsp;&nbsp;&nbsp;&nbsp;0,3<br />
<br />
&nbsp;&nbsp;In computer animation, the most commonly used matrices have either<br />
&nbsp;&nbsp;2, 3 or 4 rows and columns. These are referred to as 2x2, 3x3 and 4x4<br />
&nbsp;&nbsp;matrices respectively.<br />
&nbsp;&nbsp;2x2 matrices are used to perform rotations, shears and other types<br />
&nbsp;&nbsp;of image processing. General purpose NxN matrices can be used to<br />
&nbsp;&nbsp;perform image processing functions such as convolution.<br />
&nbsp;&nbsp;3x3 matrices are used to perform low-budget 3D animation. Operations<br />
&nbsp;&nbsp;such as rotation and multiplication can be performed using matrix<br />
&nbsp;&nbsp;operations, but perspective depth projection is performed using<br />
&nbsp;&nbsp;standard optimised into pure divide operations.<br />
&nbsp;&nbsp;4x4 matrices are used to perform high-end 3D animation. Operations<br />
&nbsp;&nbsp;such as multiplication and perspective depth projection can be<br />
&nbsp;&nbsp;performed using matrix mathematics.<br />
&nbsp;&nbsp;<br />
<a name='Q2'></a>Q2.&nbsp;&nbsp;What is the "order" of a matrix?<br />
-------------------------------------<br />
&nbsp;&nbsp;The "order" of a matrix is another name for the size of the matrix.<br />
&nbsp;&nbsp;A matrix with M rows and N columns is said to have order MxN.<br />
&nbsp;&nbsp;<br />
<a name='Q3'></a>Q3.&nbsp;&nbsp;How do I represent a matrix using the C/C++ programming languages?<br />
-----------------------------------------------------------------------<br />
&nbsp;&nbsp;The simplest way of defining a matrix using the C/C++ programming<br />
&nbsp;&nbsp;languages is to make use of the "typedef" keyword. Both 3x3 and 4x4<br />
&nbsp;&nbsp;matrices may be defined in this way ie:<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;typedef float MATRIX3[9];<br />
&nbsp;&nbsp;&nbsp;&nbsp;typedef float MATRIX4[16];<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Since each type of matrix has dimensions 3x3 and 4x4, this requires<br />
&nbsp;&nbsp;9 and 16 data elements respectively.<br />
&nbsp;&nbsp;At first glance, the use of a single linear array of data values may<br />
&nbsp;&nbsp;seem counter-intuitive. The use of two dimensional arrays may seem<br />
&nbsp;&nbsp;more convenient ie.<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;typedef float MATRIX3[3][3];<br />
&nbsp;&nbsp;&nbsp;&nbsp;typedef float MATRIX4[4][4];<br />
<br />
&nbsp;&nbsp;However, the use of two reference systems for each matrix element<br />
&nbsp;&nbsp;very often leads to confusion. With mathemetics, the order is row<br />
&nbsp;&nbsp;first (i), column second (j) ie.<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; Mij<br />
<br />
&nbsp;&nbsp;Using C/C++, this becomes<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; matrix[j][i]<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; Using two dimensional arrays also incurs a CPU performance penalty in<br />
&nbsp;&nbsp;that C compilers will often make use of multiplication operations to<br />
&nbsp;&nbsp;resolve array index operations.<br />
&nbsp;&nbsp;So, it is more efficient to stick with linear arrays. However, one issue<br />
&nbsp;&nbsp;still remains to be resolved. How is an two dimensional matrix mapped<br />
&nbsp;&nbsp;onto a linear array? Since there are only two methods (row first/column<br />
&nbsp;&nbsp;second or column first/row column).<br />
&nbsp;&nbsp;The performance differences between the two are subtle. If all for-next<br />
&nbsp;&nbsp;loops are unravelled, then there is very little difference in the<br />
&nbsp;&nbsp;performance for operations such as matrix-matrix multiplication.<br />
&nbsp;&nbsp;Using the C/C++ programming languages the linear ordering of each<br />
&nbsp;&nbsp;matrix is as follows:<br />
<br />
&nbsp;&nbsp;mat[0][nbsp][nbsp]= M[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]mat[3][nbsp][nbsp]= M<br />
[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] 00[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] 03<br />
[nbsp][nbsp]mat[12] = M[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]mat[15] = M<br />
[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] 30[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] 33<br />
<br />
	|[nbsp][nbsp]0[nbsp][nbsp]1[nbsp][nbsp]2[nbsp][nbsp]3 |<br />
[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]|[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] |[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]| 0 1 2 |<br />
[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]|[nbsp][nbsp]4[nbsp][nbsp]5[nbsp][nbsp]6[nbsp][nbsp]7 |[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]|[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] |<br />
[nbsp][nbsp][nbsp][nbsp]M = |[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] |[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]M = | 3 4 5 |<br />
[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]|[nbsp][nbsp]8[nbsp][nbsp]9 10 11 |[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]|[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] |<br />
[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]|[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] |[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]| 6 7 8 |<br />
[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]| 12 13 14 15 |<br />
<br />
<a name='Q4'></a>Q4.[nbsp][nbsp]What are the advantages of using matrices?<br />
-----------------------------------------------<br />
[nbsp][nbsp]One of the first questions asked about the use of matrices in computer<br />
[nbsp][nbsp]animation is why they should be used at all in the first place.<br />
[nbsp][nbsp]Intuitively, it would appear that the overhead of for-next loops and<br />
[nbsp][nbsp]matrix multiplication would slow down an application.<br />
[nbsp][nbsp]Arguments that resolve these objections can be pointed out. These include<br />
[nbsp][nbsp]the use of CPU registers to handle loop counters on-board data caches<br />
[nbsp][nbsp]to optimise memory accesses.<br />
[nbsp][nbsp]Advantages can also be pointed out. By following a mathematical approach<br />
[nbsp][nbsp]to defining 3D algorithms, it is possible to predict and plan the<br />
[nbsp][nbsp]design of a 3D animation system. Such mathematical approaches allow<br />
[nbsp][nbsp]for the implementation of character animation, spline curves and inverse<br />
[nbsp][nbsp]kinematics.<br />
[nbsp][nbsp]However, one objection that frequently comes up is that it would be<br />
[nbsp][nbsp]quicker to just multiply each pair of coordinates by the rotation<br />
[nbsp][nbsp]coefficients for that axis, rather than perform a full vector-matrix<br />
[nbsp][nbsp]multiplication.<br />
[nbsp][nbsp]ie. Rotation in X transforms Y and Z<br />
[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]Rotation in Y transforms X and Z<br />
[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]Rotation in Z transforms X and Y<br />
[nbsp][nbsp]The argument to this goes as follows:<br />
[nbsp][nbsp]Given a vertex V = (x,y,z), rotation angles (A,B and C) and translation<br />
[nbsp][nbsp](D,E,F). A[nbsp][nbsp]the algorithm<br />
[nbsp][nbsp]is defined as follows:<br />
[nbsp][nbsp][nbsp][nbsp]---------------------------<br />
[nbsp][nbsp][nbsp][nbsp]sx = sin(A)[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] // Setup - only done once<br />
[nbsp][nbsp][nbsp][nbsp]cx = cos(A)<br />
[nbsp][nbsp][nbsp][nbsp]sy = sin(B)<br />
[nbsp][nbsp][nbsp][nbsp]cy = cos(B)<br />
[nbsp][nbsp][nbsp][nbsp]sz = sin&copy;<br />
[nbsp][nbsp][nbsp][nbsp]cz = cos&copy;<br />
[nbsp][nbsp][nbsp][nbsp]x1 =[nbsp][nbsp]x * cz +[nbsp][nbsp]y * sz[nbsp][nbsp]// Rotation of each vertex<br />
[nbsp][nbsp][nbsp][nbsp]y1 =[nbsp][nbsp]y * cz -[nbsp][nbsp]x * sz<br />
[nbsp][nbsp][nbsp][nbsp]z1 =[nbsp][nbsp]z<br />
[nbsp][nbsp][nbsp][nbsp]x2 = x1 * cy + z1 * sy<br />
[nbsp][nbsp][nbsp][nbsp]y2 = z1<br />
[nbsp][nbsp][nbsp][nbsp]z2 = z1 * cy - x1 * sy<br />
[nbsp][nbsp][nbsp][nbsp]x3 = x2<br />
[nbsp][nbsp][nbsp][nbsp]y3 = y2 * cx + z1 * sx<br />
[nbsp][nbsp][nbsp][nbsp]z3 = z2 * cx - x1 * sx<br />
[nbsp][nbsp][nbsp][nbsp]xr = x3 + D[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] // Translation of each vertex<br />
[nbsp][nbsp][nbsp][nbsp]yr = y3 + E<br />
[nbsp][nbsp][nbsp][nbsp]zr = z3 + F<br />
[nbsp][nbsp][nbsp][nbsp]---------------------------<br />
[nbsp][nbsp]Altogether, this algorithm will use the following amounts of processing<br />
[nbsp][nbsp]time:<br />
[nbsp][nbsp][nbsp][nbsp]Set-up[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] Per-vertex<br />
[nbsp][nbsp][nbsp][nbsp]-------------------------[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]------------------------<br />
[nbsp][nbsp][nbsp][nbsp]6 trigonometric functions<br />
[nbsp][nbsp][nbsp][nbsp]6 assignment operations.[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] 12 assignment<br />
[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] 12 multiplication<br />
[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]9 addition<br />
[nbsp][nbsp][nbsp][nbsp]-------------------------[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]------------------------<br />
[nbsp][nbsp]Assume that the same operations is being performed using matrix<br />
[nbsp][nbsp]multiplication.<br />
[nbsp][nbsp]With a 4x4 matrix, the procesing time is used as follows:<br />
[nbsp][nbsp][nbsp][nbsp]Set-up[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] Change[nbsp][nbsp][nbsp][nbsp]Per-vertex[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] Change<br />
[nbsp][nbsp][nbsp][nbsp]--------------------------[nbsp][nbsp] ------[nbsp][nbsp][nbsp][nbsp]------------------------ ------<br />
[nbsp][nbsp][nbsp][nbsp]6[nbsp][nbsp]trigonometric functions[nbsp][nbsp][nbsp][nbsp]0[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]0<br />
[nbsp][nbsp][nbsp][nbsp]18 assignment operation[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]-12[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]3[nbsp][nbsp]assignment[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] -9<br />
[nbsp][nbsp][nbsp][nbsp]12 multiplication[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]+12[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]9[nbsp][nbsp]multiplication[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] -3<br />
[nbsp][nbsp][nbsp][nbsp]6[nbsp][nbsp]subtraction[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] +6[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] 6[nbsp][nbsp]addition[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp] -3<br />
[nbsp][nbsp][nbsp][nbsp]--------------------------[nbsp][nbsp] ------[nbsp][nbsp][nbsp][nbsp]------------------------ ------<br />
[nbsp][nbsp]Comparing the two tables, it can be seen that setting up a rotation<br />
[nbsp][nbsp]matrix costs at least 12 multiplication calculations and an extra<br />
[nbsp][nbsp]18 assignment calls.<br />
[nbsp][nbsp]However, while this may seem extravagant, the savings come from<br />
[nbsp][nbsp]processing each vertex. Using matrix multiplication, the savings made<br />
[nbsp][nbsp]from processing just 4 vertices, will outweigh the additional set-up<br />
[nbsp][nbsp]cost.<br />
[nbsp][nbsp]<br />
<a name='Q5'></a>Q5.[nbsp][nbsp]How do matrices relate to coordinate systems?<br />
--------------------------------------------------<br />
[nbsp][nbsp]With either 3x3 or 4x4 rotation, translation or shearing matrices, there<br />
[nbsp][nbsp]is a simple relationship between each matrix and the resulting coordinate<br />
[nbsp][nbsp]system.<br />
[nbsp][nbsp]The first three columns of the matrix define the direction vector of the<br />
[nbsp][nbsp]X, Y and Z axii respectively.<br />
[nbsp][nbsp]If a 4x4 matrix is defined as:<br />
<br />
[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]| A B C D |<br />
[nbsp][nbsp][nbsp][nbsp]M = | E F G H |<br />
[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]| I J K L |<br />
[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]| M N O P |<br />
<br />
[nbsp][nbsp]Then the direction vector for each axis is as follows:<br />
<br />
[nbsp][nbsp][nbsp][nbsp] X-axis = [ A E I ]<br />
[nbsp][nbsp][nbsp][nbsp] Y-axis = [ B F J ]<br />
[nbsp][nbsp][nbsp][nbsp] Z-axis = [ C G K ]<br />
[nbsp][nbsp][nbsp][nbsp] <br />
ARITHMETIC<br />
==========<br />
<br />
<a name='Q6'></a>Q6.[nbsp][nbsp]What is the identity matrix?<br />
---------------------------------<br />
[nbsp][nbsp]The identity matrix is matrix in which has an identical number of rows<br />
[nbsp][nbsp]and columns. Also, all the elements in which i=j are set one. All others<br />
[nbsp][nbsp]are set to zero. For example a 4x4 identity matrix is as follows:<br />
<br />
[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]| 1 0 0 0 |<br />
[nbsp][nbsp][nbsp][nbsp]M = | 0 1 0 0 |<br />
[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]| 0 0 1 0 |<br />
[nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp][nbsp]| 0 0 0 1 |<br />
<br />
<a name='Q7'></a>Q7.[nbsp][nbsp]What is the major diagonal of a matrix?<br />
--------------------------------------------<br />
[nbsp][nbsp]The major diagonal of a matrix is the set of elements where the<br />
[nbsp][nbsp]row number is equal to the column number ie.<br />
<br />
[nbsp][nbsp][nbsp][nbsp]M[nbsp][nbsp] where i=j<br />
[nbsp][nbsp][nbsp][nbsp] ij<br />
<br />
[nbsp][nbsp]In the case of the identity matrix, only the elements on the major<br />
[nbsp][nbsp]diagonal are set to 1, while all others are set to 0.<br />
[nbsp][nbsp]<br />
</span>]]></description>
		<pubDate>Mon, 11 Feb 2002 11:46:49 +0000</pubDate>
		<guid isPermaLink="false">cc823b8f1c307b292c42b8d70c7a1714</guid>
	</item>
	<item>
		<title>The Physics of Racing, Part 18:</title>
		<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/the-physics-of-racing-part-18-r1627</link>
		<description>Download the article PDF via the attached resource file</description>
		<pubDate>Mon, 07 Jan 2002 15:28:22 +0000</pubDate>
		<guid isPermaLink="false">c28180798c5c9bc681b3b23b2b4ce398</guid>
	</item>
	<item>
		<title>The Physics of Racing, Part 17:</title>
		<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/the-physics-of-racing-part-17-r1626</link>
		<description>Download the article PDF via the attached resource file</description>
		<pubDate>Mon, 07 Jan 2002 15:26:58 +0000</pubDate>
		<guid isPermaLink="false">e27c71957d1e6c223e0d48a165da2ee1</guid>
	</item>
	<item>
		<title>The Physics of Racing, Part 16: RARS, A Simple...</title>
		<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/the-physics-of-racing-part-16-rars-a-simple-r1625</link>
		<description>Download the article PDF via the attached resource file</description>
		<pubDate>Mon, 07 Jan 2002 15:24:43 +0000</pubDate>
		<guid isPermaLink="false">cb2653f548f8709598e8b5156738cc51</guid>
	</item>
	<item>
		<title>The Physics of Racing, Part 15: Bumps In The Road</title>
		<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/the-physics-of-racing-part-15-bumps-in-the-road-r1624</link>
		<description>Download the PDF article via the attached resource file</description>
		<pubDate>Mon, 07 Jan 2002 15:24:27 +0000</pubDate>
		<guid isPermaLink="false">e1c1c18c55ad8fad38e352a95bf4192e</guid>
	</item>
	<item>
		<title>The Physics of Racing, Part 14: Why Smoothness?</title>
		<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/the-physics-of-racing-part-14-why-smoothness-r1623</link>
		<description>Download the PDF of this article via the attached resource file</description>
		<pubDate>Mon, 07 Jan 2002 15:24:04 +0000</pubDate>
		<guid isPermaLink="false">4abe8aa8f6fad818f0a9e15f657d75e9</guid>
	</item>
	<item>
		<title>The Physics of Racing, Part 13: Transients - Th...</title>
		<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/the-physics-of-racing-part-13-transients-th-r1622</link>
		<description>Download the PDF of this article via the attached resource file</description>
		<pubDate>Mon, 07 Jan 2002 15:23:25 +0000</pubDate>
		<guid isPermaLink="false">ffd3d44afe65e856eb4dc1c3fd40bc28</guid>
	</item>
	<item>
		<title>The Physics of Racing, Part 12: CyberCar, Every...</title>
		<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/the-physics-of-racing-part-12-cybercar-every-r1621</link>
		<description><![CDATA[<strong class='bbc'>physicist and member of<br />
No Bucks Racing Club<br />
<br />
 P.O. Box 662<br />
Burbank, CA 91503<br />
<br />
 ©Copyright 1991<br />
</strong><br />
 The cybernetic DWIM car is coming. DWIM stands for "Do What I Mean."<sup class='bbc'>1</sup> It is a commonplace term in the field of Human-machine Interfaces, and refers to systems that automatically interpret the user's intent from his or her inputs.<br />
<br />
 Cybernetics (or at least one aspect of it) is the science of unifying humans and machines. The objective of cybernetics is usually to amplify human capability with 'intelligent' machines, but sometimes the objective is the reverse. Most of the work in cybernetics has been under the aegis of defense, for building advanced tanks and aircraft. There is a modest amount of cybernetics in the automotive industry, as well. Anti-lock Braking (ABS), Acceleration Slip Reduction (ASR), Electronic Engine Management, and Automatic Traction Control (ATC) are cybernetic DWIM systems---of a kind---already in production. They all make 'corrections' on the driver's input based on an assumed intention. Steer-by-wire, Continuously Variable Transmissions (CVT), and active suspensions are on the immediate horizon. All these features are part of a distinct trend to automate the driving experience. This month, we take a break from hard physics to look at the better and the worse of increased automation, and we look at one concept of the ultimate result, CyberCar.<br />
<br />
 Among the research directions in cybernetics are advanced sensors for human inputs. One of the more incredible is a system that reads brain waves and figures out what a fighter pilot wants to do directly from patterns in the waves.<br />
<br />
 A major challenge in the fighter cockpit is information overload. Pilots have far too many instruments, displays, horns, buzzers, radio channels, and idiot lights competing for their attention. In stressful situations, such as high speed dogfights, the pilot's brain simply ignores inputs beyond its capacity, so the pilot may not hear a critical buzzer or see a critical warning light. In the 'intelligent cockpit,' however, the pilot <em class='bbc'>consciously</em> suppresses certain displays and auditory channels, thus reducing sensory clutter. By the same token, the intelligent cockpit must be able to override the pilot's choices and to put up critical displays and to sound alarms in emergencies. In the reduced clutter of the cockpit, then, it is much less likely that a pilot will miss critical information.<br />
<br />
 How does the pilot select the displays that he<sup class='bbc'>2</sup> wants to see? The pilot cannot afford the time to scroll through menus like those on a personal computer screen or hunt-and-peck on a button panel like that on an automatic bank teller machine.<br />
<br />
 There are already sensors that can read a pilot's brain waves and anticipate what he wants to look at next. Before the pilot even consciously knows that he wants to look at a weapon status display, for example, the cybernetic system can infer the intention from his brain waves and pop up the display. If he thinks it is time to look at the radar, before he could speak the command, the system reads his brain waves, pops up the radar display, and puts away the weapon status display.<br />
<br />
 How does it work? During a training phase, the system reads brain waves and gets explicit commands through a button panel. The system analyzes the brain waves, looking for certain unique features that it can associate with the intention (inferred from the command from the button panel) to see the radar display, and other unique features to associate with the intention to look at weapon status, and so on. The system must be trained individually for each pilot. Later, during operation, whenever the system sees the unique brain wave patterns, it 'knows' what the pilot wants to do.<br />
<br />
 The implications of technology like this for automobiles is amazing. Already, things like ABS are a kind of rudimentary cybernetics. When a driver stands all over the brake pedal, it is assumed that his intention is to stop, not to skid. The ABS system 'knows,' in a manner of speaking, the driver's intention and manages the physical system of the car to accomplish that goal. So, instead of being a mere mechanical linkage between your foot and the brakes, the brake pedal becomes a kind of intentional, DWIM control. Same goes for traction control and ASR. When the driver is on the gas, the system 'knows' that he wants to go forward, not to spin out or do doughnuts. In the case of TC, the system regulates the torque split to the drive wheels, whether there be two or four. In the case of ASR, the system backs off the throttle when there is wheel spin. Cybernetics again.<br />
<br />
 ABS, TC, and ASR exist now. What about the future? Consider steer-by-wire. CyberCar, the total cybernetic car, infers the driver's intended direction from the steering wheel position. It makes corrections to the actual direction of the steered wheels and to the throttle and brakes much more quickly and smoothly than any driver can do. Coupled with slip angle<sup class='bbc'>3</sup> sensors [1] and inertial guidance systems, perhaps based on miniaturized laser/fiber optic gyros (no moving parts), cybernetic steering, throttle, and brake controls will make up a formidable racing car that could drive a course in practically optimal fashion given only the driver's <em class='bbc'>desired</em> racing line.<br />
<br />
 In an understeering situation, when a car is not turning as much as desired, a common driver mistake is to turn the steering wheel more. That is a mistake, however, only because the driver is treating the steering wheel as an <em class='bbc'>intentional</em> control rather than the physical control it actually is. In CyberCar, however, the steering wheel <em class='bbc'>is</em> an intentional control. When the driver adds more lock in a corner, CyberCar 'knows' that the driver just wants more steering. Near the limits of adhesion, CyberCar knows that the appropriate <em class='bbc'>physical</em> reaction is, in fact, some weight transfer to the front, either by trailing throttle or a little braking, and a little less steering wheel lock. When the fronts hook up again, CyberCar can immediately get back into the throttle and add a little more steering lock, all the while tracking the driver's desires through the intentional steering wheel in the cockpit. Similarly, in an oversteer situation, when the driver gives opposite steering lock, CyberCar knows what to do. First, CyberCar determines whether the condition is trailing throttle oversteer (TTO) or power oversteer (PO). It can do this by monitoring tire loads through suspension deflection and engine torque output over time. In TTO, CyberCar adds a little throttle and countersteers. When the drive wheels hook up again, it modulates the throttle and dials in a little forward lock. In PO, CyberCar gently trails off the throttle and countersteers. All the while, CyberCar monitors driver's intentional inputs and the physical status of the car at the rate of several kilohertz (thousands of times per second).<br />
<br />
 The very terms 'understeer' and 'oversteer' carry cybernetic implication, for these are terms of intent. Understeer means the car is not steering as much as wanted, and oversteer means it is steering too much.<br />
<br />
 The above description is within current technology. What if we get <em class='bbc'>really</em> fantastic? How about doing away with the steering wheel altogether? CyberCar, version II, knows where the driver wants to go by watching his eyes, and it knows whether to accelerate or brake by watching brain waves. With Virtual Reality and teleoperation, the driver does not even have to be inside the car. The driver, wearing binocular video displays that control in-car cameras (or even synthetic computer graphics) <em class='bbc'>via</em> head position, sits in a virtual cockpit in the pits.<br />
<br />
 Now we must ask how much cybernetics is desirable? Autocrossing is, largely, a pure driver skill contest. Wheel-to-wheel racing adds racecraft---drafting, passing, deception, <em class='bbc'>etc.</em> ---to car control skills. Does it not seem that cybernetics eliminates driver skill as a factor by automating it? Is it not just another way for the 'haves' to beat the 'have-nots' by out-spending them? Drivers who do not have ABS have already complained that it gives their competition an unfair advantage. On the other hand, drivers who <em class='bbc'>do</em> have it have complained that it reduces their feel of control and their options while braking. I think they doth protest too much.<br />
<br />
 In the highest forms of racing, where money is literally no object, cybernetics is already playing a critical role. The clutch-less seven speed transmissions of the Williams/Renault team dominated the latter half of the 1991 Formula 1 season. But for some unattributable bad luck, they would have won the driver's championship and the constructor's cup. Carrol Smith, noted racing engineer, has been predicting for years that ABS will show up in Formula 1 as soon as systems can be made small and light enough [2]. It seems inevitable to me that cybernetic systems will give the unfair advantage to those teams most awash in money. However, autocrossers, club racers, and other grass roots competitors will be spared the expense, and the experience of being relieved of the enjoyment of car control, for at least another decade or two.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Acknowledgements</strong></span><br />
<br />
Thanks to Phil Ethier for giving me a few tips on car control that I might be able to teach to CyberCar and to Ginger Clark for bringing slip angle sensors to my attention.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>References</strong></span><br />
<br />
  <strong class='bbc'>1</strong> <br />
<blockquote>Patrick Borthelow, "Sensing Tire Slip Angles At the Racetrack," <em class='bbc'>Sensors</em>, September 1991.</blockquote> <strong class='bbc'>2</strong> <br />
<blockquote>Carrol Smith, <em class='bbc'>Engineer to Win</em>, <em class='bbc'>Prepare to Win</em>, <em class='bbc'>Build to Win</em>, from Classic Motorbooks, P.O. Box 1/RT021, Osceola, WI, 54020.  </blockquote><br />
<strong class='bbc'><br />
<span style='font-size: 18px;'>Footnotes</span></strong><br />
<br />
<sup class='bbc'>1</sup>   ...Mean." and the word play on 'dream' was too much to resist.<br />
<br />
 <sup class='bbc'>2</sup> ...he Everywhere, 'he' means 'he or she,' 'his' means 'his or her,' <em class='bbc'>etc.</em><br />
<br />
<sup class='bbc'>3</sup> ...angle Also known as <em class='bbc'>grip angle</em>; see Part 10 of this series.<br />
<br />
<hr class='bbc' /><br />
<em class='bbc'>converted by: rck@home.net <br />
Tue Feb 14 09:38:08 PST 1995  </em>]]></description>
		<pubDate>Mon, 07 Jan 2002 15:22:29 +0000</pubDate>
		<guid isPermaLink="false">c6243fd9fd572cc14d21d70eedf07715</guid>
	</item>
	<item>
		<title>The Physics of Racing, Part 11: Braking</title>
		<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/the-physics-of-racing-part-11-braking-r1620</link>
		<description><![CDATA[<strong class='bbc'>physicist and member of<br />
No Bucks Racing Club<br />
<br />
 P.O. Box 662<br />
Burbank, CA 91503<br />
<br />
 ©Copyright 1991<br />
</strong><br />
 I was recently helping to crew Mark Thornton's effort at the Silver State Grand Prix in Nevada. Mark had built a beautiful car with a theoretical top speed of over 200 miles per hour for the 92 mile time trial from Lund to Hiko. Mark had no experience driving at these speeds and asked me as a physicist if I could predict what braking at 200 mph would be like. This month I report on the back-of-the-envelope calculations on braking I did there in the field.<br />
<br />
 There are a couple of ways of looking at this problem. Brakes work by converting the energy of motion, <em class='bbc'>kinetic</em> energy, into the energy of heat in the brakes. Converting energy from useful forms (motion, electrical, chemical, <em class='bbc'>etc.</em>) to heat is generally called <em class='bbc'>dissipating </em>the energy, because there is no easy way to get it back from heat. If we assume that brakes dissipate energy at a constant rate, then we can immediately conclude that it takes four times as much time to stop from 200 mph as from 100 mph. The reason is that kinetic energy goes up as the square of the speed. Going at twice the speed means you have four times the kinetic energy because <a class='resized_img' rel='lightbox[4bde0cbbce1c469e839dd13d924f446b]' id='ipb-attach-url-3937-0-23018000-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3937" title="_7417_tex2html_wrap102.gif - Size: 109bytes, Downloads: 22"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-36529800-1309401654_thumb.gif" id='ipb-attach-img-3937-0-23018000-1330210057' style='width:43;height:13' class='attach' width="43" height="13" alt="Attached Image: _7417_tex2html_wrap102.gif" /></a>. The exact formula for kinetic energy is <a class='resized_img' rel='lightbox[4bde0cbbce1c469e839dd13d924f446b]' id='ipb-attach-url-3938-0-23030400-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3938" title="_7417_tex2html_wrap104.gif - Size: 119bytes, Downloads: 21"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-35441700-1309401666_thumb.gif" id='ipb-attach-img-3938-0-23030400-1330210057' style='width:35;height:19' class='attach' width="35" height="19" alt="Attached Image: _7417_tex2html_wrap104.gif" /></a>, where <a class='resized_img' rel='lightbox[4bde0cbbce1c469e839dd13d924f446b]' id='ipb-attach-url-3939-0-23040400-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3939" title="_7417_tex2html_wrap106.gif - Size: 62bytes, Downloads: 20"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-28841800-1309401702_thumb.gif" id='ipb-attach-img-3939-0-23040400-1330210057' style='width:14;height:7' class='attach' width="14" height="7" alt="Attached Image: _7417_tex2html_wrap106.gif" /></a> is the mass of an object and <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3940-0-23059800-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3940" title="_7417_tex2html_wrap112.gif - Size: 54bytes, Downloads: 24"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-46068000-1309401713_thumb.gif" id='ipb-attach-img-3940-0-23059800-1330210057' style='width:8;height:7' class='attach' width="8" height="7" alt="Attached Image: _7417_tex2html_wrap112.gif" /></a> is its speed. This was useful to Mark because braking from 100 mph was within the range of familiar driving experience.<br />
<br />
 That's pretty simple, but is it right? Do brakes dissipate energy at a constant rate? My guess as a physicist is 'probably not.' The efficiency of the braking process, dissipation, will depend on details of the friction interaction between the brake pads and disks. That interaction is likely to vary with temperature. Most brake pads are formulated to grip harder when hot, but only up to a point. Brake fade occurs when the pads and rotors are overheated. If you continue braking, heating the system even more, the brake fluid will eventually boil and there will be no braking at all. Brake fluid has the function of transmitting the pressure of your foot on the pedal to the brake pads by hydrostatics. If the fluid boils, then the pressure of your foot on the pedal goes into crushing little bubbles of gaseous brake fluid in the brake lines rather than into crushing the pads against the disks. Hence, no brakes.<br />
<br />
 We now arrive at the second way of looking at this problem. Let us assume that we have good brakes, so that the braking process is limited <em class='bbc'>not</em>by the interaction between the pads and disks but by the interaction between the tires and the ground. In other words, let us assume that our brakes are better than our tires. To keep things simple and back-of-the-envelope, assume that our tires will give us a constant deceleration of <a class='resized_img' rel='lightbox[4bde0cbbce1c469e839dd13d924f446b]' id='ipb-attach-url-3941-0-23089500-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3941" title="_7417_tex2html_wrap96.gif - Size: 314bytes, Downloads: 22"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-46832300-1309401738_thumb.gif" id='ipb-attach-img-3941-0-23089500-1330210057' style='width:131;height:34' class='attach' width="131" height="34" alt="Attached Image: _7417_tex2html_wrap96.gif" /></a> The time <a class='resized_img' rel='lightbox[4bde0cbbce1c469e839dd13d924f446b]' id='ipb-attach-url-3942-0-23099600-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3942" title="_7417_tex2html_wrap110.gif - Size: 54bytes, Downloads: 23"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-20125000-1309401750_thumb.gif" id='ipb-attach-img-3942-0-23099600-1330210057' style='width:5;height:11' class='attach' width="5" height="11" alt="Attached Image: _7417_tex2html_wrap110.gif" /></a> required for braking from speed <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3940-0-23068300-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3940" title="_7417_tex2html_wrap112.gif - Size: 54bytes, Downloads: 24"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-46068000-1309401713_thumb.gif" id='ipb-attach-img-3940-0-23068300-1330210057' style='width:8;height:7' class='attach' width="8" height="7" alt="Attached Image: _7417_tex2html_wrap112.gif" /></a> can be calculated from: <a class='resized_img' rel='lightbox[4bde0cbbce1c469e839dd13d924f446b]' id='ipb-attach-url-3943-0-23109600-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3943" title="_7417_tex2html_wrap97.gif - Size: 128bytes, Downloads: 24"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-32836500-1309401771_thumb.gif" id='ipb-attach-img-3943-0-23109600-1330210057' style='width:52;height:17' class='attach' width="52" height="17" alt="Attached Image: _7417_tex2html_wrap97.gif" /></a> which simply follows from the definition of constant acceleration. Given the time for braking, we can calculate the distance <a class='resized_img' rel='lightbox[4bde0cbbce1c469e839dd13d924f446b]' id='ipb-attach-url-3944-0-23119400-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3944" title="_7417_tex2html_wrap114.gif - Size: 55bytes, Downloads: 22"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-14657600-1309401785_thumb.gif" id='ipb-attach-img-3944-0-23119400-1330210057' style='width:8;height:7' class='attach' width="8" height="7" alt="Attached Image: _7417_tex2html_wrap114.gif" /></a>, again from the definitions of acceleration and velocity: <a class='resized_img' rel='lightbox[4bde0cbbce1c469e839dd13d924f446b]' id='ipb-attach-url-3945-0-23129200-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3945" title="_7417_tex2html_wrap98.gif - Size: 222bytes, Downloads: 28"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-02770800-1309401795_thumb.gif" id='ipb-attach-img-3945-0-23129200-1330210057' style='width:97;height:33' class='attach' width="97" height="33" alt="Attached Image: _7417_tex2html_wrap98.gif" /></a> Remembering to be careful about converting miles per hour to feet per second, we arrive at the numbers in Table 1.<br />
<br />
 <a class='resized_img' rel='lightbox[4bde0cbbce1c469e839dd13d924f446b]' id='ipb-attach-url-3946-0-23139000-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3946" title="_9497_table39.gif - Size: 5.52K, Downloads: 27"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-85706800-1309401811_thumb.gif" id='ipb-attach-img-3946-0-23139000-1330210057' style='width:250;height:116' class='attach' width="250" height="116" alt="Attached Image: _9497_table39.gif" /></a><br />
<br />
 We can immediately see from this table (and, indeed, from the formulas) that it is the <em class='bbc'>distance</em>, not the time, that varies as the square of the starting speed <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3940-0-23077600-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3940" title="_7417_tex2html_wrap112.gif - Size: 54bytes, Downloads: 24"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-46068000-1309401713_thumb.gif" id='ipb-attach-img-3940-0-23077600-1330210057' style='width:8;height:7' class='attach' width="8" height="7" alt="Attached Image: _7417_tex2html_wrap112.gif" /></a>. The braking time only goes up linearly with speed, that is, in simple proportion.<br />
<br />
 The numbers in the table are in the ballpark of the braking figures one reads in published tests of high performance cars, so I am inclined to believe that the second way of looking at the problem is the right way. In other words, the assumption that the brakes are better than the tires, so long as they are not overheated, is probably right, and the assumption that brakes dissipate energy at a constant rate is probably wrong because it leads to the conclusion that braking takes more time than it actually does.<br />
<br />
 My final advice to Mark was to leave <em class='bbc'>lots of room</em>. You can see from the table that stopping from 210 mph takes well over a quarter mile of very hard, precise, threshold braking at 1<a class='resized_img' rel='lightbox[4bde0cbbce1c469e839dd13d924f446b]' id='ipb-attach-url-3947-0-23149600-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3947" title="_7417_tex2html_wrap116.gif - Size: 70bytes, Downloads: 28"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-02791600-1309401843_thumb.gif" id='ipb-attach-img-3947-0-23149600-1330210057' style='width:12;height:13' class='attach' width="12" height="13" alt="Attached Image: _7417_tex2html_wrap116.gif" /></a>!<br />
<br />
<hr class='bbc' /><br />
<em class='bbc'>  converted by: rck@home.net<br />
Thu Sep 29 14:12:42 PDT 1994  </em>]]></description>
		<pubDate>Mon, 07 Jan 2002 15:21:59 +0000</pubDate>
		<guid isPermaLink="false">ec5972de2ccb6e92baa69e11c892ca33</guid>
	</item>
	<item>
		<title>The Physics of Racing, Part 10: Grip Angle</title>
		<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/the-physics-of-racing-part-10-grip-angle-r1619</link>
		<description><![CDATA[<strong class='bbc'>physicist and member of<br />
No Bucks Racing Club<br />
<br />
 P.O. Box 662<br />
Burbank, CA 91503<br />
<br />
 ©Copyright 1991<br />
</strong><br />
 In many ways, tire mechanics is an unpleasant topic. It is shrouded in uncertainty, controversy, and trade secrecy. Both theoretical and experimental studies are extremely difficult and expensive. It is probably the most uncontrollable variable in racing today. As such, it is the source of many highs and lows. An improvement in modeling or design, even if it is found by lucky accident, can lead to several years of domination by one tire company, as with BFGoodrich in autocrossing now. An unfortunate choice of tire by a competitor can lead to frustration and a disastrous hole in the budget.<br />
<br />
 This month, we investigate the physics of tire adhesion a little more deeply than in the past. In Parts 2, 4, and 7, we used the simple friction model given by <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3931-0-26092400-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3931" title="_9409_tex2html_wrap69.gif - Size: 153bytes, Downloads: 27"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-82429500-1309400745_thumb.gif" id='ipb-attach-img-3931-0-26092400-1330210057' style='width:61;height:16' class='attach' width="61" height="16" alt="Attached Image: _9409_tex2html_wrap69.gif" /></a>, where <a class='resized_img' rel='lightbox[02700d893cdb4276a344f4d0954db6f8]' id='ipb-attach-url-3932-0-26112100-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3932" title="_9409_tex2html_wrap63.gif - Size: 67bytes, Downloads: 24"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-43486200-1309400760_thumb.gif" id='ipb-attach-img-3932-0-26112100-1330210057' style='width:11;height:12' class='attach' width="11" height="12" alt="Attached Image: _9409_tex2html_wrap63.gif" /></a> is the maximum traction force available from a tire; <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3933-0-26132500-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3933" title="_9409_tex2html_wrap65.gif - Size: 62bytes, Downloads: 24"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-38416700-1309400781_thumb.gif" id='ipb-attach-img-3933-0-26132500-1330210057' style='width:9;height:11' class='attach' width="9" height="11" alt="Attached Image: _9409_tex2html_wrap65.gif" /></a>, assumed constant, is the coefficient of friction; and <a class='resized_img' rel='lightbox[02700d893cdb4276a344f4d0954db6f8]' id='ipb-attach-url-3934-0-26161000-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3934" title="_9409_tex2html_wrap67.gif - Size: 80bytes, Downloads: 24"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-23481300-1309401285_thumb.gif" id='ipb-attach-img-3934-0-26161000-1330210057' style='width:16;height:13' class='attach' width="16" height="13" alt="Attached Image: _9409_tex2html_wrap67.gif" /></a> is the instantaneous vertical load, or weight, on a tire. While this model is adequate for a rough, intuitive feel for tire behavior, it is grossly inadequate for quantitative use, say, for the computer program we began in Part 8 or for race car engineering and set up.<br />
<br />
 I am not a tire engineer. As always, I try to give a fresh look at any topic from a physicist's point of view. I may write things that are heretical or even wrong, especially on such a difficult topic as tire mechanics. I invite debate and corrections from those more knowledgeable than I. Such interaction is part of the fun of these articles for me.<br />
<br />
 I call this month's topic 'grip angle.' The grip angle is a quantity that captures, for many purposes, the complex and subtle mechanics of a tire. Most writers call this quantity 'slip angle.' I think this name is misleading because it suggests that a tire works by slipping and sliding. The truth is more complicated. Near maximum loads, the contact patch is partly gripping and partly slipping. The maximum net force a tire can yield occurs at the threshold where the tire is still gripping but is just about to give way to total slipping. Also, I have some difficulties with the analyses of slip angle in the literature. I will present these difficulties in these articles, unfortunately, probably without resolution. For these reasons, I give the quantity a new name.<br />
<br />
 A tire is an elastic or deformable body. It delivers forces to the car by stretching, compressing, and twisting. It is thus a very complex sort of spring with several different ways, or <em class='bbc'>modes</em>, of deformation. The hypothetical tire implied by <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3931-0-26100300-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3931" title="_9409_tex2html_wrap69.gif - Size: 153bytes, Downloads: 27"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-82429500-1309400745_thumb.gif" id='ipb-attach-img-3931-0-26100300-1330210057' style='width:61;height:16' class='attach' width="61" height="16" alt="Attached Image: _9409_tex2html_wrap69.gif" /></a> with constant <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3933-0-26140100-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3933" title="_9409_tex2html_wrap65.gif - Size: 62bytes, Downloads: 24"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-38416700-1309400781_thumb.gif" id='ipb-attach-img-3933-0-26140100-1330210057' style='width:9;height:11' class='attach' width="9" height="11" alt="Attached Image: _9409_tex2html_wrap65.gif" /></a> would be a non-elastic tire. Anyone who has driven hard tires on ice knows that non-elastic tires are basically uncontrollable, not just because <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3933-0-26146900-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3933" title="_9409_tex2html_wrap65.gif - Size: 62bytes, Downloads: 24"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-38416700-1309400781_thumb.gif" id='ipb-attach-img-3933-0-26146900-1330210057' style='width:9;height:11' class='attach' width="9" height="11" alt="Attached Image: _9409_tex2html_wrap65.gif" /></a> is small but because regular tires on ice do not twist appreciably.<br />
<br />
 The first and most obvious mode of deformation is radial. This deformation is along the radius of the tire, the line from the center to the tread. It is easily visible as a bulge in the sidewall near the contact patch, where the tire touches the ground. Thus, radial compression varies around the circumference.<br />
<br />
 Second is circumferential deformation. This is most easily visible as wrinkling of the sidewalls of drag tires. These tires are intentionally set up to deform dramatically in the circumferential direction.<br />
<br />
 Third is axial deformation. This is a deflection that tends to pull the tire off the (non-elastic) wheel or rim.<br />
<br />
 Last, and most important for cornering, is <em class='bbc'>torsional</em> deformation. This is a difference in axial deflection from the front to the back of the contact patch. Fundamentally, radial, circumferential, and axial deformation furnish a complete description of a tire. But it is very useful to consider the differences in these deflections around the circumference.<br />
<br />
 Let us examine exactly how a tire delivers cornering force to the car. We can get a good intuition into the physics with a pencil eraser. Get a block eraser, of the rectangular kind like 'Pink Pearl' or 'Magic Rub.' Stand it up on a table or desk and think of it as a little segment of the circumference of a tire. Think of the part touching the desk as the contact patch. Grab the top of the eraser and think of your hand as the wheel or rim, which is going to push, pull, and twist on the segment of tire circumference as we go along the following analysis.<br />
<br />
 Consider a car traveling at speed <a class='resized_img' rel='lightbox[02700d893cdb4276a344f4d0954db6f8]' id='ipb-attach-url-3936-0-26173900-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3936" title="_9409_tex2html_wrap75.gif - Size: 54bytes, Downloads: 25"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-09126000-1309401346_thumb.gif" id='ipb-attach-img-3936-0-26173900-1330210057' style='width:8;height:7' class='attach' width="8" height="7" alt="Attached Image: _9409_tex2html_wrap75.gif" /></a> in a straight line. Let us turn the steering wheel slightly to the right (twist the top of the eraser to the right). At the instant we begin turning, the rim (your hand on the eraser), at a circumferential position just behind the contact patch, pushes slightly leftward on the bead of the tire. Just ahead of the contact patch, likewise, the rim pulls the bead a little to the right. The push and pull together are called a <em class='bbc'>force couple</em>. This couple delivers a torsional, clockwise stress to the inner part of the tire carcass, near the bead. This stress is communicated to the contact patch by the elastic material in the sidewalls (or the main body of the eraser). As a result of turning the steering wheel, therefore, the rim twists the contact patch clockwise.<br />
<br />
 The car is still going straight, just for an instant. How are we going to explain a net rightward force from the road on the contact patch? This net force <em class='bbc'>must</em> be there, otherwise the tire and the car would continue in a straight line by Newton's First Law.<br />
<br />
 Consider the piece of road just under the contact patch at the instant the turn begins. The rubber particles on the left side of the patch are going a little bit faster with respect to the road than the rest of the car and the rubber particles on the right side of the patch are going a little bit slower than the rest of the car. As a result, the left side of the patch grips a little bit less than the right. The rubber particles on the left are more likely to slide and the ones on the right are more likely to grip. Thus, the left edge of the patch 'walks' a little bit upward, resulting in a net clockwise twisting motion of the patch. The torsional stress becomes a torsional motion. As this motion is repeated from one instant to the next, the tire (and the eraser-I hope you are still following along with the eraser) walks continuously to the right.<br />
<br />
 The better grip on the right hand side of the contact patch adds up to a net rightward force on the tire, which is transmitted back through the sidewall to the car. The chassis of the car begins to yaw to the right, changing the direction of the rear wheels. A torsional stress on the rear contact patches results, and the rear tires commence a similar 'walking' motion.<br />
<br />
 The wheel (your hand) is twisted more away from the direction of the car than is the contact patch. The angular difference between the direction the wheel is pointed and the direction the tire walks is the grip angle. All quantities of interest in tire mechanics-forces, friction coefficients, <em class='bbc'>etc.</em>, are conventionally expressed as functions of grip angle.<br />
<br />
 In steady state cornering, as in sweepers, an understeering car has larger grip angles in front, and an oversteering car has larger grip angles in the rear. How to control grip angles statically with wheel alignment and dynamically with four-wheel steering are subjects for later treatment.<br />
<br />
 The greater the grip angle, the larger the cornering force becomes, up to a point. After this point, greater grip angle delivers less force. This point is analogous to the idealized adhesive limit mentioned earlier in this series. Thus, a real tire behaves <em class='bbc'>qualitatively </em>like an ideal tire, which grips until the adhesive limit is exceeded and then slides. A real tire, however, grips gradually better as cornering force increases, and then grips gradually worse as the limit is exceeded.<br />
<br />
 The walking motion of the contact patch is not entirely smooth, or in other words, somewhat <em class='bbc'>discrete</em>. Individual blocks of rubber alternately grip and slide at high frequency, thousands of times per second. Under hard cornering, the rubber blocks vibrating on the road make an audible squealing sound. Beyond the adhesive limit, squealing becomes a lower frequency sound, 'squalling,' as the point of optimum efficiency of the walking process is bypassed.<br />
<br />
 There is a lot more to say on this subject, and I admit that my first attempts at a mathematical analysis of grip angle and contact patch mechanics got bogged down. However, I think we now have an intuitive, conceptual basis for better modeling in the future.<br />
<br />
 Speaking of the future, summarize briefly the past of and plans for the <em class='bbc'>Physics of Racing</em> series. The following overlapping threads run through it:<br />
<br />
  Tire Physics <br />
<blockquote>concerns adhesion, grip angle, and elastic modeling. This has been covered in Parts 2, 4, 7, and 10, and will be covered in several later parts.</blockquote> Car Dynamics <br />
<blockquote>concerns handling, suspension movement, and motion of a car around a course; has been covered in Parts 1, 4, 5, and 8 and will continue.</blockquote> Drive Line Physics <br />
<blockquote>concerns modeling of engine performance and acceleration. Has been covered in Parts 3, 6, and 9 and will also continue.</blockquote> Computer Simulation <br />
<blockquote>concerns the design of a working program that captures all the physics. This is the ultimate goal of the series. It was begun in Part 8 and will eventually dominate discussion. </blockquote> The following is a list of articles that have appeared so far:<br />
 <ul class='bbcol decimal'><li>Weight Transfer</li><li>Keeping Your Tires Stuck to the Ground</li><li>Basic Calculations</li><li>There is No Such Thing as Centrifugal Force</li><li>Introduction to the Racing Line</li><li>Speed and Horsepower</li><li>The Circle of Traction</li><li>Simulating Car Dynamics with a Computer Program</li><li>Straights</li><li>Grip Angle</li></ul> and the following is a <em class='bbc'>tentative </em>list of articles I have planned for the near future (naturally, this list is 'subject to change without notice'):<br />
<br />
  Springs and Dampers, <br />
<blockquote>presenting a detailed model of suspension movement (suggested by Bob Mosso)</blockquote> Transients, <br />
<blockquote>presenting the dynamics of entering and leaving corners, chicanes, and slaloms (this one suggested by Karen Babb) </blockquote>Stability, <br />
<blockquote>explaining why spins and other losses of control occur</blockquote> Smoothness, <br />
<blockquote>exploring what, exactly, is meant by smoothness </blockquote>Modeling Car Data <br />
<blockquote>in a computer program; in several articles</blockquote> Modeling Course Data <br />
<blockquote>in a computer program; also in several articles </blockquote> In practice, I try to keep the lengths of articles about the same, so if a topic is getting too long (and grip angle definitely did), I break it up in to several articles.<br />
<br />
<hr class='bbc' /><br />
<em class='bbc'>  converted by: rck@home.net<br />
Thu Sep 29 14:12:20 PDT 1994  </em>]]></description>
		<pubDate>Mon, 07 Jan 2002 15:21:29 +0000</pubDate>
		<guid isPermaLink="false">91e1fea50842570d5b4bd4bc2d23364b</guid>
	</item>
	<item>
		<title>The Physics of Racing, Part  9: Straights</title>
		<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/the-physics-of-racing-part-9-straights-r1618</link>
		<description><![CDATA[<strong class='bbc'>physicist and member of<br />
No Bucks Racing Club<br />
<br />
 P.O. Box 662<br />
Burbank, CA 91503<br />
<br />
 ©Copyright 1991<br />
</strong><br />
 We found in part 5 of this series, "Introduction to the Racing Line," that a driver can lose a shocking amount of time by taking a bad line in a corner. With a six-foot-wide car on a ten-foot-wide course, one can lose sixteen hundredths by 'blowing' a single right-angle turn. This month, we extend the analysis of the racing line by following our example car down a straight. It is often said that the most critical corner in a course is the one before the longest straight. Let's find out how critical it is. We calculate how much time it takes to go down a straight as a function of the speed entering the straight. The results, which are given at the end, are not terribly dramatic, but we make several, key improvements in the mathematical model that is under continuing development in this series of articles. These improvements will be used as we proceed designing the computer program begun in Part 8.<br />
<br />
 The mathematical model for traveling down a straight follows from Newton's second law:<br />
<br />
 <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3894-0-29681400-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3894" title="_8916_equation29.gif - Size: 276bytes, Downloads: 22"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-97184600-1309399573_thumb.gif" id='ipb-attach-img-3894-0-29681400-1330210057' style='width:250;height:10' class='attach' width="250" height="10" alt="Attached Image: _8916_equation29.gif" /></a><br />
<br />
 where <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3895-0-29704500-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3895" title="_8916_tex2html_wrap185.gif - Size: 67bytes, Downloads: 19"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-34009700-1309399585_thumb.gif" id='ipb-attach-img-3895-0-29704500-1330210057' style='width:11;height:12' class='attach' width="11" height="12" alt="Attached Image: _8916_tex2html_wrap185.gif" /></a> is the force on the car, <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3896-0-29745000-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3896" title="_8916_tex2html_wrap267.gif - Size: 62bytes, Downloads: 21"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-80587300-1309399664_thumb.gif" id='ipb-attach-img-3896-0-29745000-1330210057' style='width:14;height:7' class='attach' width="14" height="7" alt="Attached Image: _8916_tex2html_wrap267.gif" /></a> is the mass of the car, and <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3897-0-29777900-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3897" title="_8916_tex2html_wrap269.gif - Size: 55bytes, Downloads: 19"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-94873300-1309399764_thumb.gif" id='ipb-attach-img-3897-0-29777900-1330210057' style='width:8;height:7' class='attach' width="8" height="7" alt="Attached Image: _8916_tex2html_wrap269.gif" /></a> is the acceleration of the car. We want to solve this equation to get time as a function of distance down the straight. Basically, we want a table of numbers so that we can look up the time it takes to go any distance. We can build this table using accountants' columnar paper, or we can use the modern version of the columnar pad: the electronic spreadsheet program.<br />
<br />
 To solve equation 1 , we first invert it:<br />
<br />
 <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3898-0-29808900-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3898" title="_8916_equation33.gif - Size: 299bytes, Downloads: 21"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-50296400-1309399890_thumb.gif" id='ipb-attach-img-3898-0-29808900-1330210057' style='width:250;height:10' class='attach' width="250" height="10" alt="Attached Image: _8916_equation33.gif" /></a><br />
<br />
 Now <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3897-0-29785400-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3897" title="_8916_tex2html_wrap269.gif - Size: 55bytes, Downloads: 19"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-94873300-1309399764_thumb.gif" id='ipb-attach-img-3897-0-29785400-1330210057' style='width:8;height:7' class='attach' width="8" height="7" alt="Attached Image: _8916_tex2html_wrap269.gif" /></a>, the acceleration, is the rate of change of velocity with time. <em class='bbc'>Rate of change</em> is simply the ratio of a small change in velocity to a small change in time. Let us assume that we have filled in a column of times on our table. The times start with <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3899-0-29820900-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3899" title="_8916_tex2html_wrap193.gif - Size: 60bytes, Downloads: 22"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-67992800-1309399902_thumb.gif" id='ipb-attach-img-3899-0-29820900-1330210057' style='width:7;height:12' class='attach' width="7" height="12" alt="Attached Image: _8916_tex2html_wrap193.gif" /></a> and go up by the same, small amount, say <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3900-0-29832800-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3900" title="_8916_tex2html_wrap195.gif - Size: 97bytes, Downloads: 21"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-24470100-1309399916_thumb.gif" id='ipb-attach-img-3900-0-29832800-1330210057' style='width:28;height:12' class='attach' width="28" height="12" alt="Attached Image: _8916_tex2html_wrap195.gif" /></a> sec. Physicists call this small time the <em class='bbc'>integration step</em>. It is standard practice to begin solving an equation with a fixed integration step. There are sometimes good reasons to vary the integration step, but those reasons do not arise in this problem. Let us call the integration step <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3901-0-29844900-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3901" title="_8916_tex2html_wrap197.gif - Size: 79bytes, Downloads: 21"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-43800500-1309399929_thumb.gif" id='ipb-attach-img-3901-0-29844900-1330210057' style='width:19;height:12' class='attach' width="19" height="12" alt="Attached Image: _8916_tex2html_wrap197.gif" /></a>. If we call the time in the <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3902-0-29867200-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3902" title="_8916_tex2html_wrap199.gif - Size: 56bytes, Downloads: 20"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-64503500-1309399942_thumb.gif" id='ipb-attach-img-3902-0-29867200-1330210057' style='width:5;height:12' class='attach' width="5" height="12" alt="Attached Image: _8916_tex2html_wrap199.gif" /></a>-th row <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3903-0-29934200-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3903" title="_8916_tex2html_wrap201.gif - Size: 67bytes, Downloads: 19"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-31021300-1309400015_thumb.gif" id='ipb-attach-img-3903-0-29934200-1330210057' style='width:10;height:13' class='attach' width="10" height="13" alt="Attached Image: _8916_tex2html_wrap201.gif" /></a>, then for every row except the first,<br />
<br />
 <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3904-0-29947000-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3904" title="_8916_equation41.gif - Size: 412bytes, Downloads: 20"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-78445400-1309400046_thumb.gif" id='ipb-attach-img-3904-0-29947000-1330210057' style='width:250;height:10' class='attach' width="250" height="10" alt="Attached Image: _8916_equation41.gif" /></a><br />
<br />
 We label another column <em class='bbc'>velocity</em>, and we'll call the velocity in the <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3902-0-29876700-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3902" title="_8916_tex2html_wrap199.gif - Size: 56bytes, Downloads: 20"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-64503500-1309399942_thumb.gif" id='ipb-attach-img-3902-0-29876700-1330210057' style='width:5;height:12' class='attach' width="5" height="12" alt="Attached Image: _8916_tex2html_wrap199.gif" /></a>-th row <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3905-0-29971800-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3905" title="_8916_tex2html_wrap207.gif - Size: 64bytes, Downloads: 20"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-01850600-1309400071_thumb.gif" id='ipb-attach-img-3905-0-29971800-1330210057' style='width:12;height:9' class='attach' width="12" height="9" alt="Attached Image: _8916_tex2html_wrap207.gif" /></a>. For every row except the first, equation 2  becomes:<br />
<br />
 <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3906-0-30005500-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3906" title="_8916_equation48.gif - Size: 432bytes, Downloads: 20"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-59909100-1309400124_thumb.gif" id='ipb-attach-img-3906-0-30005500-1330210057' style='width:250;height:17' class='attach' width="250" height="17" alt="Attached Image: _8916_equation48.gif" /></a><br />
<br />
 We want to fill in velocities as we go down the columns, so we need to solve equation 4  for <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3905-0-29980000-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3905" title="_8916_tex2html_wrap207.gif - Size: 64bytes, Downloads: 20"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-01850600-1309400071_thumb.gif" id='ipb-attach-img-3905-0-29980000-1330210057' style='width:12;height:9' class='attach' width="12" height="9" alt="Attached Image: _8916_tex2html_wrap207.gif" /></a>. This will give us a formula for computing <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3905-0-29986700-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3905" title="_8916_tex2html_wrap207.gif - Size: 64bytes, Downloads: 20"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-01850600-1309400071_thumb.gif" id='ipb-attach-img-3905-0-29986700-1330210057' style='width:12;height:9' class='attach' width="12" height="9" alt="Attached Image: _8916_tex2html_wrap207.gif" /></a> given <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3907-0-30018500-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3907" title="_8916_tex2html_wrap211.gif - Size: 78bytes, Downloads: 20"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-04825200-1309400140_thumb.gif" id='ipb-attach-img-3907-0-30018500-1330210057' style='width:26;height:9' class='attach' width="26" height="9" alt="Attached Image: _8916_tex2html_wrap211.gif" /></a> for every row except the first. In the first row, we put the speed with which we enter the straight, which is an input to the problem. We get:<br />
<br />
 <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3908-0-30031600-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3908" title="_8916_equation55.gif - Size: 392bytes, Downloads: 19"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-43575600-1309400151_thumb.gif" id='ipb-attach-img-3908-0-30031600-1330210057' style='width:250;height:10' class='attach' width="250" height="10" alt="Attached Image: _8916_equation55.gif" /></a><br />
<br />
 We label another column <em class='bbc'>distance</em>, and we call the distance value in the <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3902-0-29883700-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3902" title="_8916_tex2html_wrap199.gif - Size: 56bytes, Downloads: 20"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-64503500-1309399942_thumb.gif" id='ipb-attach-img-3902-0-29883700-1330210057' style='width:5;height:12' class='attach' width="5" height="12" alt="Attached Image: _8916_tex2html_wrap199.gif" /></a>-th row <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3909-0-30056500-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3909" title="_8916_tex2html_wrap215.gif - Size: 66bytes, Downloads: 19"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-03988800-1309400163_thumb.gif" id='ipb-attach-img-3909-0-30056500-1330210057' style='width:13;height:9' class='attach' width="13" height="9" alt="Attached Image: _8916_tex2html_wrap215.gif" /></a>. Just as acceleration is the rate of change of velocity, so velocity is the rate of change of distance over time. Just as before, then, we may write:<br />
<br />
 <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3910-0-30080600-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3910" title="_8916_equation62.gif - Size: 396bytes, Downloads: 25"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-92113400-1309400206_thumb.gif" id='ipb-attach-img-3910-0-30080600-1330210057' style='width:250;height:17' class='attach' width="250" height="17" alt="Attached Image: _8916_equation62.gif" /></a><br />
<br />
 Solved for <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3909-0-30064300-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3909" title="_8916_tex2html_wrap215.gif - Size: 66bytes, Downloads: 19"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-03988800-1309400163_thumb.gif" id='ipb-attach-img-3909-0-30064300-1330210057' style='width:13;height:9' class='attach' width="13" height="9" alt="Attached Image: _8916_tex2html_wrap215.gif" /></a>, this is:<br />
<br />
 <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3911-0-30094200-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3911" title="_8916_equation66.gif - Size: 353bytes, Downloads: 26"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-19013300-1309400218_thumb.gif" id='ipb-attach-img-3911-0-30094200-1330210057' style='width:250;height:10' class='attach' width="250" height="10" alt="Attached Image: _8916_equation66.gif" /></a><br />
<br />
 Equation 7  gives us a formula for calculating the distance for any time given the previous distance and the velocity calculated by equation 5 . Physicists would say that we have a scheme for <em class='bbc'>integrating the equations of motion</em>.<br />
<br />
 A small detail is missing: what is the force, <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3895-0-29712700-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3895" title="_8916_tex2html_wrap185.gif - Size: 67bytes, Downloads: 19"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-34009700-1309399585_thumb.gif" id='ipb-attach-img-3895-0-29712700-1330210057' style='width:11;height:12' class='attach' width="11" height="12" alt="Attached Image: _8916_tex2html_wrap185.gif" /></a>? Everything to this point is <em class='bbc'>kinematic</em>. The real modeling starts now with formulas for calculating the force. For this, we will draw on all the previous articles in this series. Let's label another column <em class='bbc'>force</em>, and a few more with <em class='bbc'>drag</em>, <em class='bbc'>rolling resistance</em>, <em class='bbc'>engine torque</em>, <em class='bbc'>engine rpm</em>, <em class='bbc'>wheel rpm</em>, <em class='bbc'>trans gear ratio</em>, <em class='bbc'>drive ratio</em>, <em class='bbc'>wheel torque</em>, and <em class='bbc'>drive force</em>. As you can see, we are going to derive a fairly complete, if not accurate, model of accelerating down the straight. We need a few constants:<br />
<br />
 <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3912-0-30107900-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3912" title="_8916_tabular86.gif - Size: 3.84K, Downloads: 27"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-82252700-1309400237_thumb.gif" id='ipb-attach-img-3912-0-30107900-1330210057' style='width:250;height:154' class='attach' width="250" height="154" alt="Attached Image: _8916_tabular86.gif" /></a><br />
<br />
 and a few variables:<br />
<br />
 <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3913-0-30122400-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3913" title="_8916_tabular93.gif - Size: 2.72K, Downloads: 25"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-98458700-1309400248_thumb.gif" id='ipb-attach-img-3913-0-30122400-1330210057' style='width:250;height:114' class='attach' width="250" height="114" alt="Attached Image: _8916_tabular93.gif" /></a><br />
<br />
 All the example values are for a late model Corvette. <em class='bbc'>Slugs</em> are the English unit of mass, and 1 slug weighs about 32.1 lbs at sea level (another manifestation of <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3914-0-30136200-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3914" title="_8916_tex2html_wrap263.gif - Size: 118bytes, Downloads: 22"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-90787200-1309400259_thumb.gif" id='ipb-attach-img-3914-0-30136200-1330210057' style='width:56;height:12' class='attach' width="56" height="12" alt="Attached Image: _8916_tex2html_wrap263.gif" /></a>, with <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3895-0-29719600-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3895" title="_8916_tex2html_wrap185.gif - Size: 67bytes, Downloads: 19"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-34009700-1309399585_thumb.gif" id='ipb-attach-img-3895-0-29719600-1330210057' style='width:11;height:12' class='attach' width="11" height="12" alt="Attached Image: _8916_tex2html_wrap185.gif" /></a> in lbs, <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3896-0-29753700-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3896" title="_8916_tex2html_wrap267.gif - Size: 62bytes, Downloads: 21"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-80587300-1309399664_thumb.gif" id='ipb-attach-img-3896-0-29753700-1330210057' style='width:14;height:7' class='attach' width="14" height="7" alt="Attached Image: _8916_tex2html_wrap267.gif" /></a> in slugs, and <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3897-0-29792800-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3897" title="_8916_tex2html_wrap269.gif - Size: 55bytes, Downloads: 19"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-94873300-1309399764_thumb.gif" id='ipb-attach-img-3897-0-29792800-1330210057' style='width:8;height:7' class='attach' width="8" height="7" alt="Attached Image: _8916_tex2html_wrap269.gif" /></a> being the acceleration of gravity, 32.1 ft/sec<a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3915-0-30149700-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3915" title="_8916_tex2html_wrap271.gif - Size: 51bytes, Downloads: 25"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-83549100-1309400278_thumb.gif" id='ipb-attach-img-3915-0-30149700-1330210057' style='width:5;height:7' class='attach' width="5" height="7" alt="Attached Image: _8916_tex2html_wrap271.gif" /></a>).<br />
<br />
 The most basic modeling equation is that the force we can use for forward acceleration is the propelling force transmitted through the wheels minus drag and rolling resistance:<br />
<br />
 <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3916-0-30163600-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3916" title="_8916_equation100.gif - Size: 372bytes, Downloads: 24"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-44187500-1309400291_thumb.gif" id='ipb-attach-img-3916-0-30163600-1330210057' style='width:250;height:10' class='attach' width="250" height="10" alt="Attached Image: _8916_equation100.gif" /></a><br />
<br />
 The force of drag we get from Part 6:<br />
<br />
 <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3917-0-30178900-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3917" title="_8916_equation102.gif - Size: 468bytes, Downloads: 24"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-81084800-1309400303_thumb.gif" id='ipb-attach-img-3917-0-30178900-1330210057' style='width:250;height:19' class='attach' width="250" height="19" alt="Attached Image: _8916_equation102.gif" /></a><br />
<br />
 Note that to calculate the force at step <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3902-0-29890900-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3902" title="_8916_tex2html_wrap199.gif - Size: 56bytes, Downloads: 20"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-64503500-1309399942_thumb.gif" id='ipb-attach-img-3902-0-29890900-1330210057' style='width:5;height:12' class='attach' width="5" height="12" alt="Attached Image: _8916_tex2html_wrap199.gif" /></a>, we can use the velocity at step <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3902-0-29897400-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3902" title="_8916_tex2html_wrap199.gif - Size: 56bytes, Downloads: 20"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-64503500-1309399942_thumb.gif" id='ipb-attach-img-3902-0-29897400-1330210057' style='width:5;height:12' class='attach' width="5" height="12" alt="Attached Image: _8916_tex2html_wrap199.gif" /></a>. This force goes into calculating the acceleration at step <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3902-0-29903900-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3902" title="_8916_tex2html_wrap199.gif - Size: 56bytes, Downloads: 20"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-64503500-1309399942_thumb.gif" id='ipb-attach-img-3902-0-29903900-1330210057' style='width:5;height:12' class='attach' width="5" height="12" alt="Attached Image: _8916_tex2html_wrap199.gif" /></a>, which is used to calculate the velocity and distance at step <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3918-0-30193000-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3918" title="_8916_tex2html_wrap279.gif - Size: 95bytes, Downloads: 24"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-58248200-1309400318_thumb.gif" id='ipb-attach-img-3918-0-30193000-1330210057' style='width:33;height:14' class='attach' width="33" height="14" alt="Attached Image: _8916_tex2html_wrap279.gif" /></a> by equations 5  and 7 . Those two equations represent the only 'backward references' we need. Thus, the only inputs to the integration are the initial distance, 0, and the entrance velocity, <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3919-0-30206900-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3919" title="_8916_tex2html_wrap281.gif - Size: 66bytes, Downloads: 25"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-06231200-1309400344_thumb.gif" id='ipb-attach-img-3919-0-30206900-1330210057' style='width:14;height:9' class='attach' width="14" height="9" alt="Attached Image: _8916_tex2html_wrap281.gif" /></a>.<br />
<br />
 The rolling resistance is approximately proportional to the velocity:<br />
<br />
 <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3920-0-30220500-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3920" title="_8916_equation108.gif - Size: 402bytes, Downloads: 16"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-68688700-1309400354_thumb.gif" id='ipb-attach-img-3920-0-30220500-1330210057' style='width:250;height:10' class='attach' width="250" height="10" alt="Attached Image: _8916_equation108.gif" /></a><br />
<br />
 This approximation is probably the weakest one in the model. I derived it by noting from a Corvette book that 8.2 hp were needed to overcome rolling resistance at 55 mph. I have nothing else but intuition to go on for this equation, so take it with a grain of salt.<br />
<br />
 Finally, we must calculate the forward force delivered by the ground to the car by reaction to the rearward force delivered to the ground <em class='bbc'>via</em> the engine and drive train:<br />
<br />
 <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3921-0-30234300-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3921" title="_8916_equation110.gif - Size: 506bytes, Downloads: 23"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-30670800-1309400365_thumb.gif" id='ipb-attach-img-3921-0-30234300-1330210057' style='width:250;height:22' class='attach' width="250" height="22" alt="Attached Image: _8916_equation110.gif" /></a><br />
<br />
 This equation simply states that we take the engine torque multiplied by the rear axle ratio and the transmission drive ratio in the <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3922-0-30248300-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3922" title="_8916_tex2html_wrap283.gif - Size: 62bytes, Downloads: 20"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-78206100-1309400378_thumb.gif" id='ipb-attach-img-3922-0-30248300-1330210057' style='width:8;height:12' class='attach' width="8" height="12" alt="Attached Image: _8916_tex2html_wrap283.gif" /></a>-th gear, which is the torque at the drive wheels, <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3923-0-30262300-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3923" title="_8916_tex2html_wrap285.gif - Size: 91bytes, Downloads: 21"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-71356900-1309400391_thumb.gif" id='ipb-attach-img-3923-0-30262300-1330210057' style='width:22;height:14' class='attach' width="22" height="14" alt="Attached Image: _8916_tex2html_wrap285.gif" /></a>, and divide it by the radius of the wheel, which is half the diameter of the wheel, <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3924-0-30277900-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3924" title="_8916_tex2html_wrap287.gif - Size: 62bytes, Downloads: 22"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-13062400-1309400403_thumb.gif" id='ipb-attach-img-3924-0-30277900-1330210057' style='width:9;height:12' class='attach' width="9" height="12" alt="Attached Image: _8916_tex2html_wrap287.gif" /></a>.<br />
<br />
 To calculate the forward force, we must decide what gear to be in. The logic we use to do this is the following: from the velocity, we can calculate the wheel rpm:<br />
<br />
 <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3925-0-30292300-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3925" title="_8916_equation115.gif - Size: 486bytes, Downloads: 22"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-16333700-1309400416_thumb.gif" id='ipb-attach-img-3925-0-30292300-1330210057' style='width:250;height:17' class='attach' width="250" height="17" alt="Attached Image: _8916_equation115.gif" /></a><br />
<br />
 From this, we know the engine rpm:<br />
<br />
 <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3926-0-30306800-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3926" title="_8916_equation121.gif - Size: 351bytes, Downloads: 21"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-98810600-1309400430_thumb.gif" id='ipb-attach-img-3926-0-30306800-1330210057' style='width:250;height:10' class='attach' width="250" height="10" alt="Attached Image: _8916_equation121.gif" /></a><br />
<br />
 At each step of integration, we look at the current engine rpm and ask "is it past the torque peak of the engine?" If so, we shift to the next highest gear, if possible. Somewhat arbitrarily, we assume that the torque peak is at 4200 rpm. To keep things simple, we also make the optimistic assumption that the engine puts out a constant torque of 330 ft-lbs. To make the model more realistic, we need merely look up a torque curve for our engine, usually expressed as a function of rpm, and read the torque off the curve at each step of the integration. The current approximation is not terrible however; it merely gives us artificially good times and speeds. Another important improvement on the logic would be to check whether the wheels are spinning, <em class='bbc'>i.e.</em>, that acceleration is less than about <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3927-0-30321100-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3927" title="_8916_tex2html_wrap289.gif - Size: 97bytes, Downloads: 18"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-44087700-1309400450_thumb.gif" id='ipb-attach-img-3927-0-30321100-1330210057' style='width:20;height:19' class='attach' width="20" height="19" alt="Attached Image: _8916_tex2html_wrap289.gif" /></a>, and to 'lift off the gas' in that case.<br />
<br />
 We have all the ingredients necessary to calculate how much time it takes to cover a straight given an initial speed. You can imagine doing the calculations outlined above by hand on columnar paper, or you can check my results (below) by programming them up in a spreadsheet program like Lotus 1-2-3 or Microsoft Excel. Eventually, of course, if you follow this series, you will see these equations again as we write our Scheme program for simulating car dynamics. Integrating the equations of motion by hand will take you many hours. Using a spreadsheet will take several hours, too, but many less than integrating by hand.<br />
<br />
 To illustrate the process, we show below the times and exit speeds for a 200 foot straight, which is a fairly long one in autocrossing, and a 500 foot straight, which you should only see on race tracks. We show times and speeds for a variety of speeds entering the straight from 25 to 50 mph in Table 1 . The results are also summarized in the two plots, Figures 1  and 2 .<br />
<br />
 <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3928-0-30335400-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3928" title="_8916_table128.gif - Size: 6.47K, Downloads: 20"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-67992300-1309400489_thumb.gif" id='ipb-attach-img-3928-0-30335400-1330210057' style='width:250;height:182' class='attach' width="250" height="182" alt="Attached Image: _8916_table128.gif" /></a><br />
<br />
 <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3929-0-30350000-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3929" title="time.gif - Size: 3.76K, Downloads: 21"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-82374900-1309400499_thumb.gif" id='ipb-attach-img-3929-0-30350000-1330210057' style='width:250;height:180' class='attach' width="250" height="180" alt="Attached Image: time.gif" /></a><br />
<br />
 <a class='resized_img' rel='lightbox[17ee584b5680408188a5eb6d7bbdef50]' id='ipb-attach-url-3930-0-30364800-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3930" title="speed.gif - Size: 3.99K, Downloads: 20"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-38214600-1309400527_thumb.gif" id='ipb-attach-img-3930-0-30364800-1330210057' style='width:250;height:181' class='attach' width="250" height="181" alt="Attached Image: speed.gif" /></a><br />
<br />
 The notable facts arising in this analysis are the following. The time difference resulting from entering the 200' straight at 27 mph rather than 25 mph is about 6 hundredths. Frankly, not as much as I expected. The time difference between entering at 31 mph over 25 mph is about 2 tenths, again less than I would have guessed. The speed difference at the end of the straight between entering at 25 mph and 50 mph is only 8 mph, a result of the fact that the car labors against friction and higher gear ratios at high speeds. It is also a consequence of the fact that there is so much torque available at 25 mph in low gear that the car can almost make up the difference over the relatively short 200' straight. In fact, on the longer 500' straight, the exit speed difference between entering at 25 mph and 50 mph is not even 5 mph, though the time difference is nearly a full second.<br />
<br />
 This analysis would most likely be much more dramatic for a car with less torque than a Corvette. In a Corvette, with 330 ft-lbs of torque on tap, the penalty for entering a straight slower than necessary is not so great as it would be in a more typical car, where recovering speed lost through timidity or bad cornering is much more difficult.<br />
<br />
 Again, the analysis can be improved by using a real torque curve and by checking whether the wheels are spinning in lower gears.<br />
<br />
<hr class='bbc' /><br />
<em class='bbc'>  converted by: rck@home.net<br />
Thu Sep 29 14:11:00 PDT 1994  </em>]]></description>
		<pubDate>Mon, 07 Jan 2002 15:21:00 +0000</pubDate>
		<guid isPermaLink="false">de4994a3a1ec0331d2c59d37631a4776</guid>
	</item>
	<item>
		<title>The Physics of Racing, Part  8: Simulating Car...</title>
		<link>http://www.gamedev.net/page/resources/_/technical/math-and-physics/the-physics-of-racing-part-8-simulating-car-r1617</link>
		<description><![CDATA[<strong class='bbc'>physicist and member of<br />
No Bucks Racing Club<br />
<br />
 P.O. Box 662<br />
Burbank, CA 91503<br />
<br />
 ©Copyright 1991<br />
</strong><br />
 This month, we begin writing a computer program to simulate the physics of racing. Such a program is quite an ambitious one. A simple racing video game, such as "Pole Position," probably took an expert programmer several months to write. A big, realistic game like "Hard Drivin" probably took three to five people more than a year to create. The point is that the topic of writing a racing simulation is one that we will have to revisit many times in these articles, assuming your patience holds out. There are many `just physics' topics still to cover too, such as springs and dampers, transients, and thermodynamics. Your author hopes you will find the computer programming topic an enjoyable sideline and is interested, as always, in your feedback.<br />
<br />
 We will use a computer programming language called Scheme. You have probably encountered BASIC, a language that is very common on personal computers. Scheme is like BASIC in that it is <em class='bbc'>interactive</em>. An interactive computer language is the right kind to use when inventing a program as you go along. Scheme is better than BASIC, however, because it is a good deal simpler and also more powerful and modern. Scheme is available for most PCs at very modest cost (MIT Press has published a book and diskette with Scheme for IBM compatibles for about $40; I have a free version for Macintoshes). I will explain everything we need to know about Scheme as we go along. Although I assume little or no knowledge about computer programming on your part, we will ultimately learn some very advanced things.<br />
<br />
 The first thing we need to do is create a <em class='bbc'>data structure</em> that contains the mathematical state of the car at any time. This data structure is a block of computer memory. As simulated time progresses, mathematical operations performed on the data structure simulate the physics. We create a new instance of this data structure by typing the following on the computer keyboard at the Scheme prompt:<br />
<br />
<pre class='prettyprint'>(new-race-car)</pre>This is an example of an <em class='bbc'>exp<b></b>ressi&#111;n</em>. The exp<b></b>ressi&#111;n includes the parentheses. When it is typed in, it is <span style='font-family: Courier New'>evaluated</span> immediately. When we say that Scheme is an interactive programming language, we mean that it evaluates exp<b></b>ressi&#111;ns immediately. Later on, I show how we <em class='bbc'>define</em> this exp<b></b>ressi&#111;n. It is by defining such exp<b></b>ressi&#111;ns that we write our simulation program.<br />
<br />
 Everything in Scheme is an exp<b></b>ressi&#111;n (that's why Scheme is simple). Every exp<b></b>ressi&#111;n has a value. The value of the exp<b></b>ressi&#111;n above is the new data structure itself. We need to give the new data structure a name so we can refer to it in later exp<b></b>ressi&#111;ns:<br />
<br />
<pre class='prettyprint'>(define car-161 (new-race-car))</pre>This exp<b></b>ressi&#111;n illustrates two Scheme features. The first is that exp<b></b>ressi&#111;ns can contain sub-exp<b></b>ressi&#111;ns inside them. The inside exp<b></b>ressi&#111;ns are called <em class='bbc'>nested</em>. Scheme figures out which exp<b></b>ressi&#111;ns are nested by counting parentheses. It is partly by nesting exp<b></b>ressi&#111;ns that we build up the complexity needed to simulate racing. The second feature is the use of the special Scheme word <span style='font-family: Courier New'>define</span>. This causes the immediately following word to become a stand-in synonym for the value just after. The technical name for such a stand-in synonym is <em class='bbc'>variable</em>. Thus, the exp<b></b>ressi&#111;n <span style='font-family: Courier New'>car-161</span>, wherever it appears after the <span style='font-family: Courier New'>define</span> exp<b></b>ressi&#111;n, is a synonym for the data structure created by the nested exp<b></b>ressi&#111;n <span style='font-family: Courier New'>(new-race-car)</span>.<br />
<br />
 We will have another data structure (with the same format) for <span style='font-family: Courier New'>car-240</span>, another for <span style='font-family: Courier New'>car-70</span>, and so on. We get to choose these names to be almost anything we like . So, we would create all the data structures for the cars in our simulation with exp<b></b>ressi&#111;ns like the following:<br />
<br />
<pre class='prettyprint'>(define car-161 (new-race-car)) <br />(define car-240 (new-race-car))<br />(define car-70  (new-race-car))</pre>The state of a race car consists of several numbers describing the physics of the car. First, there is the car's position. Imagine a map of the course. Every position on the map is denoted by a pair of coordinates, <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3888-0-33955400-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3888" title="_8820_tex2html_wrap88.gif - Size: 55bytes, Downloads: 25"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-61658000-1309398483_thumb.gif" id='ipb-attach-img-3888-0-33955400-1330210057' style='width:8;height:7' class='attach' width="8" height="7" alt="Attached Image: _8820_tex2html_wrap88.gif" /></a> and <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3889-0-34016500-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3889" title="_8820_tex2html_wrap86.gif - Size: 59bytes, Downloads: 25"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-39189700-1309398544_thumb.gif" id='ipb-attach-img-3889-0-34016500-1330210057' style='width:8;height:11' class='attach' width="8" height="11" alt="Attached Image: _8820_tex2html_wrap86.gif" /></a>. For elevation changes, we add a height coordinate, <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3890-0-34055300-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3890" title="_8820_tex2html_wrap76.gif - Size: 55bytes, Downloads: 21"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-13018400-1309398687_thumb.gif" id='ipb-attach-img-3890-0-34055300-1330210057' style='width:8;height:7' class='attach' width="8" height="7" alt="Attached Image: _8820_tex2html_wrap76.gif" /></a>. The position of the center of gravity of a car at any time is denoted with exp<b></b>ressi&#111;ns such as the following:<br />
<br />
<pre class='prettyprint'>(race-car-x car-161)<br />(race-car-y car-161)<br />(race-car-z car-161)</pre>Each of these exp<b></b>ressi&#111;ns performs <em class='bbc'>data retrieval</em> on the data structure <span style='font-family: Courier New'>car-161</span>. The value of the first exp<b></b>ressi&#111;n is the <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3888-0-33963400-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3888" title="_8820_tex2html_wrap88.gif - Size: 55bytes, Downloads: 25"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-61658000-1309398483_thumb.gif" id='ipb-attach-img-3888-0-33963400-1330210057' style='width:8;height:7' class='attach' width="8" height="7" alt="Attached Image: _8820_tex2html_wrap88.gif" /></a> coordinate of the car, <em class='bbc'>etc.</em> Normally, when running the Scheme interpreter, typing an exp<b></b>ressi&#111;n simply causes its value to be printed, so we would see the car position coordinates printed out as we typed. We could also store these positions in another block of computer memory for further manipulations, or we could specify various mathematical operations to be performed on them.<br />
<br />
 The next pieces of state information are the three components of the car's velocity. When the car is going in any direction on the course, we can ask "how fast is it going in the <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3888-0-33971900-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3888" title="_8820_tex2html_wrap88.gif - Size: 55bytes, Downloads: 25"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-61658000-1309398483_thumb.gif" id='ipb-attach-img-3888-0-33971900-1330210057' style='width:8;height:7' class='attach' width="8" height="7" alt="Attached Image: _8820_tex2html_wrap88.gif" /></a> direction, ignoring its motion in the <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3889-0-34024300-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3889" title="_8820_tex2html_wrap86.gif - Size: 59bytes, Downloads: 25"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-39189700-1309398544_thumb.gif" id='ipb-attach-img-3889-0-34024300-1330210057' style='width:8;height:11' class='attach' width="8" height="11" alt="Attached Image: _8820_tex2html_wrap86.gif" /></a> and <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3890-0-34063100-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3890" title="_8820_tex2html_wrap76.gif - Size: 55bytes, Downloads: 21"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-13018400-1309398687_thumb.gif" id='ipb-attach-img-3890-0-34063100-1330210057' style='width:8;height:7' class='attach' width="8" height="7" alt="Attached Image: _8820_tex2html_wrap76.gif" /></a> directions?" Similarly, we want to know how fast it is going in the <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3889-0-34031100-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3889" title="_8820_tex2html_wrap86.gif - Size: 59bytes, Downloads: 25"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-39189700-1309398544_thumb.gif" id='ipb-attach-img-3889-0-34031100-1330210057' style='width:8;height:11' class='attach' width="8" height="11" alt="Attached Image: _8820_tex2html_wrap86.gif" /></a> direction, ignoring the <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3888-0-33979700-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3888" title="_8820_tex2html_wrap88.gif - Size: 55bytes, Downloads: 25"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-61658000-1309398483_thumb.gif" id='ipb-attach-img-3888-0-33979700-1330210057' style='width:8;height:7' class='attach' width="8" height="7" alt="Attached Image: _8820_tex2html_wrap88.gif" /></a> and <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3890-0-34070000-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3890" title="_8820_tex2html_wrap76.gif - Size: 55bytes, Downloads: 21"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-13018400-1309398687_thumb.gif" id='ipb-attach-img-3890-0-34070000-1330210057' style='width:8;height:7' class='attach' width="8" height="7" alt="Attached Image: _8820_tex2html_wrap76.gif" /></a> directions, and so on. Decomposing an object's velocity into separate components along the principal coordinate directions is necessary for computation. The technique was originated by the French mathematician Descartes, and Newton found that the motion in each direction can be analyzed independently of the motions in the other directions at right angles to the first direction.<br />
<br />
 The velocity of our race car is retrieved via the following exp<b></b>ressi&#111;ns:<br />
<br />
<pre class='prettyprint'>(race-car-vx car-161)<br />(race-car-vy car-161)<br />(race-car-vz car-161)</pre>To end this month's article, we show how velocity is computed. Suppose we retrieve the position of the car at simulated time <a class='resized_img' rel='lightbox[007241510347481fa780bd8ce940f2c7]' id='ipb-attach-url-3891-0-34087200-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3891" title="_8820_tex2html_wrap92.gif - Size: 67bytes, Downloads: 19"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-83904700-1309398712_thumb.gif" id='ipb-attach-img-3891-0-34087200-1330210057' style='width:11;height:13' class='attach' width="11" height="13" alt="Attached Image: _8820_tex2html_wrap92.gif" /></a> and save it in some variables, as follows:<br />
<br />
<pre class='prettyprint'>(define x1 (race-car-x car-161))<br />(define y1 (race-car-y car-161))<br />(define z1 (race-car-z car-161))</pre>and again, at a slightly later instant of simulated time, <a class='resized_img' rel='lightbox[007241510347481fa780bd8ce940f2c7]' id='ipb-attach-url-3892-0-34098700-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3892" title="_8820_tex2html_wrap94.gif - Size: 68bytes, Downloads: 16"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-31841900-1309398887_thumb.gif" id='ipb-attach-img-3892-0-34098700-1330210057' style='width:11;height:13' class='attach' width="11" height="13" alt="Attached Image: _8820_tex2html_wrap94.gif" /></a>:<br />
<br />
<pre class='prettyprint'>(define x2 (race-car-x car-161))<br />(define y2 (race-car-y car-161))<br />(define z2 (race-car-z car-161))</pre>We have used <span style='font-family: Courier New'>define</span> to create some new variables that now have the values of the car's positions at two times. To calculate the average velocity of the car between the two times and store it in some more variables, we evaluate the following exp<b></b>ressi&#111;ns:<br />
<br />
<pre class='prettyprint'>(define vx (/ (- x2 x1) (- t2 t1)))<br />(define vy (/ (- y2 y1) (- t2 t1)))<br />(define vz (/ (- z2 z1) (- t2 t1)))</pre>The nesting of exp<b></b>ressi&#111;ns is one level deeper than we have seen heretofore, but these exp<b></b>ressi&#111;ns can be easily analyzed. Since they all have the same form, it suffices to explain just one of them. First of all, the <span style='font-family: Courier New'>define</span> operation works as before, just creating the variable <span style='font-family: Courier New'>vx</span> and assigning it the value of the following exp<b></b>ressi&#111;n. This exp<b></b>ressi&#111;n is<br />
<br />
<pre class='prettyprint'>(/ (- x2 x1) (- t2 t1))</pre>In normal mathematical notation, this exp<b></b>ressi&#111;n would read <a class='resized_img' rel='lightbox[007241510347481fa780bd8ce940f2c7]' id='ipb-attach-url-3893-0-34110100-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3893" title="_8820_tex2html_wrap70.gif - Size: 185bytes, Downloads: 18"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-85836100-1309398944_thumb.gif" id='ipb-attach-img-3893-0-34110100-1330210057' style='width:52;height:32' class='attach' width="52" height="32" alt="Attached Image: _8820_tex2html_wrap70.gif" /></a> and in most computer languages, it would look like this:<br />
<br />
<pre class='prettyprint'>(x2 - x1) / (t2 - t1)	</pre>We can immediately see this is the velocity in the <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3888-0-33986900-1330210057' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3888" title="_8820_tex2html_wrap88.gif - Size: 55bytes, Downloads: 25"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-61658000-1309398483_thumb.gif" id='ipb-attach-img-3888-0-33986900-1330210057' style='width:8;height:7' class='attach' width="8" height="7" alt="Attached Image: _8820_tex2html_wrap88.gif" /></a> direction: a change in position divided by the corresponding change in time. The Scheme version of this exp<b></b>ressi&#111;n looks a little strange, but there is a good reason for it: consistency. Scheme requires that all operations, including everyday mathematical ones, appear in the first position in a parenthesized exp<b></b>ressi&#111;n, immediately after the left parenthesis. Although consistency makes mathematical exp<b></b>ressi&#111;ns look strange, the payback is simplicity: all exp<b></b>ressi&#111;ns have the same form. If Scheme had one notation for mathematical exp<b></b>ressi&#111;ns and another notation for non-mathematical exp<b></b>ressi&#111;ns, like most computer languages, it would be more complicated. Incidentally, Scheme's notation is called Polish notation. Perhaps you have been exposed to Hewlett-Packard calculators, which use reverse Polish, in in which the operator always appears in the <em class='bbc'>last</em> position. Same idea, and advantages, as Scheme, only reversed.<br />
<br />
 So, to analyze the exp<b></b>ressi&#111;n completely, it is a division exp<b></b>ressi&#111;n<br />
<br />
<pre class='prettyprint'>(/ ...)	</pre>whose two arguments are nested subtraction exp<b></b>ressi&#111;ns<br />
<br />
<pre class='prettyprint'>(- ...) (- ...)	</pre>The whole exp<b></b>ressi&#111;n has the form<br />
<br />
<pre class='prettyprint'>(/ (- ...) (- ...))</pre>which, when the variables are filled in, is<br />
<br />
<pre class='prettyprint'>(/ (- x2 x1) (- t2 t1))</pre>After a little practice, Scheme's style for mathematics becomes second nature and the advantages of consistent notation pay off in the long run.<br />
<br />
 Finally, we should like to store the velocity values in our data structure. We do so as follows:<br />
<br />
<pre class='prettyprint'>(set-race-car-vx! car-161 vx)<br />(set-race-car-vy! car-161 vy)<br />(set-race-car-vz! car-161 vz)	</pre>The <span style='font-family: Courier New'>set</span> operations change the values in the data structure named <span style='font-family: Courier New'>car-161</span>. The exclamation point at the end of the names of these operations doesn't do anything special. It's just a Scheme idiom for operations that change data structures.<br />
<br />
<hr class='bbc' /><br />
<em class='bbc'>  converted by: rck@home.net<br />
Thu Sep 29 14:10:24 PDT 1994  </em>]]></description>
		<pubDate>Mon, 07 Jan 2002 15:19:50 +0000</pubDate>
		<guid isPermaLink="false">17ae6739cdbe8fda7dbf9d8a18bb6de0</guid>
	</item>
</channel>
</rss>
