<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Reza Nourai's Game Development Ramblings</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/rezanour/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/rezanour/feed.xml</link>
    <description>Random discussions about game development. Particularly math, physics, collision detection/response, and performance.</description>
    <lastBuildDate>Wed, 17 Apr 2019 03:25:06 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Moving to wordpress</title>
      <link>https://docs.microsoft.com/archive/blogs/rezanour/moving-to-wordpress</link>
      <pubDate>Sun, 01 Jun 2014 19:26:18 GMT</pubDate>
      <dc:creator><![CDATA[Reza Nourai]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/rezanour/2014/06/01/moving-to-wordpress/</guid>
      <description><![CDATA[To give me a bit more flexibility and control over the blog, I'm moving this blog to...]]></description>
      <content:encoded><![CDATA[<p>To give me a bit more flexibility and control over the blog, I'm moving this blog to <a href="http://rezanourai.wordpress.com/">http://rezanourai.wordpress.com/</a>. I've migrated the majority of the content over already. Also, feel free to look for updates on my twitter, @RezaNourai</p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>Introduction to Geometric Queries</title>
      <link>https://docs.microsoft.com/archive/blogs/rezanour/introduction-to-geometric-queries</link>
      <pubDate>Sun, 02 Mar 2014 07:04:18 GMT</pubDate>
      <dc:creator><![CDATA[Reza Nourai]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/rezanour/2014/03/02/introduction-to-geometric-queries/</guid>
      <description><![CDATA[Just about every game, whether simple or complex, will require making geometric queries. It&rsquo;s...]]></description>
      <content:encoded><![CDATA[<p>Just about every game, whether simple or complex, will require making geometric queries. It&rsquo;s a fundamental part of building a game, so I wanted to cover it before we go further. Geometric queries also act as building blocks for many more things that we&rsquo;ll talk about in upcoming posts.</p>
<p>So what is a <strong><em>geometric query</em></strong>, anyway? It&rsquo;s a generic term that covers all questions involving shapes, positions, orientations, and anything else geometry related. Here are some common examples from various parts of a game engine:</p>
<ol>
<li>Collision &ndash; Did the player collide with anything this frame?</li>
<li>Graphics &ndash; Is a particular object visible to the camera?</li>
<li>Audio &ndash; Can the player hear a particular sound? How loud, and in what direction?</li>
<li>Input &ndash; Does the touch point or mouse click location &ldquo;select&rdquo; an object?</li>
<li>AI &ndash; Is an enemy soldier&rsquo;s path to the room unobstructed?</li>
</ol>
<p>It&rsquo;s possible to build more complex geometric queries by combining simpler ones. For that reason, I think it&rsquo;s important to build a set of basic primitive tests that you can use to solve all kinds of problems with. These primitive queries are so fundamental, that I view them as an extension of the core math library.</p>
<p>Geometric queries come in a variety of forms. Some ask a Boolean question, others ask for specific details such as distance or angles. There are countless queries we can come up with, but we&rsquo;ll focus on a few key types of basic queries. They are:</p>
<ul>
<li>Boolean overlap query &ndash; Do two shapes overlap in any fashion? No additional data is returned, only that they overlap or that they don&rsquo;t. Overlap is defined as sharing any region of space with each other, so even if one is completely contained in the other, they&rsquo;re considered overlapping.</li>
<li>Overlap query &ndash; This is similar to the Boolean overlap query, except that it also returns information about the overlapping region.</li>
<li>Intersection query &ndash; This is a class of queries that can return more detailed intersection data.</li>
<li>Ray cast query &ndash; If you shoot a ray out from a point in a direction, does it hit anything? Where? How far?</li>
</ul>
<p>Shapes can range from very simple (points, lines, triangles) to very complex (arbitrary polyhedra, smooth curvy surfaces, etc&hellip;). For the purposes of this blog, we&rsquo;ll start with some simple shapes as our building blocks, and in later posts will cover a few complex ones. However, we&rsquo;ll generally always stick with convex shapes. This is because queries involving convex shapes generally have simpler solutions (both mathematically so we can understand them, and computationally so they are efficient). Most non-convex shapes can be described in terms of multiple convex ones, so we can usually use a combination of smaller queries to answer the non-convex question.</p>
<p>This post was just an introduction to the concept of geometric queries, giving a reason for why we care about them. In the coming posts, we&rsquo;ll explore some basic shapes and common queries involving them. I&rsquo;ll do my best to come up with real-world examples to use for the motivation of each test. I&rsquo;m currently planning on covering points, lines, triangles, spheres, and axis aligned boxes as the simple shapes. Then, the plan is to talk about using a <em>change of basis</em> and the separating axis test as a way to solve more complicated problems, using the non-axis aligned box (also called oriented bounding box) as an example. Once shapes are covered, we&rsquo;ll talk about higher level algorithms for visibility culling, collision detection, space partitioning, etc&hellip;</p>
<p>Also, if you have specific shapes or queries you&rsquo;re interested in, please let me know and I&rsquo;ll try to include them.</p>]]></content:encoded>
    </item>
    <item>
      <title>Reviving the blog</title>
      <link>https://docs.microsoft.com/archive/blogs/rezanour/reviving-the-blog</link>
      <pubDate>Sat, 08 Feb 2014 14:13:20 GMT</pubDate>
      <dc:creator><![CDATA[Reza Nourai]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/rezanour/2014/02/08/reviving-the-blog/</guid>
      <description><![CDATA[As you may have heard, the Xbox One shipped! :)
I spent the past 2 years working on various OS...]]></description>
      <content:encoded><![CDATA[<p>As you may have heard, the Xbox One shipped! :)</p>
<p>I spent the past 2 years working on various OS components for the Xbox One, including much of the multitasking work for the system (what allows you switch quickly from app to app, or from game to app and back. And run multiple apps side by side), the live rendering of the game you see in the dash when you pop back with the Guide button, and various other things throughout. That's also the reason why my blog has been pretty quiet, things were intense trying to get a high quality product out the door on time. Now that the Xbox has shipped, I'm moving on to work on the core OS graphics kernel team, so I can help improve graphics performance and capabilities across all of our products (Xbox, Phone, and Windows). Additionally, I'm going to be setting aside time to start making regular posts to this blog again. Given that my new role is in graphics, you can expect more graphics themed posts. However, that doesn't mean I'm abandoning the&nbsp;physics engine series (I need to dust off the work I was doing for that, and get it cleaned up enough to post :) ).</p>
<p>Looking forward to having some great discussions on here.</p>
<p>-Reza</p>]]></content:encoded>
    </item>
    <item>
      <title>Math Primer Series: Rotation Representations and Quaternions</title>
      <link>https://docs.microsoft.com/archive/blogs/rezanour/math-primer-series-rotation-representations-and-quaternions</link>
      <pubDate>Sun, 29 Apr 2012 20:12:03 GMT</pubDate>
      <dc:creator><![CDATA[Reza Nourai]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/rezanour/2012/04/29/math-primer-series-rotation-representations-and-quaternions/</guid>
      <description><![CDATA[We saw the power and usefulness of transforms in the previous primer posts, and we’ll be using them...]]></description>
      <content:encoded><![CDATA[<p><font size="3">We saw the power and usefulness of transforms in the previous primer posts, and we’ll be using them quite a bit in our discussions of physics and graphics. One of the first tasks we’ll need to do is determine how to represent our transformations in code. We’re going to be creating, manipulating, and animating these transformations over time, so they must be easy and efficient to work with. Particularly, we’d like to be able to manipulate the individual components (translation, rotation, and scale) independently. One natural, but naïve, choice is to just use the transformation matrix directly, since that’s the form we’ve seen so far. However, using a matrix directly makes it nontrivial to manipulate and animate. It’s also difficult to retrieve and change independent components of the transform. It’s obvious that we want something better, so let’s take a look at some options.</font></p> <font size="3"></font>  <p><font size="3">The next natural choice is to represent translation, rotation, and scale separately. This makes it trivial to manipulate the values independently. However, since most graphics packages require the final transformation as a matrix, we’ll need to combine the elements later. This isn’t very difficult to do, and we’ve already seen how we can do that in previous posts. Translation and scale are trivially represented as 3 element vectors, which maps well to how we use them, including combining them with matrices. But what about rotation? How can we represent that?</font></p>  <h4><font style="font-weight: bold;" color="#4f81bd" size="4"></font></h4>  <h4><font style="font-weight: bold;" color="#4f81bd" size="4">Rotation Matrix</font></h4>  <p><font size="3">One way to represent the rotation is to just leave it as a pure orthonormal rotation matrix. It is easy to combine this form with position and scale, since the rotation is already in matrix form. We can add more rotation to this matrix by concatenating other rotation matrices using matrix multiplication. This is somewhat expensive, but conceptually simple. </font></p>  <p><font size="3">However, as more and more rotations are applied, our matrix could start to stray from being orthonormal (due to rounding errors, etc…). </font><font size="3">If we stray far enough away from being orthonormal, we can no longer be considered a rotation, and applying this matrix to an object may have unexpected side effects like shearing or deformation. Therefore, we need to regularly check and ensure that our matrix maintains the orthonormal property, which is another somewhat expensive task to do regularly. </font></p>  <p><font size="3">Finally, we still have the problem of requiring 9 floats (16 if you only support 4x4 matrices) to store the data. Despite all this, rotation matrices are still a common form of storing rotations.</font></p> <font size="3">&#160; </font>  <h4><font style="font-weight: bold;" color="#4f81bd" size="4"></font></h4>  <h4><font style="font-weight: bold;" color="#4f81bd" size="4">Euler Angles</font></h4> <font size="3"></font>  <p><font size="3">Another common way to represent rotation is by using 3 angles (called the Euler angles) which represent a rotation around the x, y, and z axes. This representation only requires 3 floating point numbers to store, and allows us to easily adjust rotations around each axis independently. When the axes of rotation are the local coordinate axes of an object, the rotations are sometimes called yaw (rotation about y axis), pitch (rotation about x-axis), and roll (rotation about z axis). </font></p>  <p><font size="3">While this scheme sounds simple to implement, it has some serious draw backs. First of all, in which order do you apply the rotations? Do you first rotate about x, then about the y, then about the z axis? Or perhaps a different order? You’ll notice that the result is different for each combination. There is also a condition called </font><a href="http://en.wikipedia.org/wiki/Gimbal_lock"><font size="3">gimbal lock</font></a><font size="3"> which can occur when two axis are made collinear as you rotate. For instance, if we first rotate about the y axis, and this brings our&#160; z axis in line with where our x axis would have been, then the z rotation would look more like an x rotation, and would likely not give us the result we’re looking for.</font></p>  <p><font size="3">Even with these issues, Euler angles are a common way of representing rotations. They are certainly intuitive, which is likely why they are one of the most common representations in 3D modeling tools, game and level editors, CAD programs, and many other software applications where reading and typing in rotation values is necessary. But for our internal representation in code, we can probably do better.</font></p>  <p><font size="3"></font></p>  <h4><font style="font-weight: bold;" color="#4f81bd" size="4">Axis-Angle</font></h4>  <p><font size="3">For any set of rotations, the final orientation can be represented as some final axis of rotation and an angle. This is called axis-angle representation. For example, imagine that your head is at the origin, and that you are looking forward along some axis. If you rotate your head about the y axis by 90 degrees to the left, then rotate about the z axis by 90 degrees so that you are facing upward, you end up looking up and to the left, with your chin held high to your left. This final orientation could have also been achieved by using a single axis, which is at a 45 degree angle going in the up &amp; right direction from where you started. Return your head to the starting position, and imagine that there is an axis going up and to the right. Now rotate your head about that axis and you should see that you end up in the same final location as the first pair of rotations.</font></p>  <p><font size="3">The axis and angle are normally stored as a single 3 element vector. The direction of the vector represents the axis of rotation, and the magnitude of the vector is equal to the angle of rotation. This keeps the storage requirements minimal, requiring only 3 floats. Unfortunately, adding two rotations in this form is not a simple task. You can’t just add the two vectors together, as rotations aren’t really vectors. This difficulty of combining them makes these less ideal for use in games, as one would normally convert them to another form, combine them, and then convert back.</font></p>  <p><font size="3"></font></p>  <h4><font style="font-weight: bold;" color="#4f81bd" size="4">Quaternion</font></h4>  <p><font size="3">The final representation for rotations that we’ll consider is the quaternion. Quaternions are a set of numbers (usually said to be in the space <em>H</em>) and are an extension of the complex numbers, and they have a lot of uses in mathematics. For our purposes, however, we are only concerned with <em>unit quaternions.</em> A unit quaternion can be used to represent rotations. For a complete discussion of how unit quaternions relate to rotation, and how you can visualize them using a hypersphere, refer to <a href="http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation">this wiki page</a>.</font></p>  <p><font size="3">Before we get into the mathematics and operations of quaternions, let’s examine why they are a better choice than the options we’ve previously discussed. Firstly, they require only 4 floats to store, which makes them much more compact than a rotation matrix, and pretty close in footprint to the other representations. Secondly, combining quaternions is far simpler than for axis angle, and they represent a continuous space so they have no risk of gimbal lock like the Euler angles. While it’s true that we have to normalize quaternions often to prevent rounding error, the normalization process is simple and much more efficient than orthonormalizing a rotation matrix. Lastly, converting to matrix representation is simple and requires no complex operations, so building our composite transform is trivial as well.</font></p>  <p><font size="3">How exactly do we represent a quaternion? What do they look like? The quaternion space, <em>H</em>, is a 4 dimensional vector space and so we can represent quaternions using a 4 element vector. Quaternions are an extension of complex numbers, and have 1 real component and 3 imaginary components. They are written in the form w + x<em>i</em>, + y<em>j</em> + z<em>k</em>. To store them as a 4 element vector, we just put the exponents for i, j, and k into x, y, and z, and use w to represent the real portion. </font></p>  <p><font size="3">The usual convention for writing quaternions is to write the 4 element vector with the real number first:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2350.clip_image004_4EBE04E8.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2350.clip_5F00_image004_5F00_4EBE04E8.gif"><img style="border: 0px currentcolor; margin-right: auto; margin-left: auto; float: none; display: block; background-image: none;" title="clip_image004" border="0" alt="clip_image004" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3821.clip_image004_thumb_479EC870.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3821.clip_5F00_image004_5F00_thumb_5F00_479EC870.gif" width="81" height="25" /></a></p>  <p><font size="3">We can also write it as the real component and the vector component:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3362.clip_image00234_74A0C803.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3362.clip_5F00_image00234_5F00_74A0C803.gif"><img style="margin: 0px auto; border: 0px currentcolor; float: none; display: block; background-image: none;" title="clip_image002[34]" border="0" alt="clip_image002[34]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5736.clip_image00234_thumb_0D306554.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5736.clip_5F00_image00234_5F00_thumb_5F00_0D306554.gif" width="84" height="25" /></a></p>  <p><font size="3">Unit quaternions can be thought of as a modified axis-angle (axis r, angle theta), where:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8463.clip_image00236_3808C966.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8463.clip_5F00_image00236_5F00_3808C966.gif"><img style="margin: 0px auto; border: 0px currentcolor; float: none; display: block; background-image: none;" title="clip_image002[36]" border="0" alt="clip_image002[36]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2210.clip_image00236_thumb_73C86219.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2210.clip_5F00_image00236_5F00_thumb_5F00_73C86219.gif" width="79" height="45" /></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6404.clip_image00239_57B7A32E.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6404.clip_5F00_image00239_5F00_57B7A32E.gif"><img style="margin: 0px auto; border: 0px currentcolor; float: none; display: block; background-image: none;" title="clip_image002[39]" border="0" alt="clip_image002[39]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0131.clip_image00239_thumb_13773BE2.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0131.clip_5F00_image00239_5F00_thumb_5F00_13773BE2.gif" width="176" height="45" /></a></p>  <p><font size="3">The identity quaternion is:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/1777.clip_image006_12923940.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/1777.clip_5F00_image006_5F00_12923940.gif"><img style="border: 0px currentcolor; margin-right: auto; margin-left: auto; float: none; display: block; background-image: none;" title="clip_image006" border="0" alt="clip_image006" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2671.clip_image006_thumb_72772C82.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2671.clip_5F00_image006_5F00_thumb_5F00_72772C82.gif" width="78" height="25" /></a></p>  <p><font size="3">Quaternion addition is just like any 4 element vector:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6866.clip_image008_2E36C536.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6866.clip_5F00_image008_5F00_2E36C536.gif"><img style="border: 0px currentcolor; margin-right: auto; margin-left: auto; float: none; display: block; background-image: none;" title="clip_image008" border="0" alt="clip_image008" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3326.clip_image008_thumb_271788BE.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3326.clip_5F00_image008_5F00_thumb_5F00_271788BE.gif" width="419" height="30" /></a></p>  <p><font size="3">Scalar multiplication also works as it does for vectors:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3240.clip_image010_38F41C8B.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3240.clip_5F00_image010_5F00_38F41C8B.gif"><img style="border: 0px currentcolor; margin-right: auto; margin-left: auto; float: none; display: block; background-image: none;" title="clip_image010" border="0" alt="clip_image010" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0601.clip_image010_thumb_31D4E013.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0601.clip_5F00_image010_5F00_thumb_5F00_31D4E013.gif" width="194" height="27" /></a></p>  <p><font size="3">Normalizing a quaternion should also look familiar:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8623.clip_image012_0690490C.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8623.clip_5F00_image012_5F00_0690490C.gif"><img style="border: 0px currentcolor; margin-right: auto; margin-left: auto; float: none; display: block; background-image: none;" title="clip_image012" border="0" alt="clip_image012" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5074.clip_image012_thumb_7F710C93.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5074.clip_5F00_image012_5F00_thumb_5F00_7F710C93.gif" width="210" height="55" /></a></p>  <p><font size="3">Quaternions have a <em>conjugate</em>, which is written as <strong>q*</strong>. The <em>reciprocal </em>or <em>multiplicative</em> <em>inverse</em> of the quaternion can be defined in terms of the conjugate, and is written as <strong>q<sup>-1</sup></strong>:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5086.clip_image00224_114DA061.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5086.clip_5F00_image00224_5F00_114DA061.gif"><img style="margin: 0px auto; border: 0px currentcolor; float: none; display: block; background-image: none;" title="clip_image002[24]" border="0" alt="clip_image002[24]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7633.clip_image00224_thumb_4D0D3914.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7633.clip_5F00_image00224_5F00_thumb_5F00_4D0D3914.gif" width="198" height="27" /></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2768.clip_image00230_77667CF6.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2768.clip_5F00_image00230_5F00_77667CF6.gif"><img style="margin: 0px auto; border: 0px currentcolor; float: none; display: block; background-image: none;" title="clip_image002[30]" border="0" alt="clip_image002[30]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2781.clip_image00230_thumb_1E349337.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2781.clip_5F00_image00230_5F00_thumb_5F00_1E349337.gif" width="200" height="52" /></a></p>  <p><font size="3">Multiplying, or <em>concatenating</em>, two quaternions takes the form:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/1033.clip_image00232_171556BF.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/1033.clip_5F00_image00232_5F00_171556BF.gif"><img style="margin: 0px auto; border: 0px currentcolor; float: none; display: block; background-image: none;" title="clip_image002[32]" border="0" alt="clip_image002[32]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3660.clip_image00232_thumb_52D4EF72.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3660.clip_5F00_image00232_5F00_thumb_5F00_52D4EF72.gif" width="389" height="25" /></a></p>  <p><font size="4">or:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3240.clip_image00228_50AB53F1.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3240.clip_5F00_image00228_5F00_50AB53F1.gif"><img style="margin: 0px auto; border: 0px currentcolor; float: none; display: block; background-image: none;" title="clip_image002[28]" border="0" alt="clip_image002[28]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6076.clip_image00228_thumb_2566BCEA.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6076.clip_5F00_image00228_5F00_thumb_5F00_2566BCEA.gif" width="624" height="122" /></a></p>  <p><font size="3">It is important to note that quaternion multiplication is not commutative, and written and performed like matrix multiplication, from right to left. Finally, rotating a vector by a quaternion can be achieved by using:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8623.clip_image00216_4C34D32A.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8623.clip_5F00_image00216_5F00_4C34D32A.gif"><img style="border: 0px currentcolor; margin-right: auto; margin-left: auto; float: none; display: block; background-image: none;" title="clip_image002[16]" border="0" alt="clip_image002[16]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0284.clip_image00216_thumb_451596B2.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0284.clip_5F00_image00216_5F00_thumb_5F00_451596B2.gif" width="105" height="28" /></a></p>  <p><font size="3">where <strong>v<sub>r</sub></strong> is the resulting rotated vector, and <strong>v<sub>q</sub></strong> is the initial vector represented as a quaternion (w of 0).</font></p>  <p><font size="3"></font></p>  <p><font size="3">Converting to matrix form is also very important for us, since we’ll need to do this to build our transform. Additionally, creating quaternions from a given axis and angle will prove to be much more convenient than trying to determine rotation quaternions directly. For instance, if I want to rotate an object about the y axis by theta degrees, it would be convenient to specify my rotation in those terms.</font></p>  <p><font size="3">Converting from an axis <em><strong>v</strong></em> and angle theta to a quaternion, which can then get applied to the orientation, is straightforward:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3821.clip_image00218_3DF65A3A.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3821.clip_5F00_image00218_5F00_3DF65A3A.gif"><img style="border: 0px currentcolor; margin-right: auto; margin-left: auto; float: none; display: block; background-image: none;" title="clip_image002[18]" border="0" alt="clip_image002[18]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4401.clip_image00218_thumb_64C4707A.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4401.clip_5F00_image00218_5F00_thumb_5F00_64C4707A.gif" width="148" height="45" /></a></p>  <p><font size="3">Creating a matrix, which represents the quaternion rotation, takes the form of:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/1185.clip_image00226_44A963BD.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/1185.clip_5F00_image00226_5F00_44A963BD.gif"><img style="margin: 0px auto; border: 0px currentcolor; float: none; display: block; background-image: none;" title="clip_image002[26]" border="0" alt="clip_image002[26]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4722.clip_image00226_thumb_5685F78A.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4722.clip_5F00_image00226_5F00_thumb_5F00_5685F78A.gif" width="528" height="86" /></a></p>  <p><font size="3">With all of these operations, we can now handle all of our scenarios, and we’ve met our criteria for choosing a representation for rotations. To summarize:</font></p>  <ul>   <li><font size="3">Requires only 4 floating point numbers to store</font></li>    <li><font size="3">Manipulation is simplified by using axis-angle rotations as input</font></li>    <li><font size="3">Vectors are trivially rotated using the formula above</font></li>    <li><font size="3">Easily converted into matrix form for building transform</font></li>    <li><font size="3">Normalizing to maintain unit quaternion qualities is trivially performed</font></li> </ul>  <p><font size="3"></font></p>  <p><font size="3">Given all of these properties and benefits, it’s easy to see why quaternions have become a very popular choice for games to use. As we start to explore the physics engine more in the coming posts, we’ll be using quaternions as our representation of rotation as well, and will be referring back to many of these concepts and formulas for that discussion.</font></p>  <p><font size="3"></font></p>]]></content:encoded>
    </item>
    <item>
      <title>More posts coming, magazine article published!</title>
      <link>https://docs.microsoft.com/archive/blogs/rezanour/more-posts-coming-magazine-article-published</link>
      <pubDate>Sun, 22 Apr 2012 12:34:51 GMT</pubDate>
      <dc:creator><![CDATA[Reza Nourai]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/rezanour/2012/04/22/more-posts-coming-magazine-article-published/</guid>
      <description><![CDATA[I apologize for the lack of updates in a while, but things have been pretty busy at work. I’m...]]></description>
      <content:encoded><![CDATA[<p>I apologize for the lack of updates in a while, but things have been pretty busy at work. I’m working on a new post and I’d love to get some feedback on what topics people want to see most in the future.</p>  <p><font color="#4f81bd"><strong>Topics I have planned:</strong></font></p>  <ol>   <li>Finish the math primer (rotations &amp; quaternions)</li>    <li>Collision detection infrastructure</li>    <li>Common collision detection algorithms in detail (multiple posts)</li>    <li>Physics simulation infrastructure</li>    <li>Common physics integration and solver algorithms (multiple posts)</li>    <li>Architecture and building of a full physics and collision engine (multi part series)</li>    <li>If there’s enough interest in non-physics topics, I can go into graphics, scripting and general engine design</li> </ol>  <p>By the way, I recently wrote an article about collision detection that got published in the April issue of GameCoderMag.<strong> </strong><a href="http://en.sdjournal.org/" target="_blank"><strong>Check it out!</strong></a></p>]]></content:encoded>
    </item>
    <item>
      <title>Math Primer Series: Matrices III: Affine Transformations and Matrices</title>
      <link>https://docs.microsoft.com/archive/blogs/rezanour/math-primer-series-matrices-iii-affine-transformations-and-matrices</link>
      <pubDate>Sun, 20 Nov 2011 16:13:49 GMT</pubDate>
      <dc:creator><![CDATA[Reza Nourai]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/rezanour/2011/11/20/math-primer-series-matrices-iii-affine-transformations-and-matrices/</guid>
      <description><![CDATA[We’ve seen matrices used as representations of a basis, and we’ve seen them used as linear...]]></description>
      <content:encoded><![CDATA[<p>We’ve seen matrices used as representations of a basis, and we’ve seen them used as linear transformations, but what else can we do with them? So far, we’ve only been able to use matrices to transform vectors from one vector space to another. What about points and vectors in an affine space? There is another class of transformation, called an affine transformation, which does exactly this. </p>  <h4><font color="#4f81bd">Affine Transformations</font></h4>  <p>An <em>affine transform </em>is a transformation which maps points and vectors in an affine space to another affine space. This allows us to transform positions now, in addition to just vectors. An affine transformation can be thought of as a combination of a basis matrix and a translation to an origin, which is analogous to affine spaces compared to vector spaces, since affine spaces add an origin. When we look at an object, we can define a right, up, and forward vector for it, relative to some frame of reference. But furthermore, we can describe it’s <em>position </em>in space. Not the position of a particular point on the object, but the position of the whole object. What we’re actually doing is saying that all the points on the object can be thought of relative to some origin on the object, and that origin has a location in space (relative to some frame of reference of course). This means that even though we move the object’s origin around, we’re not changing the orientation (the right, up, and forward vectors). The reverse is also true, we can rotate or scale our object all we want, but it won’t move the object’s origin. In this way, we see that the origin of the object, and it’s basis are independent, and the formal affine definition reflects this separation. Affine transformations are formally defined as multiplying a point by a matrix component (to define it’s orientation) and then adding a vector component (to define it’s origin’s position):</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/1031.clip_image00219_666E7FEA.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/1031.clip_5F00_image00219_5F00_666E7FEA.gif"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="clip_image002[19]" border="0" alt="clip_image002[19]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2110.clip_image00219_thumb_5425B928.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2110.clip_5F00_image00219_5F00_thumb_5F00_5425B928.gif" width="113" height="29" /></a><b></b></p>    <p>Here, M is the matrix portion of the transformation, and is sometimes referred to as the linear portion. This can consist of rotation, scaling, or any other linear transformation. The t in the equation is called the <em>translation </em>and is the vector defining where the object’s origin is compared to some frame of reference. Let’s take a look at an example to get a better grasp of this:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4073.image_7DAFB87D.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4073.image_5F00_7DAFB87D.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2251.image_thumb_163F55CE.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2251.image_5F00_thumb_5F00_163F55CE.png" width="855" height="763" /></a></p>  <p>In Figure 1, we see a frame of reference shown (origin O, with right, up, and forward defining our frame). We also see an object (the square). If we were locally sitting inside that object, then x and y would have been our right and up vectors, and P our local origin. But since we’re examining the object from a different frame of reference, it appears rotated and located at some other location. This placement and orientation can be described as a single affine transformation, as show in the equation above, with M being the linear portion and t being the translation portion. Using our example above, and assuming only rotation (to simplify), our matrix M would likely look like:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5756.clip_image0046_7AF3CF68.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5756.clip_5F00_image0046_5F00_7AF3CF68.gif"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="clip_image004[6]" border="0" alt="clip_image004[6]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2117.clip_image0046_thumb_5EE3107D.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2117.clip_5F00_image0046_5F00_thumb_5F00_5EE3107D.gif" width="171" height="72" /></a></p>  <p>Assuming that x, y, and z (which we can’t see in the image) are defined relative to our coordinate space and are unit length. Look back to <a href="http://blogs.msdn.com/b/rezanour/archive/2011/09/05/math-primer-series-matrices-i-introduction-and-basics-operations.aspx" target="_blank">this post</a> if you’re unsure how we got that. We then would add our translation vector (dashed line t in the figure).</p>  <p>While this works out well enough, the extra addition must be remembered and there’s not a convenient way to store this information. Fortunately, there’s an alternate way to express and use affine transformations which is much more convenient and consistent with what we’ve already seen:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/1121.clip_image0064_339E7976.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/1121.clip_5F00_image0064_5F00_339E7976.gif"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="clip_image006[4]" border="0" alt="clip_image006[4]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2021.clip_image0064_thumb_2C7F3CFE.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2021.clip_5F00_image0064_5F00_thumb_5F00_2C7F3CFE.gif" width="72" height="46" /></a></p>  <p>Note that this is now a 4x4 matrix, as apposed to the usual 3x3 we’ve seen so far. It contains the linear part of the affine transformation in the upper left 3x3 block, and the translation vector as the last column. The bottom row contains 0s with the exception of the last entry which is a 1. Here’s an example of the expanded matrix from the previous example:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4657.clip_image0085_25`86.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4657.clip_5F00_image0085_5F00_25600086.gif"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="clip_image008[5]" border="0" alt="clip_image008[5]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7384.clip_image0085_thumb_4C2E16C6.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7384.clip_5F00_image0085_5F00_thumb_5F00_4C2E16C6.gif" width="165" height="98" /></a></p>  <p>Before we go on, I wanted to call out that I’ve been using column matrices so far in this post. The same concepts apply if you’re using row matrices, just remember the layout will be transposed from what I’m showing here, with the translation vector as the bottom row of the matrix, and the 0s as the last column, and transposing the upper left block.</p>  <p>Now, we claimed earlier that affine transformations could be used to transform both points and vectors from an affine space to another. Points and vectors are quite different. One is a location and one is a direction. It doesn’t make any sense to translate a direction, so how can we possibly use this matrix to transform vectors? The answer is in the fact that we have to augment a point or vector to be compatible with this matrix. This is a 4x4, and both points and vectors are 3 components. Without some augmentation, the points and vectors are not compatible with this new matrix. How we augment them depends on whether they are points or vectors, and dictates whether the translation component of the affine matrix is applied or not.</p>  <p>If you recall from <a href="http://blogs.msdn.com/b/rezanour/archive/2011/05/19/math-primer-vectors-i-points-vs-vectors.aspx" target="_blank">this post</a>, points are sometimes written as 4 component vectors with a 1 in the last component (sometimes called w). Vectors can likewise be written with 4 components, with the last component equal to 0. The reasons this worked for arithmetic were shown in the post, but we now see there is another critical reason for that distinction. When you multiply a 4 element vector with the affine matrix above, the math works out to:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7317.clip_image0105_5E0AAA93.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7317.clip_5F00_image0105_5F00_5E0AAA93.gif"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="clip_image010[5]" border="0" alt="clip_image010[5]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0044.clip_image0105_thumb_19CA4347.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0044.clip_5F00_image0105_5F00_thumb_5F00_19CA4347.gif" width="136" height="46" /></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3681.clip_image012_12AB06CF.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3681.clip_5F00_image012_5F00_12AB06CF.gif"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="clip_image012" border="0" alt="clip_image012" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0042.clip_image012_thumb_39791D0F.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0042.clip_5F00_image012_5F00_thumb_5F00_39791D0F.gif" width="141" height="98" /></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3678.clip_image014_4B55B0DC.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3678.clip_5F00_image014_5F00_4B55B0DC.gif"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="clip_image014" border="0" alt="clip_image014" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2021.clip_image014_thumb_7223C71C.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2021.clip_5F00_image014_5F00_thumb_5F00_7223C71C.gif" width="233" height="98" /></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4657.clip_image016_18F1DD5D.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4657.clip_5F00_image016_5F00_18F1DD5D.gif"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="clip_image016" border="0" alt="clip_image016" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7384.clip_image016_thumb_2ACE712A.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7384.clip_5F00_image016_5F00_thumb_5F00_2ACE712A.gif" width="283" height="107" /></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3107.clip_image018_3CAB04F7.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3107.clip_5F00_image018_5F00_3CAB04F7.gif"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="clip_image018" border="0" alt="clip_image018" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5734.clip_image018_thumb_11666DF0.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5734.clip_5F00_image018_5F00_thumb_5F00_11666DF0.gif" width="283" height="102" /></a></p>  <p>&#160;</p>  <p>Note the highlighted portion of the last one there. This is exactly what you’d get using a normal 3x3 transform M multiplied by p. This means that we get the exact same result as applying the linear transformation M and then adding t times p’s w component. If the w component is 0, as in the vector case, it cancels out the translation portion. If the w component is 1, then we translate by exactly t, which is what we expect for points. Notice also that the last element of the new vector is exactly equal to the w component of the starting vector. This means that vectors stay vectors under affine transformation, and points stay points. This is pretty important, it means that an affine space will never turn points into vectors or vice versa. The augmented points and vectors which contain the w component are said to be in <em>homogenous space</em>, and another term often used for the affine matrix (since it requires homogenous vectors) is a <em>homogenous matrix.</em></p>  <h4></h4>  <p>In the next and final matrix-related math primer post, we’ll examine some other operations which can be performed on matrices. Specifically, we’ll take a look at the determinant, adjunct, and inverse. Afterwards, we’ll quickly look at some of the problems with rotations, and introduce quaternions as an alternative way to express rotations which overcomes many of the traditional problems. I’m going to be continuing the physics posts as well.</p>]]></content:encoded>
    </item>
    <item>
      <title>Math Primer Series: Matrices II: Linear Transformations</title>
      <link>https://docs.microsoft.com/archive/blogs/rezanour/math-primer-series-matrices-ii-linear-transformations</link>
      <pubDate>Sun, 02 Oct 2011 22:36:30 GMT</pubDate>
      <dc:creator><![CDATA[Reza Nourai]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/rezanour/2011/10/02/math-primer-series-matrices-ii-linear-transformations/</guid>
      <description><![CDATA[In the last installment of the math primer series, we looked at the basics of matrices. Today, we’ll...]]></description>
      <content:encoded><![CDATA[<p><font face="Arial">In the </font><a href="http://blogs.msdn.com/b/rezanour/archive/2011/09/05/math-primer-series-matrices-i-introduction-and-basics-operations.aspx" target="_blank"><font face="Arial">last installment</font></a><font face="Arial"> of the math primer series, we looked at the basics of matrices. Today, we’ll take a look at using matrices for linear transformations, which are one of the most common uses of matrices in games. But, before we dive into linear transformations, let’s take a quick look at what a <em>transformation</em> is, and why we represent them using a matrix in the first place.</font></p>  <p><font face="Arial">A transformation is any operation that maps values from one space to another. In the context of standard algebra, we are usually introduced to transformations in the form of <em>functions</em>. Functions and transformations are really one and the same, though the term transformation is more common in linear algebra. In fact, sometimes you may even see transformations or functions referred to as <em>mappings</em>. Again, for our purposes these are all equivalent ways of conveying the same meaning. We take in a set of values, called the domain, and we produce another set of values, called the range.</font></p>  <p><font face="Arial">When discussing transformations of affine and vector spaces, it is quite convenient to represent the transformations in the form of a matrix. This allows for succinct notation, as well as easily combining transformations through matrix concatenation (multiplication). For example, take the following transformation:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6710.clip_image002_4B81C7D3.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6710.clip_5F00_image002_5F00_4B81C7D3.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002" border="0" alt="clip_image002" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0456.clip_image002_thumb_0E9D2034.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0456.clip_5F00_image002_5F00_thumb_5F00_0E9D2034.gif" width="101" height="29" /></font></a><b></b></p> <font color="#4f81bd" face="Arial"></font>  <p><font face="Arial">Here, we say that the matrix <strong><em>M </em></strong>is multiplied with the vector <strong><em>x</em></strong>, and is represented by the transformation <em>T</em>. We also know, from our discussion about matrices and vectors, that if we are using column vectors and column-major matrices, then the result of this transformation will be another vector. If we’re using row vectors and row-major matrices, then our result would be a matrix. If we want to use row vectors and row matrices, and still get a vector result, we would write the transformation as:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4064.clip_image0024_077DE3BC.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4064.clip_5F00_image0024_5F00_077DE3BC.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002[4]" border="0" alt="clip_image002[4]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4087.clip_image0024_thumb_005EA744.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4087.clip_5F00_image0024_5F00_thumb_5F00_005EA744.gif" width="101" height="29" /></font></a><b></b></p> <font color="#4f81bd" size="3" face="Arial"></font>  <p><font face="Arial">A <em>linear</em> transformation is a transformation that maps from vector space to vector space, maintaining the vector addition and scalar multiplication properties of the vectors. The first part of the definition, mapping from vector space to vector space, means that our transformation matrix must be exactly <em>n</em> x <em>n</em> in size, where <em>n</em> is the dimension of the vector space. The number of columns must be n in order to be compatible for multiplication with the vector. The number of rows must be n to give us an n-dimensional vector as a result. For 2 dimensional space, that means a 2x2 matrix. For three dimensional space, that means a 3x3 matrix.</font> </p>  <p><font face="Arial">The second part of the definition means that the addition of two vectors, and scalar multiplication of a vector, must be maintained after the transformation. Put in equation form:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8272.clip_image004_793F6ACB.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8272.clip_5F00_image004_5F00_793F6ACB.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image004" border="0" alt="clip_image004" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4571.clip_image004_thumb_72202E53.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4571.clip_5F00_image004_5F00_thumb_5F00_72202E53.gif" width="207" height="29" /></font></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5141.clip_image0026_7FF2744E.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5141.clip_5F00_image0026_5F00_7FF2744E.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002[6]" border="0" alt="clip_image002[6]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3007.clip_image0026_thumb_5FD76791.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3007.clip_5F00_image0026_5F00_thumb_5F00_5FD76791.gif" width="131" height="29" /></font></a></p>  <p><font face="Arial">The first equation says that the transformation of the sum of two vectors is equal to the sum of the transformation of the original vectors. This is what we mean when we say that the vector addition property of the vectors is maintained. The second equation says that the transformation of a scaled vector is equal to scaling the transformation of the original vector. This is what’s meant by maintaining the scalar multiplication property of vectors. Because of this, an easy way to determine if a transformation is linear is to combine the above equations and try and prove that they hold true for a particular transformation:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4578.clip_image0028_6DA9AD8C.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4578.clip_5F00_image0028_5F00_6DA9AD8C.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002[8]" border="0" alt="clip_image002[8]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2425.clip_image0028_thumb_4D8EA0CF.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2425.clip_5F00_image0028_5F00_thumb_5F00_4D8EA0CF.gif" width="227" height="29" /></font></a></p>  <p><font face="Arial">If you can prove that the above does not hold true for a given transformation, then that transformation is not linear.</font></p>  <p><font face="Arial">Next, we’ll look at two of the most common linear transformations encountered in games: scaling and rotation. In addition to describing each transformation, I’ll show that they’re linear by using the equations above, and also use each one with some real numbers plugged in as an example. Hopefully, this will make them easier to understand.</font></p>  <h4>Scale</h4>  <p><font face="Arial">The first linear transformation we’ll look at is scaling. Three dimensional scaling can be represented with the following matrix:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3005.clip_image00212_466F6457.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3005.clip_5F00_image00212_5F00_466F6457.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002[12]" border="0" alt="clip_image002[12]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0842.clip_image00212_thumb_1162D527.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0842.clip_5F00_image00212_5F00_thumb_5F00_1162D527.gif" width="112" height="85" /></font></a></p>  <p><font face="Arial">Where s<sub>i </sub>represents the amount of scale along the <strong><em>i</em></strong> vector, s<sub>j</sub> along the <strong><em>j</em></strong> vector, and s<sub>k</sub> along the <strong><em>k</em></strong> vector. Solving the linear transformation equation from before gives us:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5460.clip_image00214_7147C869.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5460.clip_5F00_image00214_5F00_7147C869.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002[14]" border="0" alt="clip_image002[14]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6131.clip_image00214_thumb_512CBBAC.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6131.clip_5F00_image00214_5F00_thumb_5F00_512CBBAC.gif" width="101" height="29" /></font></a><b></b></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6153.clip_image0044_5EFF01A7.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6153.clip_5F00_image0044_5F00_5EFF01A7.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image004[4]" border="0" alt="clip_image004[4]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/1348.clip_image0044_thumb_05CD17E8.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/1348.clip_5F00_image0044_5F00_thumb_5F00_05CD17E8.gif" width="224" height="85" /></font></a><b></b></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8204.clip_image006_7EADDB6F.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8204.clip_5F00_image006_5F00_7EADDB6F.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image006" border="0" alt="clip_image006" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5141.clip_image006_thumb_5E92CEB2.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5141.clip_5F00_image006_5F00_thumb_5F00_5E92CEB2.gif" width="81" height="72" /></font></a><b></b></p>  <p><font face="Arial">Which is what we’d expect. Now, let’s show that this is linear by plugging in the two sides of the equation for showing linearity from above and seeing that the results are equal in both cases:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3007.clip_image00216_3E77C1F5.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3007.clip_5F00_image00216_5F00_3E77C1F5.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002[16]" border="0" alt="clip_image002[16]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4578.clip_image00216_thumb_1E5CB538.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4578.clip_5F00_image00216_5F00_thumb_5F00_1E5CB538.gif" width="219" height="29" /></font></a><b></b></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3581.clip_image0046_7E41A87A.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3581.clip_5F00_image0046_5F00_7E41A87A.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image004[6]" border="0" alt="clip_image004[6]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6237.clip_image0046_thumb_3E0B8F00.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6237.clip_5F00_image0046_5F00_thumb_5F00_3E0B8F00.gif" width="283" height="85" /></font></a><b></b></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5460.clip_image0064_4BDDD4FB.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5460.clip_5F00_image0064_5F00_4BDDD4FB.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image006[4]" border="0" alt="clip_image006[4]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5483.clip_image0064_thumb_2FCD1610.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5483.clip_5F00_image0064_5F00_thumb_5F00_2FCD1610.gif" width="158" height="85" /></font></a><b></b></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6153.clip_image008_6B8CAEC3.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6153.clip_5F00_image008_5F00_6B8CAEC3.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image008" border="0" alt="clip_image008" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7624.clip_image008_thumb_36801F93.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7624.clip_5F00_image008_5F00_thumb_5F00_36801F93.gif" width="250" height="29" /></font></a><b></b></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6646.clip_image010_4452658E.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6646.clip_5F00_image010_5F00_4452658E.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image010" border="0" alt="clip_image010" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7217.clip_image010_thumb_0F45D65E.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7217.clip_5F00_image010_5F00_thumb_5F00_0F45D65E.gif" width="372" height="85" /></font></a><b></b></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7230.clip_image012_4B056F11.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7230.clip_5F00_image012_5F00_4B056F11.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image012" border="0" alt="clip_image012" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2425.clip_image012_thumb_43E63299.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2425.clip_5F00_image012_5F00_thumb_5F00_43E63299.gif" width="364" height="72" /></font></a><b></b></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/1447.clip_image014_3CC6F621.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/1447.clip_5F00_image014_5F00_3CC6F621.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image014" border="0" alt="clip_image014" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2018.clip_image014_thumb_35A7B9A9.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2018.clip_5F00_image014_5F00_thumb_5F00_35A7B9A9.gif" width="324" height="85" /></font></a><b></b></p>  <p><font face="Arial">We can see that in either case, we ended up with the same answer. This shows that the scaling transformation is indeed a linear one.</font></p>  <p><font face="Arial">Now, let’s look at an example you may encounter in a game. For this example, let’s say that we are trying to scale up a triangle with vertices (-1, 0, 0), (0, 1, 0), and (1, 0, 0) by a factor of 3 in all directions. I’ve intentionally used simple numbers to make this easier to visualize and show in a blog post. The same concept applies regardless of the numbers. This gives us a matrix with 3 all along the diagonal:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4812.clip_image00218_4379FFA4.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4812.clip_5F00_image00218_5F00_4379FFA4.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002[18]" border="0" alt="clip_image002[18]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6131.clip_image00218_thumb_235EF2E7.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6131.clip_5F00_image00218_5F00_thumb_5F00_235EF2E7.gif" width="95" height="71" /></font></a><b></b></p>  <p><font face="Arial">To scale our triangle, we would need to multiply each vertex by the scale matrix:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6153.clip_image00220_6E5263B6.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6153.clip_5F00_image00220_5F00_6E5263B6.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002[20]" border="0" alt="clip_image002[20]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5076.clip_image00220_thumb_7C24A9B1.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5076.clip_5F00_image00220_5F00_thumb_5F00_7C24A9B1.gif" width="238" height="71" /></font></a><b></b></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0361.clip_image0048_22F2BFF2.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0361.clip_5F00_image0048_5F00_22F2BFF2.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image004[8]" border="0" alt="clip_image004[8]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3007.clip_image0048_thumb_1BD3837A.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3007.clip_5F00_image0048_5F00_thumb_5F00_1BD3837A.gif" width="206" height="71" /></font></a><b></b></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8306.clip_image0066_14B44702.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8306.clip_5F00_image0066_5F00_14B44702.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image006[6]" border="0" alt="clip_image006[6]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2043.clip_image0066_thumb_3B825D42.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2043.clip_5F00_image0066_5F00_thumb_5F00_3B825D42.gif" width="206" height="71" /></font></a><b></b></p>  <p><font face="Arial">This gives us the 3 scaled vertices we expect: (-3, 0, 0), (0, 3, 0), and (3, 0, 0).</font></p>  <h4>Rotation</h4>  <p><font face="Arial">The other linear transformation we’ll look at is rotation. Rotation consists of an <em>axis of rotation</em>, and the <em>angle of rotation</em>. When looking directly into the axis of rotation (the axis is pointing towards you), the rotation angle is measured <em>counterclockwise</em>. We’ll start by examining the matrix representations of rotations about the axes of the standard basis (<strong><em>i</em></strong>, <strong><em>j</em></strong>, and <strong><em>k</em></strong>). Then, we’ll&#160; show linearity and solve an example. </font></p>  <p><font face="Arial">Let’s start by looking at the matrix for rotation about the <strong><em>i, j, </em></strong>and<strong><em> k</em></strong> vectors (axes). These are sometimes referred to as <em>pitch, yaw,</em> and <em>roll</em> respectively<em>.</em></font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6237.clip_image00228_4954A33D.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6237.clip_5F00_image00228_5F00_4954A33D.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002[28]" border="0" alt="clip_image002[28]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8132.clip_image00228_thumb_423566C5.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8132.clip_5F00_image00228_5F00_thumb_5F00_423566C5.gif" width="255" height="71" /></font></a></p> <b><font face="Arial"></font></b>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3326.clip_image00416_3B162A4D.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3326.clip_5F00_image00416_5F00_3B162A4D.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image004[16]" border="0" alt="clip_image004[16]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2330.clip_image00416_thumb_33F6EDD5.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2330.clip_5F00_image00416_5F00_thumb_5F00_33F6EDD5.gif" width="255" height="72" /></font></a></p> <b><font face="Arial"></font></b>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7624.clip_image00614_2CD7B15D.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7624.clip_5F00_image00614_5F00_2CD7B15D.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image006[14]" border="0" alt="clip_image006[14]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3823.clip_image00614_thumb_3AA9F758.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3823.clip_5F00_image00614_5F00_thumb_5F00_3AA9F758.gif" width="259" height="72" /></font></a></p>  <p><font face="Arial">We can then combine these through concatenation to form a general rotation matrix representing the combined rotations. However, we’ve seen that concatenation is order dependent, so we must be careful which order we combine them in. Combining pitch, then yaw, then roll may give a different result from combining as yaw, then pitch, then roll. There’s not really any standard for the order in which they’re combined, so be sure to stay consistent.</font></p>  <p><font face="Arial">So, are rotations linear transformations? I’ve said that they are, but let’s show that this is the case. We’ll show this for one of the rotations above, but the same thing can be done for each of them:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7217.clip_image00230_338ABAE0.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7217.clip_5F00_image00230_5F00_338ABAE0.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002[30]" border="0" alt="clip_image002[30]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/1854.clip_image00230_thumb_2C6B7E68.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/1854.clip_5F00_image00230_5F00_thumb_5F00_2C6B7E68.gif" width="407" height="76" /></font></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6253.clip_image00418_682B171B.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6253.clip_5F00_image00418_5F00_682B171B.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image004[18]" border="0" alt="clip_image004[18]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/1447.clip_image00418_thumb_610BDAA3.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/1447.clip_5F00_image00418_5F00_thumb_5F00_610BDAA3.gif" width="350" height="90" /></font></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6746.clip_image00232_59EC9E2B.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6746.clip_5F00_image00232_5F00_59EC9E2B.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002[32]" border="0" alt="clip_image002[32]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5460.clip_image00232_thumb_67BEE426.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5460.clip_5F00_image00232_5F00_thumb_5F00_67BEE426.gif" width="160" height="29" /></font></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5483.clip_image0087_47A3D769.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5483.clip_5F00_image0087_5F00_47A3D769.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image008[7]" border="0" alt="clip_image008[7]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4405.clip_image0087_thumb_2B93187E.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4405.clip_5F00_image0087_5F00_thumb_5F00_2B93187E.gif" width="501" height="72" /></font></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7142.clip_image0105_39655E79.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7142.clip_5F00_image0105_5F00_39655E79.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image010[5]" border="0" alt="clip_image010[5]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8713.clip_image0105_thumb_32462201.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8713.clip_5F00_image0105_5F00_thumb_5F00_32462201.gif" width="414" height="79" /></font></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2450.clip_image0125_59143841.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2450.clip_5F00_image0125_5F00_59143841.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image012[5]" border="0" alt="clip_image012[5]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8132.clip_image0125_thumb_667A4B47.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8132.clip_5F00_image0125_5F00_thumb_5F00_667A4B47.gif" width="405" height="85" /></font></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3010.clip_image00419_3820C59A.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3010.clip_5F00_image00419_5F00_3820C59A.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image004[19]" border="0" alt="clip_image004[19]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3823.clip_image00419_thumb_5EEEDBDA.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3823.clip_5F00_image00419_5F00_thumb_5F00_5EEEDBDA.gif" width="350" height="90" /></font></a></p>  <p><font face="Arial">As we can see, both ways lead to the same result, which confirms that rotations are in fact linear transformations.</font></p>  <p><font face="Arial">Finally, let’s consider an example with real numbers. Let’s say we have a vector<strong> u</strong> = (3, 4, 5). We want to rotate this vector by 45<sup>o</sup> counterclockwise about the <strong><em>i</em></strong> vector, then 30<sup>o</sup> counterclockwise about the <strong><em>j</em></strong> vector:</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/1778.clip_image00234_05BCF21B.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/1778.clip_5F00_image00234_5F00_05BCF21B.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002[34]" border="0" alt="clip_image002[34]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0702.clip_image00234_thumb_65A1E55D.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0702.clip_5F00_image00234_5F00_thumb_5F00_65A1E55D.gif" width="70" height="71" /></font></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7658.clip_image00422_5E82A8E5.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7658.clip_5F00_image00422_5F00_5E82A8E5.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image004[22]" border="0" alt="clip_image004[22]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0876.clip_image00422_thumb_3E679C28.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0876.clip_5F00_image00422_5F00_thumb_5F00_3E679C28.gif" width="113" height="47" /></font></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6175.clip_image00618_1E4C8F6B.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6175.clip_5F00_image00618_5F00_1E4C8F6B.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image006[18]" border="0" alt="clip_image006[18]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6746.clip_image00618_thumb_69@3A.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6746.clip_5F00_image00618_5F00_thumb_5F00_6940003A.gif" width="115" height="47" /></font></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5078.clip_image0089_77124635.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5078.clip_5F00_image0089_5F00_77124635.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image008[9]" border="0" alt="clip_image008[9]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6558.clip_image0089_thumb_6FF309BD.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6558.clip_5F00_image0089_5F00_thumb_5F00_6FF309BD.gif" width="256" height="71" /></font></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0285.clip_image0107_68D3CD45.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0285.clip_5F00_image0107_5F00_68D3CD45.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image010[7]" border="0" alt="clip_image010[7]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5584.clip_image0107_thumb_249365F9.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5584.clip_5F00_image0107_5F00_thumb_5F00_249365F9.gif" width="257" height="72" /></font></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6165.clip_image0127_1D742981.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6165.clip_5F00_image0127_5F00_1D742981.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image012[7]" border="0" alt="clip_image012[7]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4011.clip_image0127_thumb_68679A50.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4011.clip_5F00_image0127_5F00_thumb_5F00_68679A50.gif" width="168" height="32" /></font></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8306.clip_image0145_484C8D93.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8306.clip_5F00_image0145_5F00_484C8D93.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image014[5]" border="0" alt="clip_image014[5]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8228.clip_image0145_thumb_040C2647.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8228.clip_5F00_image0145_5F00_thumb_5F00_040C2647.gif" width="195" height="71" /></font></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2055.clip_image016_7CECE9CE.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2055.clip_5F00_image016_5F00_7CECE9CE.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image016" border="0" alt="clip_image016" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0207.clip_image016_thumb_75CDAD56.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0207.clip_5F00_image016_5F00_thumb_5F00_75CDAD56.gif" width="435" height="116" /></font></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/1768.clip_image018_1C9BC397.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/1768.clip_5F00_image018_5F00_1C9BC397.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image018" border="0" alt="clip_image018" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4405.clip_image018_thumb_157C871F.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4405.clip_5F00_image018_5F00_thumb_5F00_157C871F.gif" width="431" height="78" /></font></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0714.clip_image020_0E5D4AA7.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0714.clip_5F00_image020_5F00_0E5D4AA7.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image020" border="0" alt="clip_image020" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3441.clip_image020_thumb_073E0E2F.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3441.clip_5F00_image020_5F00_thumb_5F00_073E0E2F.gif" width="311" height="72" /></font></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6177.clip_image022_42FDA6E2.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6177.clip_5F00_image022_5F00_42FDA6E2.gif"><font face="Arial"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6253.clip_image022_54DA3AAF.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6253.clip_5F00_image022_5F00_54DA3AAF.gif"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="clip_image022" border="0" alt="clip_image022" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7242.clip_image022_thumb_429173ED.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7242.clip_5F00_image022_5F00_thumb_5F00_429173ED.gif" width="221" height="72" /></a></font></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5187.clip_image024_3B723775.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5187.clip_5F00_image024_5F00_3B723775.gif"><font face="Arial"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image024" border="0" alt="clip_image024" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5078.clip_image024_thumb_1B572AB8.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5078.clip_5F00_image024_5F00_thumb_5F00_1B572AB8.gif" width="132" height="72" /></font></a></p>  <p><font face="Arial">And that gives us the new vector after the two rotations: (5.7795, –0.707, 2.3285).</font></p>  <p><font face="Arial">To wrap up, we’ve discussed transformations in general and looked at a special class of transformations known as linear transformations. We’ve looked at the two most common linear transformations in video games, scale and rotation. In the next installment of the math primer series, we’ll discuss affine transformations. As always, please let me know if there’s anything that I can help to explain better. </font></p> <font face="Arial"></font>]]></content:encoded>
    </item>
    <item>
      <title>Intro to Physics in Games</title>
      <link>https://docs.microsoft.com/archive/blogs/rezanour/intro-to-physics-in-games</link>
      <pubDate>Sun, 02 Oct 2011 16:35:30 GMT</pubDate>
      <dc:creator><![CDATA[Reza Nourai]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/rezanour/2011/10/02/intro-to-physics-in-games/</guid>
      <description><![CDATA[I’ve decided to try something a bit different and mix in physics posts while I wrap up the math...]]></description>
      <content:encoded><![CDATA[<p>I’ve decided to try something a bit different and mix in physics posts while I wrap up the math primer. Many of you might be more interested in the physics, or may already be familiar with the math topics, so this gives me a chance to have something for everyone.</p>  <p>Today, we’ll look at some of the core concepts around physics simulations in video games. We’ll go over some terminology and approaches so that we’re all on the same page when discussing more involved topics in later posts. First off, we’ll discuss what it means to have physics in a video game, and how does that compare with physical simulation in other software fields. Then, we’ll discuss the basic steps in simulating physics in a game, and how it integrates with the rest of the game code. </p>  <p>&#160;</p>  <h4><font color="#4f81bd">Physics in Video Games</font></h4>  <p>Video games have become incredibly complicated pieces of software over the past 20 years. I recall a time when PC games could fit on a single density 720KB 5.25” floppy disk. Several years later when CDs were initially becoming available, you could find a single CD with over 1000 games on it! These games ran at measly 320x240 resolutions with 8 or 16 colors. </p>  <p>Today, games easily weigh in at several gigabytes, with many being tens of gigabytes. They have nearly photo-realistic graphics with incredibly high resolutions. Along with that extra visual realism comes an expectation of <em>immersion </em>from the user. The point of having incredibly realistic graphics is to make the player <em>feel</em>&#160; like they’re actually in the game. However, for the illusion to hold, the virtual world around them must also <em>behave </em>in a believable manner. The best graphics in the world wouldn’t make a player feel like they’re actually immersed if the characters move unnaturally, pass through walls or floors, or things don’t fall and topple as if they had realistic mass and material properties. These are just some of the challenges of making the world feel believable.</p>  <p>Physical simulation software is nothing new, and has been used for decades for scientific research and study. Even the use of physics in games isn’t entirely new, though it’s gotten a lot more attention in recent years. Even some of the earliest games, such as Pong, had very primitive physics simulations in the sense that the trajectory of the ball bouncing off the paddles was determined in a way that would seem intuitive and consistent with our understanding of physics. What is new, however, is the recent adoption of general purpose physics simulations in video games. The physics in early games was very much written for the specific scenarios of that game. For example, it could handle projecting the trajectory of a ball off of a paddle, but nothing else. This meant that for each new effect the game wanted to have, a new piece of physics code would have to be written to handle it. Additionally, a new game written would have to have new physics code written for it as well. As game worlds became more complicated, the need for more physical scenarios increased, and the cost of writing specialized functions for each scenario became too prohibitive. During this time, the concept of having a general purpose piece of code that, given some overall parameters, could simulate arbitrary physical conditions and scenarios came to be. These general purpose physics <em>engines</em> could allow game developers to create games with many more interesting scenarios, and do it much more quickly.</p>  <p>Before moving on to discussing the anatomy of these physics engines, there’s one more important point to consider. Physics simulations are just that, simulations. Physics, <em>in general</em>, is very complex and not possible to replicate in code. However, if we take certain core aspects or principles of physics, and simulate them with some acceptable level of accuracy, then performing this in code becomes much more reasonable. The most common class of physics simulated in games is called Rigid Body Dynamics. Rigid body simulations use Newtonian principles of movement and mass to simulate rigid objects (spheres, boxes, a tower, a boulder, a wall, etc…). In games, the physical accuracy of the simulation only needs to be high enough to be believable, and is often times reduced to improve performance. A smooth running, albeit slightly less accurate, game is much more immersive than a perfectly accurate game that runs poorly and constantly drops frames.</p>  <h4><font color="#4f81bd"></font></h4>  <h4><font color="#4f81bd">Basic Components of Physics Engines</font></h4>  <p>There are many different physics engines out on the market today. Each one works somewhat differently than the next, and each uses different approaches to solving the general physics problem for games. However, in order to solve the problem for games, there are certain things that every engine must do. For the purposes of this post, we’ll be focusing on rigid body dynamics as it’s the most common type of physics in games. I’ll try and include posts later to discuss other types of simulations such as cloth, fluid, or gas. All of the components of the physics engine can be summarized in a single general operation called the <em>simulation step</em>.</p>  <p>Video games display many rendered frames per second. Comparing this to animation, many small in-between images are shown quickly to give the impression of movement. The de facto standard for most PC and console games is to target 60fps, which means that each frame represents about 0.01667s of time. For the physics simulation to match, only 0.01667s worth of physics should happen each frame. That means an object moving forward at a velocity of 1m/s should only move 0.01667 meters that frame, and then again the next frame, and then again, and finally after 60 frames have gone by, the object would have covered 1 meter of distance.</p>  <p>These intervals of moving objects along their trajectories is called the physics simulation step. Almost every physics simulation equation involves time, and the time used for solving these is this time slice determined by the game. Most engines will take in the time as a value each frame, as it could change from frame to frame. Some games use variable frame rates, and so a static number should never be assumed.</p>  <p>So, what exactly <em>happens </em>during the simulation step? </p>  <h6>Integration</h6>  <p>A typical physics engine normally tracks all the objects that it’s simulating in a data structure somewhere. For simplicity let’s call it a list, though this isn’t always the case. For each object, the physics engine needs to know some important information, such as it’s mass, current velocity, current position and orientation, and outside forces acting on the object. Each step, the <em>integration </em>portion of the physics code will <em>solve </em>for the new current positions and velocities for every object. This involves using equations of motion from physics to approximate the positions and velocities for an object in some future time (current time plus the time slice for the frame), using the current positions and velocities as starting points. In addition, outside forces such as gravity, springs, friction, or anything else relevant to the game are also considered to ensure the newly computed positions and velocities make sense.</p>  <h6>Collision Detection</h6>  <p>If there were only a single object moving in a vacuum, then we’d be done! However, most games involve more than one object, and these objects move in interesting environments. Therefore, there arises a situation where two objects are moving towards each other or end up running into each other. What happens? If we don’t do anything, these objects will just pass right through each other. The renderer certainly has no knowledge that these are separate, solid objects that shouldn’t overlap. It will happily draw them intersecting each other. In most games, however, you don’t want the objects to pass through each other. An asteroid colliding with a ship should crash into it, possibly destroying the ship. A character walking on top of a floor should stay above it, gravity shouldn’t pull the character down through the ground. In order to handle these scenarios, the game needs to know that<em> </em>two objects are overlapping. The process of identifying these scenarios is called <em>collision detection</em>, and is normally one of the other major tasks the physics code must do. Generally, the job of the collision detection code is to determine all such pairs of overlapping objects, possibly including some additional data such as how far they overlap and in what orientation, and providing this data to the game for further processing.</p>  <h6>Collision Resolution</h6>  <p>Once the physics engine has identified that a pair (or many pairs) of objects are overlapping, then what do we do? In many cases, this is something specific to the rules of the game. For instance, in a space shooter game, when an asteroid overlaps the player’s ship, the game may decide to stop drawing the player’s ship and instead draw an explosion animation. Following that, the game would probably start the level over and reduce the number of lives of the player. All of these reactions to the collision are driven entirely by the game itself, and not the physics engine. This is because they are very specific to the game in question. However, there are certainly cases where the game doesn’t care to be involved. For instance, in a first person shooter, if the player knocks over a chair in a room, the game doesn’t need to do anything specific for this case. There are no game rules invoked, and therefore the game just wants the motion of this chair and player to continue to be simulated in a realistic fashion. This likely means the chair falls over in response to being bumped by the player, and when it strikes the floor, it probably rolls or tumbles slightly. This class of reaction is another common, and arguably the most complex, job of the physics engine and is generally referred to as <em>collision response</em> or <em>collision resolution</em>.</p>  <p>We’ve covered the basics of all physics engines. Every simulation suitable for games will have these general components, though it’s common to include many more features such as joints, cloth simulations, physics-based animation, and other interesting things. I’ll be going into a lot more details for each component as we continue to discuss physics in games. I’m planning on presenting a sample architecture for a physics engine, and then drilling into each section piece by piece to discuss the design, why it was designed that way, what algorithms are used, what other alternate algorithms are there, and what optimizations where made and why. I’ll be providing sample code snippets and probably entire posts dedicated to certain algorithms and optimizations. Please note that the architecture used will be something of my own invention, and is not that of any other physics engine out there. While there will certainly be similarities due to the fact that we’re solving the same problem, all of the code and design presented will have been created specifically for the purpose of education on this blog.</p>]]></content:encoded>
    </item>
    <item>
      <title>Math Primer Series: Matrices I: Introduction and Basics Operations</title>
      <link>https://docs.microsoft.com/archive/blogs/rezanour/math-primer-series-matrices-i-introduction-and-basics-operations</link>
      <pubDate>Mon, 05 Sep 2011 18:02:43 GMT</pubDate>
      <dc:creator><![CDATA[Reza Nourai]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/rezanour/2011/09/05/math-primer-series-matrices-i-introduction-and-basics-operations/</guid>
      <description><![CDATA[&#160;  Few things are as ubiquitous in game and graphics programming as a matrix. In this...]]></description>
      <content:encoded><![CDATA[<p>&#160;</p>  <p>Few things are as ubiquitous in game and graphics programming as a matrix. In this installment of the math primer, we take a look at these structures, investigating not only their numerical significance, but also what they represent visually. Next time, we’ll see how to combine them with vectors and with other matrices to form complex transformations, which we rely heavily on in game code.</p>  <h4><font color="#4f81bd">Matrices are the <em>Basis</em> of Everything</font></h4>  <p>When we refer to a coordinate system, we represent the system with a central point (origin), and 2 (for 2D) or 3 (for 3D) linearly independent vectors, also called <em>axes.</em> <a href="http://blogs.msdn.com/b/rezanour/archive/2011/06/26/math-primer-series-vectors-iii-affine-spaces-linear-and-affine-combinations.aspx" target="_blank">Look back to the earlier primer articles for a refresher if you need it</a>. To measure a point with respect to this coordinate system, we use an ordered 2- or 3-tuple, such as (3, 5, 1), which represents starting at the origin, then moving 3 units along the first vector, 5 units along the second vector’s direction, and finally 1 unit along the 3rd vector’s direction. The three vectors used in this way are called a <em>basis</em>. A basis is the set of linearly independent vectors used to define a coordinate system (or more accurately, a coordinate <em>frame</em> or <em>frame of reference</em>). If we label these vectors <strong>u</strong>, <strong>v</strong>, and <strong>w</strong>, then we can write the 3-tuple above as 3<strong>u</strong> + 5<strong>v</strong> + 1<strong>w</strong>. We can even define left or right handedness of the basis by looking at the way we orient the third vector with respect to the first two. Specifically, third here means the one that we write last when expressing the tuple. When someone mentions the <em>standard basis</em>, they’re referring to the set of vectors (normally labeled <strong>i</strong>,<strong> j</strong>, and<strong> k</strong>), where the values are (1, 0, 0), (0, 1, 0), and (0, 0, 1) respectively, normally centered around the origin <strong>O</strong> (0, 0, 0). Let’s take a look at Figure 1 for a more visual representation.</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0488.image_0(91B.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0488.image_5F00_0280091B.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0576.image_thumb_61F8C968.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0576.image_5F00_thumb_5F00_61F8C968.png" width="812" height="641" /></a></p>  <p>Something important to note here is that we can express any basis in <em>terms</em>&#160;<em>of another basis</em>. That means that we can express any basis in terms of the standard basis. If we look at Figure 1 a little more closely, we see that even though<strong> u</strong>, <strong>v</strong>, and<strong> w</strong> are vectors making up a basis, they’re still just vectors, and that means we can express them in terms of <strong>i</strong>, <strong>j</strong>, and<strong> k</strong>. For instance, if we use the basis consisting of <strong>u</strong>, <strong>v</strong>, and <strong>w</strong> as our frame of reference, then <strong>u</strong> would most likely be written as (1, 0, 0). However, using the standard basis as our point of reference, we might measure <strong>u</strong> to be some vector (0.6, 0.6, 0) or something of the like. This is a key concept to keep in mind: basis vectors can all be measured and represented in terms of another basis, including the standard one.</p>  <p>It’s getting a little tedious to constantly keep referring to a basis in a manner such as “the basis consisting of basis vectors <strong>u</strong>, <strong>v</strong>, and <strong>w</strong>”. Wouldn’t it be nice if there was a succinct notation to capture that? Well, there is! We can write the basis vectors in block form, like:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5775.clip_image002_01A7A331.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5775.clip_5F00_image002_5F00_01A7A331.gif"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="clip_image002" border="0" alt="clip_image002" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8004.clip_image002_thumb_2875B971.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8004.clip_5F00_image002_5F00_thumb_5F00_2875B971.gif" width="101" height="29" /></a></p>  <p>Where <strong>u, v, </strong>and <strong>w</strong> are expressed as vectors in terms of the standard basis. This is a matrix, and the expanded form looks like this:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7026.clip_image0024_5A6D59FB.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7026.clip_5F00_image0024_5F00_5A6D59FB.gif"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="clip_image002[4]" border="0" alt="clip_image002[4]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7848.clip_image0024_thumb_534E1D83.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7848.clip_5F00_image0024_5F00_thumb_5F00_534E1D83.gif" width="130" height="72" /></a></p>  <p>Now, we need to clarify a few things here before continuing. The way I’ve laid out the matrix above is not the only correct way to lay out a basis. Just as coordinate systems have left handed and right handed variations, which are just a matter of preference and convention, matrices too have some convention considerations to make. Matrices may be used in what’s called row-major or column-major form, which directly correlates with how you wish to write vectors. Vectors can be written as row-vectors or column-vectors. See Figure 2 for a comparison of the two. It’s important to realize that just as picking one handedness of coordinate system over another had no bearing on the result, just the shape of the formulae, the same is true of how we express our vectors and matrices.</p>  <p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7510.clip_image00210_0147D27C.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7510.clip_5F00_image00210_5F00_0147D27C.gif"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image002[10]" border="0" alt="clip_image002[10]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4466.clip_image00210_thumb_612CC5BE.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4466.clip_5F00_image00210_5F00_thumb_5F00_612CC5BE.gif" width="131" height="32" /></a>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2313.clip_image004_4111B901.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2313.clip_5F00_image004_5F00_4111B901.gif"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image004" border="0" alt="clip_image004" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3884.clip_image004_thumb_20F6AC44.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3884.clip_5F00_image004_5F00_thumb_5F00_20F6AC44.gif" width="44" height="81" /></a></p>  <p><b><font color="#0000ff" size="4" face="Arial">Figure 2: The row-vector on the left is written with the 3 components horizontal. The column vector on the right is written with the 3 components laid out vertically.</font></b></p>  <p>How we write out matrices is directly related to what kind of vectors we use. If we use row vectors, then we lay down our basis vectors as <em>rows</em> of the matrix. If we are using column vectors, then we lay down the basis vectors as <em>columns</em> in the matrix. See Figure 3 below:</p>  <p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2234.clip_image0026_4C2EE10B.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2234.clip_5F00_image0026_5F00_4C2EE10B.gif"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="clip_image002[6]" border="0" alt="clip_image002[6]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5861.clip_image0026_thumb_07EE79BF.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5861.clip_5F00_image0026_5F00_thumb_5F00_07EE79BF.gif" width="129" height="74" /></a>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3113.clip_image0041_19CB0D8C.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3113.clip_5F00_image0041_5F00_19CB0D8C.gif"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="clip_image004[1]" border="0" alt="clip_image004[1]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6740.clip_image0041_thumb_12ABD114.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6740.clip_5F00_image0041_5F00_thumb_5F00_12ABD114.gif" width="130" height="72" /></a></p>  <p><b><font color="#0000ff" size="4" face="Arial">Figure 3: The row-major matrix on the left consists of the basis vectors written as rows of the matrix. The column-major matrix on the right consists of the basis vectors written as columns in the matrix.</font></b></p>  <p>Again, which we choose doesn’t make a difference as long as we are consistent with our convention and form our formulae appropriately for the form we’ve chosen. In mathematics, and most texts on mathematics and graphics, column form is more widespread. However, in the actual game and graphics world things are a little more divided. For instance, DirectX and XNA both use row form, but OpenGL uses column form. You could write an entire library in column form, but still use DirectX or XNA to render, you just need to convert between the forms at the appropriate places. The conversion between the two, called a transpose, will be covered a bit later in this post. </p>  <p>I will choose to use column vector form even though most of my coding examples will likely be either DirectX or XNA. You might think that seems counterintuitive, but I believe writing out mathematics in a manner which is more consistent with academia is more natural, and will match what you find in research papers, math books, and other references around the web. My coding examples are just that: examples. I don’t think it’s justified to form my mathematical explanations around my examples’ choice of graphics API.</p>  <p>NOTE: It is important to realize that this discussion of row versus column major matrix is only relevant when talking about vectors. As we’ll see in a moment, matrices can be used for many other things besides vectors, and in those cases there is only a single form of a matrix. In other words: row major and column major matrices are still the same matrix, we’ve just chosen to impose a convention on <em>how we write vectors in terms of matrices. </em></p>  <h4><font color="#4f81bd">Introduction to Matrices</font></h4>  <p>While it’s convenient to write vectors as single row or column matrices, and basis vectors as the rows or columns of a 9 element square matrix, these are far from the only uses of a matrix. In fact, most formal definitions of a matrix are something along the lines of “a rectangular arrangement of numbers, organized into rows and columns”, which says nothing about vectors. </p>  <p>Let’s try and define matrices a little more generally now. We know that they look like blocks of numbers, and that they are considered to have rows and columns, so let’s add that we can refer to the number of rows and columns as “<em>n</em> by <em>m</em>”, or <em>n</em> x <em>m</em>, where n is the number of rows and m is the number of columns. This is summarized in Figure 4. </p>  <p align="center">&#160;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3480.clip_image0028_4E77CC07.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3480.clip_5F00_image0028_5F00_4E77CC07.gif"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image002[8]" border="0" alt="clip_image002[8]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4061.clip_image0028_thumb_5C4A1202.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4061.clip_5F00_image0028_5F00_thumb_5F00_5C4A1202.gif" width="150" height="47" /></a>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0576.clip_image0043_273D82D2.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0576.clip_5F00_image0043_5F00_273D82D2.gif"><img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image004[3]" border="0" alt="clip_image004[3]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/1731.clip_image0043_thumb_1BA7C593.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/1731.clip_5F00_image0043_5F00_thumb_5F00_1BA7C593.gif" width="60" height="29" /></a>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8686.clip_image0064_6D4E3FE5.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8686.clip_5F00_image0064_5F00_6D4E3FE5.gif"><img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image006[4]" border="0" alt="clip_image006[4]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0257.clip_image0064_thumb_4D333328.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0257.clip_5F00_image0064_5F00_thumb_5F00_4D333328.gif" width="41" height="71" /></a>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6114.clip_image0084_2D18266B.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6114.clip_5F00_image0084_5F00_2D18266B.gif"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image008[4]" border="0" alt="clip_image008[4]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4061.clip_image0084_thumb_0CFD19AE.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4061.clip_5F00_image0084_5F00_thumb_5F00_0CFD19AE.gif" width="95" height="71" /></a></p>  <p><font color="#0000ff" size="4" face="Arial"><strong>Figure 4: Matrices are labeled using <i>row </i>x <i>column</i>. From left to right, the matrix sizes are: 2x3, 1x2, 3x1, and 3x3.</strong></font></p>  <p>We can see from the first matrix in the figure that elements within the matrix are always labeled using the row, then the column number, and are 1-based. The subscripts in the first matrix show the row and column numbers of element a<sub><em>ij</em></sub>. The second and third matrices could be interpreted as row and column vectors, respectively. The final matrix in the figure leads us to a few more definitions.</p>  <p>If the number of rows and columns in a matrix are the same, the matrix is said to be a <em>square matrix.</em> Since the number of rows and columns are the same, we can refer to square matrices with a single size dimension. For instance, we can say something is a dimension 3 square matrix, meaning it’s a 3x3. The set of all elements in the vector for which the row and column are the same (a<sub>11</sub>, a<sub>22</sub>, etc…) is called the <em>diagonal</em> of the matrix. For example, in the rightmost matrix above, the diagonal is the set of numbers (4, 3, 8). If the only non-0 elements in a matrix are within the diagonal, then the matrix is called a <em>diagonal matrix.</em> So, to summarize, our final matrix above can be called a <em>square, diagonal matrix</em>. Finally, as a matter of notation, I’ll use capital, bold, italic letters to represent a matrix. This should make it easier to tell them apart from vectors (bold lowercase) and points (italic capital). For example, a matrix <strong><em>M</em></strong>.</p>  <p>There is a special matrix, called the <em>identity matrix</em>, which is a <em>square, diagonal matrix </em>with only 1s in the diagonal. It can be any size, is normally written as <strong><em>I</em></strong> or<em><strong> I</strong><sub>n</sub> (</em>where n is the size), and we’ll see in a moment that it’s used to ensure multiplicative identity holds (hence, the name).</p>  <p>Now that we have notation and terminology out of the way, let’s start looking at operations we can do with matrices!</p>  <h4><font color="#4f81bd">Basic Matrix Operations</font></h4>  <h5>Transpose</h5>  <p>The most trivial operation we can perform on a matrix is taking it’s transpose. This swaps all the rows of the matrix with all of the columns. If the matrix begins as an n x m matrix, then the transpose is an m x n. The transpose of <strong><em>M</em></strong> is written as <strong><em>M</em></strong><sup>T</sup>. Examples:</p>  <p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5531.clip_image00210_05DDDD36.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5531.clip_5F00_image00210_5F00_05DDDD36.gif"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image002[10]" border="0" alt="clip_image002[10]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3487.clip_image00210_thumb_65C2D078.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3487.clip_5F00_image00210_5F00_thumb_5F00_65C2D078.gif" width="170" height="63" /></a></p>  <p align="center">&#160;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0654.clip_image0047_45A7C3BB.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0654.clip_5F00_image0047_5F00_45A7C3BB.gif"><img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image004[7]" border="0" alt="clip_image004[7]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7510.clip_image0047_thumb_258CB6FE.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7510.clip_5F00_image0047_5F00_thumb_5F00_258CB6FE.gif" width="110" height="40" /></a></p>  <p align="center">&#160;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2705.clip_image0068_335EFCF9.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2705.clip_5F00_image0068_5F00_335EFCF9.gif"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image006[8]" border="0" alt="clip_image006[8]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6507.clip_image0068_thumb_5A2D1339.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6507.clip_5F00_image0068_5F00_thumb_5F00_5A2D1339.gif" width="205" height="72" /></a></p>  <p>There are a few important observations to make. Firstly, if we look back to our discussion on row and column vectors and matrices, then we can see clearly now that to convert between the two we take the transpose. Secondly, it’s important to note that the diagonal of a matrix remains the same after taking it’s transpose. This will always be the case. In fact, many like to think of taking the transpose as taking the reflection of the non-diagonal elements across the diagonal.</p>  <h5>Addition and Subtraction</h5>  <p>Addition and subtraction of two matrices doesn’t come up quite as often in games, but no discussion of matrix operations would be complete without them. Matrix addition can only be done between two matrices of the same exact dimensions, and is a trivial operation of summing the elements at the same location in each:</p>  <p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7178.clip_image00212_3E1C544E.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7178.clip_5F00_image00212_5F00_3E1C544E.gif"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image002[12]" border="0" alt="clip_image002[12]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7181.clip_image00212_thumb_79DBED01.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7181.clip_5F00_image00212_5F00_thumb_5F00_79DBED01.gif" width="393" height="45" /></a></p>  <p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6114.clip_image0049_44CF5DD1.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6114.clip_5F00_image0049_5F00_44CF5DD1.gif"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image004[9]" border="0" alt="clip_image004[9]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7674.clip_image0049_thumb_3DB02159.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7674.clip_5F00_image0049_5F00_thumb_5F00_3DB02159.gif" width="303" height="41" /></a></p>  <p>Subtraction is done in the exact same way, again requiring the matrices be of the same dimension and shape.</p>  <h5>Scalar Multiplication</h5>  <p>Scalar multiplication is as straightforward as can be. Multiplying a matrix <strong><em>M</em></strong> by a scalar <em>s</em> just multiplies each element of the matrix by <em>s</em>.</p>  <h5>Matrix Multiplication</h5>  <p>Multiplying, also called <em>concatenating</em>, two matrices is by far the most common operation done on matrices in game code. We’ll explore why when we talk about transformations later in this post. Multiplying matrices isn’t as straightforward as adding or subtracting, but with a little help visualizing what it is we’re doing, it’s not too bad. Let’s take the following two matrices, <strong><em>A</em></strong> and <strong><em>B</em></strong>.</p>  <p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5531.clip_image00214_796FBA0C.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5531.clip_5F00_image00214_5F00_796FBA0C.gif"><img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image002[14]" border="0" alt="clip_image002[14]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6102.clip_image00214_thumb_2B675A97.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6102.clip_5F00_image00214_5F00_thumb_5F00_2B675A97.gif" width="133" height="41" /></a></p>  <p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0654.clip_image00411_3939A092.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0654.clip_5F00_image00411_5F00_3939A092.gif"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image004[11]" border="0" alt="clip_image004[11]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7510.clip_image00411_thumb_042D1162.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7510.clip_5F00_image00411_5F00_thumb_5F00_042D1162.gif" width="106" height="63" /></a></p>  <p>Multiplication of matrices requires that the number of <em>columns </em>of the first matrix match the number of <em>rows </em>of the second. We can refer to this dimension as <em>d</em>. We can see that our matrices <strong><em>A</em></strong> and <strong><em>B</em></strong> meet that requirement, with <em>d</em> = 3. The resulting matrix from multiplication will have dimensions of <em>n</em> x <em>m</em>, where <em>n</em> is the number of rows in <strong><em>A</em></strong> and <em>m</em> is the number of columns in <strong><em>B</em></strong>. The formal definition of matrix multiplication then is:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8171.clip_image00218_79038717.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8171.clip_5F00_image00218_5F00_79038717.gif"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002[18]" border="0" alt="clip_image002[18]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3365.clip_image00218_thumb_71E44A9F.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3365.clip_5F00_image00218_5F00_thumb_5F00_71E44A9F.gif" width="202" height="67" /></a></p>  <p>Using our example matrices <strong><em>A</em></strong> and <strong><em>B</em></strong> from above:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8664.clip_image00222_6AC50E27.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8664.clip_5F00_image00222_5F00_6AC50E27.gif"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002[22]" border="0" alt="clip_image002[22]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3858.clip_image00222_thumb_78975422.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3858.clip_5F00_image00222_5F00_thumb_5F00_78975422.gif" width="240" height="62" /></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4530.clip_image00415_438AC4F2.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4530.clip_5F00_image00415_5F00_438AC4F2.gif"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image004[15]" border="0" alt="clip_image004[15]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4442.clip_image00415_thumb_515D0AED.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4442.clip_5F00_image00415_5F00_thumb_5F00_515D0AED.gif" width="485" height="47" /></a></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5123.clip_image00224_4A3DCE75.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5123.clip_5F00_image00224_5F00_4A3DCE75.gif"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002[24]" border="0" alt="clip_image002[24]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4035.clip_image00224_thumb_58101470.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4035.clip_5F00_image00224_5F00_thumb_5F00_58101470.gif" width="331" height="41" /></a></p>  <p>By this definition, matrix multiplication is not commutative, since the column and row requirements may not be met, and even if they were, the result would be different. The only matrices which meet the row and column requirements when reversed are square matrices, but again the result of the multiplication is different.</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7587.clip_image00230_50F0D7F8.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7587.clip_5F00_image00230_5F00_50F0D7F8.gif"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002[30]" border="0" alt="clip_image002[30]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6082.clip_image00230_thumb_30D5CB3B.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6082.clip_5F00_image00230_5F00_thumb_5F00_30D5CB3B.gif" width="76" height="25" /></a></p>  <p>While we can certainly think of multiplication in this way, I find it far easier to visualize the multiplication in a more vector-oriented way. If we imagine the rows of the first matrix as vectors (like a row major basis), and the columns of the second matrix as vectors (like a column major basis), then what we’re really doing is taking the dot product of each possible pair of vectors, with the dot product of the <em>i</em>th row of the first matrix and the <em>j</em>th column of the second matrix making up the element m<em><sub>ij</sub></em> in the resulting matrix. In other words:</p>  <p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4848.clip_image00226_10BABE7E.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4848.clip_5F00_image00226_5F00_10BABE7E.gif"><img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image002[26]" border="0" alt="clip_image002[26]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5428.clip_image00226_thumb_42B25F08.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5428.clip_5F00_image00226_5F00_thumb_5F00_42B25F08.gif" width="203" height="41" /></a></p>  <p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/1727.clip_image00417_3B932290.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/1727.clip_5F00_image00417_5F00_3B932290.gif"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image004[17]" border="0" alt="clip_image004[17]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2388.clip_image00417_thumb_4965688B.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2388.clip_5F00_image00417_5F00_thumb_5F00_4965688B.gif" width="188" height="46" /></a></p>  <p align="left">We now can see what the purpose of the identity matrix, <strong><em>I</em></strong>, is. Multiplying any matrix by an identity matrix of the appropriate size, yields the original matrix:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7266.clip_image00228_294A5BCE.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7266.clip_5F00_image00228_5F00_294A5BCE.gif"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002[28]" border="0" alt="clip_image002[28]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3377.clip_image00228_thumb_56CB7B91.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3377.clip_5F00_image00228_5F00_thumb_5F00_56CB7B91.gif" width="57" height="25" /></a></p>  <h5>Multiplying a Matrix and a Vector</h5>  <p>Multiplying a vector by a matrix is called <em>transforming</em> the vector. We’ll look at transformations in the next post in this series, but let’s understand the math behind it first. This is where our discussion of column versus row vectors becomes most relevant. To multiply a vector and a matrix, we treat the vector as a single row or column matrix and multiply as usual. This implies that which side of the matrix the vector goes on is important, and must satisfy the row and column requirements of the multiplication. If our vector is a row vector, then we could write a 3-vector and 3x3 matrix multiplication as:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6014.clip_image00238_565F489C.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6014.clip_5F00_image00238_5F00_565F489C.gif"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002[38]" border="0" alt="clip_image002[38]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7585.clip_image00238_thumb_4F400C24.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7585.clip_5F00_image00238_5F00_thumb_5F00_4F400C24.gif" width="240" height="67" /></a></p>  <p>We could similarly write a column vector multiplied by the same matrix as:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2870.clip_image00240_4820CFAC.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2870.clip_5F00_image00240_5F00_4820CFAC.gif"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002[40]" border="0" alt="clip_image002[40]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7178.clip_image00240_thumb_41019334.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7178.clip_5F00_image00240_5F00_thumb_5F00_41019334.gif" width="175" height="68" /></a></p>  <p>Notice that the vector is on the other side of the matrix. This is required to make the multiplication work. Looking at the expressions above, the product of the multiplication would be different in each case. However, we know intuitively that transforming a vector by a matrix can only have a single answer, and that our choice to use row or column vectors shouldn’t impact the result. In order to move the vector from one side of the matrix to the other to satisfy the multiplication requirements, we must also <em>transpose</em> our matrix to ensure that the <em>result</em> remains the same. If we do that, the product of the multiplication will be the same regardless of whether we choose row vectors or column vectors. This is exactly what we were talking about up above in the basis section. So the correct form for the second equation becomes:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8640.clip_image00242_4ED3D92F.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8640.clip_5F00_image00242_5F00_4ED3D92F.gif"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="clip_image002[42]" border="0" alt="clip_image002[42]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0310.clip_image00242_thumb_19C749FF.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0310.clip_5F00_image00242_5F00_thumb_5F00_19C749FF.gif" width="176" height="68" /></a></p>  <p>Which will ensure we get the same result as the first case.</p>  <p>There are many more operations we can do with matrices, and I’ll cover some as we go through the next few blog posts. But for now, we have enough covered that we can start to look at linear transformations. The next installment will start our exploration of transformations, beginning with linear transformations. I hope you enjoyed the introduction of matrices, and as always let me know if there’s anything you’d like to see me explain in more detail.</p>]]></content:encoded>
    </item>
    <item>
      <title>Barycentric Coordinates and Point in Triangle Tests</title>
      <link>https://docs.microsoft.com/archive/blogs/rezanour/barycentric-coordinates-and-point-in-triangle-tests</link>
      <pubDate>Sun, 07 Aug 2011 13:50:00 GMT</pubDate>
      <dc:creator><![CDATA[Reza Nourai]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/rezanour/2011/08/07/barycentric-coordinates-and-point-in-triangle-tests/</guid>
      <description><![CDATA[&nbsp;
I know it&rsquo;s been a little while since my last post, and I apologize. I&rsquo;ll try...]]></description>
      <content:encoded><![CDATA[<p>&nbsp;</p>
<p>I know it&rsquo;s been a little while since my last post, and I apologize. I&rsquo;ll try and keep the posts a little more frequent moving forward.</p>
<p>In the last post, we briefly encountered barycentric coordinates and loosely defined them as the coefficients of an affine combination. While that&rsquo;s true, we can do better. We can define a more precise definition, and we can take a closer look at what they really mean, both numerically and geometrically. That&rsquo;s the topic of this post, as well as taking a brief look at how we could use them in a real world game programming context.</p>
<p>First, let&rsquo;s take a look at the formal definition of the coordinates, then we&rsquo;ll consider a slightly refactored version that works better for our situations. Consider a triangle ABC (see Figure 1), and then imagine a little weight at each vertex. We can assign each weight as having 100% weight contribution from that vertex, and 0 contribution from the other vertices. So, for point A that&rsquo;s (1, 0, 0), for point B it&rsquo;s (0, 1, 0), and for point C it&rsquo;s (0, 0, 1). This means that if you&rsquo;re at the vertex, you only get the weight from that 1 vertex. Anywhere else within the triangle would be a combination of these weights. The <em>barycenter</em> of the triangle is the point inside the triangle where you could balance the weights. In other words, the weights would be contributing evenly to that point. Assuming that the weights at each vertex are equal (1), this would be the mean of the weights (or vertices):</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4834.clip_image002_4CF7{.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4834.clip_5F00_image002_5F00_4CF77B00.gif"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px; border-width: 0px;" title="clip_image002" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5023.clip_image002_thumb_2C703B4E.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5023.clip_5F00_image002_5F00_thumb_5F00_2C703B4E.gif" alt="clip_image002" width="162" height="45" border="0" /></a><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8267.image_37547564.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8267.image_5F00_37547564.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px; border-width: 0px;" title="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5050.image_thumb_41A599C4.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5050.image_5F00_thumb_5F00_41A599C4.png" alt="image" width="803" height="628" border="0" /></a></p>
<p>The barycentric coordinates for the barycenter then become (1/3, 1/3, 1/3) given our equation above. Notice that this is exactly the equation of an affine combination, which is why we stated that the coefficients of an affine combination are also the barycentric coordinates. The dashed lines in the image represent the barycentric axes. A barycentric axis starts on a triangle edge, where the weight for the opposite vertex is 0. They then extend through the barycenter of the triangle to the opposite vertex, where the weight for that vertex is 1. Notice that the other coordinates in the base of each axis are 1/2. This is just a coincidence since we happen to be looking at an equilateral triangle. This won&rsquo;t hold true for other kinds of triangles.</p>
<p>Now, what else can we observe? Well, for each axis, our values only extend from 0 to 1, since they are weights of that vertex. In other words, a value less than 0 or greater than 1 would be outside of our simplex (triangle in this case). Furthermore, the sum of the coordinates is necessarily equal to 1. Since these coordinates represent the amounts of each weight that you observe at that point, they are percentages, and therefore must sum up to the total. Otherwise, you&rsquo;d be missing some of the weight from the system. These two observations will be extremely helpful as we examine uses in game code. The other thing I wanted to mention here is that if the restriction that coefficients of an affine combination must sum up to 1 didn&rsquo;t make sense after my explanation before, I hope that looking at it from the perspective of barycentric coordinates helps to justify the restriction.</p>
<p>&nbsp;</p>
<p>Now that we&rsquo;ve examined the formal definition and use of barycentric coordinates, let&rsquo;s take a slightly modified look at them, and see how we can make them more useful to us as game developers. We saw in the last post that any affine combination could be refactored and expressed as a single point, or origin, added to a linear combination. Let&rsquo;s take our barycentric equation (which is an affine combination) and refactor it in this way now, using s, r, and t as our barycentric coordinates (coefficients):</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4863.clip_image0026_360FDC85.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4863.clip_5F00_image0026_5F00_360FDC85.gif"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image002[6]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7610.clip_image0026_thumb_19FF1D9A.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7610.clip_5F00_image0026_5F00_thumb_5F00_19FF1D9A.gif" alt="clip_image002[6]" width="142" height="25" border="0" /></a></p>
<p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8270.clip_image004_55BEB64D.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8270.clip_5F00_image004_5F00_55BEB64D.gif"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image004" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4786.clip_image004_thumb_4E9F79D5.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4786.clip_5F00_image004_5F00_thumb_5F00_4E9F79D5.gif" alt="clip_image004" width="105" height="25" border="0" /></a></p>
<p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7026.clip_image006_151C69DE.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7026.clip_5F00_image006_5F00_151C69DE.gif"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image006" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2804.clip_image006_thumb_7FBEB475.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2804.clip_5F00_image006_5F00_thumb_5F00_7FBEB475.gif" alt="clip_image006" width="105" height="25" border="0" /></a></p>
<p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8203.clip_image008_7F528180.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8203.clip_5F00_image008_5F00_7F528180.gif"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image008" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0763.clip_image008_thumb_0D24C77C.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0763.clip_5F00_image008_5F00_thumb_5F00_0D24C77C.gif" alt="clip_image008" width="221" height="25" border="0" /></a></p>
<p>&nbsp;</p>
<p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4382.clip_image010_06058B04.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4382.clip_5F00_image010_5F00_06058B04.gif"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image010" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0576.clip_image010_thumb_7EE64E8B.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0576.clip_5F00_image010_5F00_thumb_5F00_7EE64E8B.gif" alt="clip_image010" width="219" height="25" border="0" /></a></p>
<p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8508.clip_image012_77C71213.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8508.clip_5F00_image012_5F00_77C71213.gif"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image012" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0160.clip_image012_thumb_0599580F.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0160.clip_5F00_image012_5F00_thumb_5F00_0599580F.gif" alt="clip_image012" width="234" height="25" border="0" /></a></p>
<p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8182.clip_image00214_136B9E0A.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8182.clip_5F00_image00214_5F00_136B9E0A.gif"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image002[14]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2728.clip_image00214_thumb_775ADF1E.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2728.clip_5F00_image00214_5F00_thumb_5F00_775ADF1E.gif" alt="clip_image002[14]" width="99" height="25" border="0" /></a></p>
<p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5556.clip_image00410_1E28F55F.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5556.clip_5F00_image00410_5F00_1E28F55F.gif"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image004[10]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0741.clip_image00410_thumb_44F70B9F.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0741.clip_5F00_image00410_5F00_thumb_5F00_44F70B9F.gif" alt="clip_image004[10]" width="97" height="25" border="0" /></a></p>
<p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0763.clip_image0066_3DD7CF27.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0763.clip_5F00_image0066_5F00_3DD7CF27.gif"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image006[6]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6840.clip_image0066_thumb_4BAA1522.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6840.clip_5F00_image0066_5F00_thumb_5F00_4BAA1522.gif" alt="clip_image006[6]" width="133" height="25" border="0" /></a></p>
<p>We&rsquo;ve substituted u and v as (B-A) and (C-A), respectively. Relating our result to the figure above, we see that we&rsquo;ve picked A as our local origin, and two of the triangle&rsquo;s edges as u and v. Our barycentric coordinates have been reduced to just r and t, and are now expressed relative to the local origin A. It&rsquo;s important to note that mathematically, this &lsquo;reduced&rsquo; form of the barycentric coordinates is equivalent to the formal version, but this format is much more usable to us. Because r and t are still barycentric coordinates, they must still fall between 0 and 1, and their sum still cannot exceed 1. Notice that we said exceed this time, and not sum up to 1. This is a subtle difference than before, and it can be explained like this: previously, we had the sum of s, r, and t = 1. This still must hold true. However, we&rsquo;ve made s <em>implicit</em> in our new reduced form, and therefore it is not directly included in our sum. If r and t sum up to 1, then s is 0. However, r and t can sum to less than 1, and s will be equal to the remainder (see the second and third steps of how we arrived to our reduced form). In summary:</p>
<p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5852.clip_image00210_448AD8AA.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5852.clip_5F00_image00210_5F00_448AD8AA.gif"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image002[10]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5875.clip_image00210_thumb_3D6B9C32.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5875.clip_5F00_image00210_5F00_thumb_5F00_3D6B9C32.gif" alt="clip_image002[10]" width="221" height="25" border="0" /></a></p>
<p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2728.clip_image0046_364C5FBA.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2728.clip_5F00_image0046_5F00_364C5FBA.gif"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image004[6]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8015.clip_image0046_thumb_63CD7F7D.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8015.clip_5F00_image0046_5F00_thumb_5F00_63CD7F7D.gif" alt="clip_image004[6]" width="74" height="25" border="0" /></a></p>
<p>Now let&rsquo;s see how we can use this. Imagine we&rsquo;re trying to write a function in our game that determines whether or not a point is contained within a triangle. This is actually quite the common problem to solve in collision detection. In two dimensions, it might be a direct collision detection query. In three dimensions, we normally will first determine if a point is in the plane of a triangle, and if so, then reduce it to a two dimensional problem exactly like the normal 2D case. In either situation, we need a robust way to determine if a point is contained within a triangle. We can use barycentric coordinates in the reduced form to solve this, by taking the following steps:</p>
<p>1. Pick a vertex of the triangle to be our local origin, which we&rsquo;ll refer to as A</p>
<p>2. Compute u and v using the differences of the other two vertices and our origin as we did above (ex: u = B-A, v = C-A)</p>
<p>3. Compute the r and t barycentric values for our point P with respect to A</p>
<p>4. Check that r and t are both within 0 and 1, and that their sum is less than or equal to 1. If so, return true. Otherwise, the point is outside, return false.</p>
<p>It&rsquo;s actually quite straightforward, with the exception that we haven&rsquo;t yet discussed how you&rsquo;d complete step 3, computing the barycentric coordinates. Let&rsquo;s take a look at that now, and then with r and t computed, we&rsquo;ll be able to complete the function. There are several approaches to finding the barycentric coordinates in this step. The simpler of the two uses some identities and properties of vectors we&rsquo;ve covered up to this point, which is why I&rsquo;ll choose to show that one now. However, after we take a good look at matrices and solving systems of linear equations with them, we&rsquo;ll see that there&rsquo;s a more efficient way to compute them. See Figure 2 to see the problem we&rsquo;re trying to solve.</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6825.image_7589F614.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6825.image_5F00_7589F614.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px; border: 0px;" title="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3716.image_thumb_1BEBD960.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3716.image_5F00_thumb_5F00_1BEBD960.png" alt="image" width="799" height="779" border="0" /></a></p>
<p>Let&rsquo;s start by refactoring our equation slightly, and move the A over to the other side:</p>
<p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7823.clip_image00216_03955F1B.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7823.clip_5F00_image00216_5F00_03955F1B.gif"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image002[16]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8484.clip_image00216_thumb_7F1EDE53.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8484.clip_5F00_image00216_5F00_thumb_5F00_7F1EDE53.gif" alt="clip_image002[16]" width="133" height="25" border="0" /></a></p>
<p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4682.clip_image00412_77FFA1DB.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4682.clip_5F00_image00412_5F00_77FFA1DB.gif"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image004[12]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3034.clip_image00412_thumb_42F312AB.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3034.clip_5F00_image00412_5F00_thumb_5F00_42F312AB.gif" alt="clip_image004[12]" width="85" height="25" border="0" /></a></p>
<p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4505.clip_image0068_7EB2AB5E.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4505.clip_5F00_image0068_5F00_7EB2AB5E.gif"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image006[8]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6232.clip_image0068_thumb_77936EE6.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6232.clip_5F00_image0068_5F00_thumb_5F00_77936EE6.gif" alt="clip_image006[8]" width="101" height="25" border="0" /></a></p>
<p>We&rsquo;ve replaced P-A with the vector w. We need to now solve for r and t. If we look at some of the vector rules that we covered earlier, we&rsquo;ll remember that any vector crossed with itself (or any collinear vector) will result in the 0 vector. So, to eliminate t, let&rsquo;s take the cross product of both sides with v:</p>
<p>&nbsp;</p>
<p align="center">&nbsp;</p>
<p align="center">&nbsp;</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4073.clip_image0084_0EC56D83.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4073.clip_5F00_image0084_5F00_0EC56D83.gif"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px; border-width: 0px;" title="clip_image008[4]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3005.clip_image0084_thumb_07A6310B.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3005.clip_5F00_image0084_5F00_thumb_5F00_07A6310B.gif" alt="clip_image008[4]" width="231" height="25" border="0" /></a></p>
<p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0172.clip_image0104_5299A1DA.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0172.clip_5F00_image0104_5F00_5299A1DA.gif"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image010[4]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/1643.clip_image0104_thumb_0E593A8E.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/1643.clip_5F00_image0104_5F00_thumb_5F00_0E593A8E.gif" alt="clip_image010[4]" width="198" height="25" border="0" /></a></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/6835.clip_image0021_0283D626.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/6835.clip_5F00_image0021_5F00_0283D626.gif"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px; border: 0px;" title="clip_image002[1]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/5857.clip_image0021_thumb_6268C968.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/5857.clip_5F00_image0021_5F00_thumb_5F00_6268C968.gif" alt="clip_image002[1]" width="81" height="43" border="0" /></a></p>
<p>&nbsp;</p>
<p align="left">We can see that by having the cross product of v with itself go to the 0 vector, we were able to eliminate t from the equation and solve for r. We can repeat this same process for t to obtain:</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3704.clip_image0023_2D5C3A38.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3704.clip_5F00_image0023_5F00_2D5C3A38.gif"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px; border: 0px;" title="clip_image002[3]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/1651.clip_image0023_thumb_3B2E8033.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/1651.clip_5F00_image0023_5F00_thumb_5F00_3B2E8033.gif" alt="clip_image002[3]" width="85" height="43" border="0" /></a></p>
<p align="left">At this point, we can determine whether or not r and t are going to be greater than 0 or not. This is the first requirement of our test. The equations for r and t above represent ratios between two cross products. The two cross products each represent a vector, so in other words we&rsquo;re taking the ratio of two vectors. The only way r or t can be negative is if these vectors point in opposite directions. So, let&rsquo;s use the dot product to determine if the numerator and denominator in each case point in the same direction:</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3113.clip_image0025_6D2620BD.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3113.clip_5F00_image0025_5F00_6D2620BD.gif"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px; border: 0px;" title="clip_image002[5]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4774.clip_image0025_thumb_4D0B1400.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4774.clip_5F00_image0025_5F00_thumb_5F00_4D0B1400.gif" alt="clip_image002[5]" width="222" height="25" border="0" /></a></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2630.clip_image0041_08CAACB4.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2630.clip_5F00_image0041_5F00_08CAACB4.gif"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px; border: 0px;" title="clip_image004[1]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0576.clip_image0041_thumb_3AC24D3E.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0576.clip_5F00_image0041_5F00_thumb_5F00_3AC24D3E.gif" alt="clip_image004[1]" width="222" height="25" border="0" /></a></p>
<p align="left">The sign() of each side will be &gt; 0 if the vectors are pointing the same direction, or &lt; 0 if the vectors are pointing away from each other. At this point, if either is &lt; 0, we can exit the function with a false result.</p>
<p align="left">The next requirement we need to meet is that r and t must each be smaller than 1, and that their sum must also be less than 1. To do this, let&rsquo;s take the norm of each of the equations above. Since we already know that r and t are positive, we know that the norm of r and t is just r and t.</p>
<p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/1665.clip_image0124_6E3E2DD0.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/1665.clip_5F00_image0124_5F00_6E3E2DD0.gif"><img style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image012[4]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/0677.clip_image0124_thumb_671EF158.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/0677.clip_5F00_image0124_5F00_thumb_5F00_671EF158.gif" alt="clip_image012[4]" width="240" height="24" border="0" /></a></p>
<p>&nbsp;</p>
<p align="center"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4863.clip_image0144_5FFFB4E0.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4863.clip_5F00_image0144_5F00_5FFFB4E0.gif"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="clip_image014[4]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/7610.clip_image0144_thumb_06CDCB21.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/7610.clip_5F00_image0144_5F00_thumb_5F00_06CDCB21.gif" alt="clip_image014[4]" width="101" height="50" border="0" /></a></p>
<p>Again, we can repeat this same process to solve for t, and we&rsquo;ll get:</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/8688.clip_image00218_2D9BE161.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/8688.clip_5F00_image00218_5F00_2D9BE161.gif"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px; border-width: 0px;" title="clip_image002[18]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/4073.clip_image00218_thumb_3F78752E.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/4073.clip_5F00_image00218_5F00_thumb_5F00_3F78752E.gif" alt="clip_image002[18]" width="100" height="50" border="0" /></a></p>
<p>Also, since swapping the order of a cross product doesn&rsquo;t change the magnitude of the resulting vector, only it&rsquo;s direction, then we can also say that</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/3005.clip_image00220_385938B6.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/3005.clip_5F00_image00220_5F00_385938B6.gif"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px; border-width: 0px;" title="clip_image002[20]" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/45/26/metablogapi/2248.clip_image00220_thumb_5F274EF6.gif" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-45-26-metablogapi/2248.clip_5F00_image00220_5F00_thumb_5F00_5F274EF6.gif" alt="clip_image002[20]" width="154" height="25" border="0" /></a></p>
<p>Which gives us a common denominator in our r and t formulas, so we only have to compute the value once. And there we have it, we now have r and t computed, which means we can complete our function. A sample implementation, written in C# and using XNA might look like this:</p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="font-family: Consolas;"><span><span style="color: #808080;"><span style="font-size: 9.5pt;">///</span></span></span><span><span style="color: #808080; font-size: 9.5pt;">&lt;summary&gt;</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="font-family: Consolas;"><span><span style="color: #808080;"><span style="font-size: 9.5pt;">///</span></span></span><span><span style="color: #008000; font-size: 9.5pt;"> Determine whether a point P is inside the triangle ABC. Note, this function</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="font-family: Consolas;"><span><span style="color: #808080;"><span style="font-size: 9.5pt;">///</span></span></span><span><span style="color: #008000; font-size: 9.5pt;"> assumes that P is coplanar with the triangle.</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="font-family: Consolas;"><span><span style="color: #808080;"><span style="font-size: 9.5pt;">///</span></span></span><span><span style="color: #808080; font-size: 9.5pt;">&lt;/summary&gt;</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="font-family: Consolas;"><span><span style="color: #808080;"><span style="font-size: 9.5pt;">///</span></span></span><span style="font-size: 9.5pt;"><span><span style="color: #808080;">&lt;returns&gt;</span></span><span><span style="color: #008000;">True if the point is inside, false if it is not.</span></span></span><span><span style="color: #808080; font-size: 9.5pt;">&lt;/returns&gt;</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="font-family: Consolas;"><span><span style="color: #0000ff;"><span style="font-size: 9.5pt;">public</span></span></span><span><span style="font-size: 9.5pt;"> <span><span style="color: #0000ff;">static</span></span> <span><span style="color: #0000ff;">bool</span></span> PointInTriangle(<span><span style="color: #0000ff;">ref</span></span> <span><span style="color: #2b91af;">Vector3</span></span> A, <span><span style="color: #0000ff;">ref</span></span> <span><span style="color: #2b91af;">Vector3</span></span> B, <span><span style="color: #0000ff;">ref</span></span> <span><span style="color: #2b91af;">Vector3</span></span> C, <span><span style="color: #0000ff;">ref</span></span> <span><span style="color: #2b91af;">Vector3</span></span> P)</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="font-size: 9.5pt;">{</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="mso-spacerun: yes;"><span style="font-size: 9.5pt;">&nbsp;&nbsp;&nbsp; </span></span><span><span style="color: #008000; font-size: 9.5pt;">// Prepare our barycentric variables</span></span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="mso-spacerun: yes;"><span style="font-size: 9.5pt;">&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 9.5pt;"><span><span style="color: #2b91af;">Vector3</span></span> u = B - A;</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="mso-spacerun: yes;"><span style="font-size: 9.5pt;">&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 9.5pt;"><span><span style="color: #2b91af;">Vector3</span></span> v = C - A;</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="mso-spacerun: yes;"><span style="font-size: 9.5pt;">&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 9.5pt;"><span><span style="color: #2b91af;">Vector3</span></span> w = P - A;</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">&nbsp;</p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="font-size: 9.5pt;">&nbsp;&nbsp;&nbsp; </span></span></span><span><span style="font-family: Consolas;"><span style="font-size: 9.5pt;"><span><span style="color: #2b91af;">Vector3</span></span> vCrossW = <span><span style="color: #2b91af;">Vector3</span></span>.Cross(v, w);</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="font-size: 9.5pt;"><span><span style="color: #2b91af;">&nbsp;&nbsp;&nbsp; Vector3</span></span> vCrossU = <span><span style="color: #2b91af;">Vector3</span></span>.Cross(v, u);</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">&nbsp;</p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span><span style="color: #008000; font-size: 9.5pt;">&nbsp;&nbsp;&nbsp; // Test sign of r</span></span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="font-size: 9.5pt;"><span><span style="color: #0000ff;">&nbsp;&nbsp;&nbsp; if</span></span> (<span><span style="color: #2b91af;">Vector3</span></span>.Dot(vCrossW, vCrossU) &lt; 0)</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="font-size: 9.5pt;"><span><span style="color: #0000ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return</span></span> <span><span style="color: #0000ff;">false</span></span>;</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="font-size: 9.5pt;">&nbsp;</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="font-size: 9.5pt;"><span><span style="color: #2b91af;">&nbsp;&nbsp;&nbsp; Vector3</span></span> uCrossW = <span><span style="color: #2b91af;">Vector3</span></span>.Cross(u, w);</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="font-size: 9.5pt;"><span><span style="color: #2b91af;">&nbsp;&nbsp;&nbsp; Vector3</span></span> uCrossV = <span><span style="color: #2b91af;">Vector3</span></span>.Cross(u, v);</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="font-size: 9.5pt;">&nbsp;</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span><span style="color: #008000; font-size: 9.5pt;">&nbsp;&nbsp;&nbsp; // Test sign of t</span></span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="font-size: 9.5pt;"><span><span style="color: #0000ff;">&nbsp;&nbsp;&nbsp; if</span></span> (<span><span style="color: #2b91af;">Vector3</span></span>.Dot(uCrossW, uCrossV) &lt; 0)</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="font-size: 9.5pt;"><span><span style="color: #0000ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return</span></span> <span><span style="color: #0000ff;">false</span></span>;</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="font-size: 9.5pt;">&nbsp;</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span><span style="color: #008000; font-size: 9.5pt;">&nbsp;&nbsp;&nbsp; // At this point, we know that r and t and both &gt; 0.</span></span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span><span style="color: #008000; font-size: 9.5pt;">&nbsp;&nbsp;&nbsp; // Therefore, as long as their sum is &lt;= 1, each must be less &lt;= 1</span></span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="font-size: 9.5pt;"><span><span style="color: #0000ff;">&nbsp;&nbsp;&nbsp; float</span></span> denom = uCrossV.Length();</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="font-size: 9.5pt;"><span><span style="color: #0000ff;">&nbsp;&nbsp;&nbsp; float</span></span> r = vCrossW.Length() / denom;</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="font-size: 9.5pt;"><span><span style="color: #0000ff;">&nbsp;&nbsp;&nbsp; float</span></span> t = uCrossW.Length() / denom;</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="font-size: 9.5pt;">&nbsp;</span></span></span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt; line-height: normal; mso-layout-grid-align: none;">&nbsp;</p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="font-size: 9.5pt;"><span><span style="color: #0000ff;">&nbsp;&nbsp;&nbsp; return</span></span> (r + t &lt;= 1);</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span><span style="font-family: Consolas;"><span style="font-size: 9.5pt;">}</span></span></span></p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">&nbsp;</p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">&nbsp;</p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">&nbsp;</p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">&nbsp;</p>
<p class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span>And that concludes this post on barycentric coordinates, and one of their uses in game code. I hope that this post also served to solidify some of the previous information about affine combinations. Finally, it gave us a chance to use what we&rsquo;ve covered so far to so something useful. I hope you enjoyed it, and I&rsquo;ll be moving on to matrices next.</span></p>]]></content:encoded>
    </item>
  </channel>
</rss>