<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Shawn Hargreaves Blog</title><link>http://blogs.msdn.com/shawnhar/default.aspx</link><description>Game programming with the XNA Framework</description><dc:language>en</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Angles, integers, and modulo arithmetic</title><link>http://blogs.msdn.com/shawnhar/archive/2010/01/04/angles-integers-and-modulo-arithmetic.aspx</link><pubDate>Mon, 04 Jan 2010 21:39:34 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9943602</guid><dc:creator>ShawnHargreaves</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/shawnhar/comments/9943602.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnhar/commentrss.aspx?PostID=9943602</wfw:commentRss><description>&lt;p&gt;These days most people represent angles using degrees or radians, but many old-skool game programmers preferred a binary integer format where a full circle is 65536. To convert:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;short&lt;/span&gt; ToBinary(&lt;span class="kwrd"&gt;float&lt;/span&gt; degrees)
    {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; (&lt;span class="kwrd"&gt;short&lt;/span&gt;)(degrees * 65536 / 360);
    }&lt;/pre&gt;

&lt;p&gt;If you store such a value in a 16 bit integer type, it will automatically overflow any time you increment it past a full circle, so you no longer need special case wrapping code to handle the circular (&lt;a href="http://en.wikipedia.org/wiki/Modular_arithmetic" target="_blank"&gt;modulo&lt;/a&gt;) nature of angle arithmetic.&lt;/p&gt;

&lt;p&gt;When manipulating degrees using floats, you might have to write:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    angle += turnAmount;

    &lt;span class="kwrd"&gt;if&lt;/span&gt; (angle &amp;gt;= 360)
        angle -= 360;
    &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (angle &amp;lt; 0)
        angle += 360;&lt;/pre&gt;

&lt;p&gt;But with a binary angle represented as a short, you can get the same result with just:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    angle += turnAmount;&lt;/pre&gt;

&lt;p&gt;This simplifies many common angle computations. For instance the TurnToFace method from the &lt;a href="http://creators.xna.com/en-US/sample/aiming" target="_blank"&gt;Aiming sample&lt;/a&gt; would no longer need to bother calling WrapAngle if it used this binary format.&lt;/p&gt;

&lt;p&gt;Back in the day most games used integer or &lt;a href="http://en.wikipedia.org/wiki/Fixed-point_arithmetic" target="_blank"&gt;fixed point&lt;/a&gt; math, so this was a major win. But today most people use floating point, and converting between integer and float formats is awkward and slow. So it is debatable whether this format is still useful.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9943602" width="1" height="1"&gt;</description></item><item><title>MotoGP: AI coordinate systems</title><link>http://blogs.msdn.com/shawnhar/archive/2009/12/30/motogp-ai-coordinate-systems.aspx</link><pubDate>Thu, 31 Dec 2009 01:19:56 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9942469</guid><dc:creator>ShawnHargreaves</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/shawnhar/comments/9942469.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnhar/commentrss.aspx?PostID=9942469</wfw:commentRss><description>&lt;p&gt;I occasionally get requests to write about game AI, especially the AI from &lt;a href="http://www.talula.demon.co.uk/blogindex.html#motogp" target="_blank"&gt;MotoGP&lt;/a&gt;. I have resisted this topic for the simple reason that I never worked directly on AI code, so I don't really know much about it. But hey, this is the Internet, right? You don't have to know anything about a subject in order to write about it on the Internet :-)&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Disclaimer: what follows is mostly hearsay, filtered through a couple years of forgetfulness.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;My &lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/12/29/bug-or-feature.aspx" target="_blank"&gt;previous post&lt;/a&gt; reminded me how many tasks can be simplified by choosing the right coordinate system. Anyone who works with 3D graphics will be familiar with the concept of moving back and forth between &lt;a href="http://creators.xna.com/en-US/article/shader_coord" target="_blank"&gt;different coordinate spaces&lt;/a&gt;, common examples being object space, world space, view space, projection space, bone space, and tangent space. Many AI problems can also benefit from their own specialized coordinate systems.&lt;/p&gt;  &lt;p&gt;A common simplification is to collapse 3D into 2D. Even though rendering and physics may be truly 3D, decision making logic need not treat all three axes equally. MotoGP tracks have few hills, so our AI was able to ignore the y component.&lt;/p&gt;  &lt;p&gt;Next, we switched from x/z cartesian coordinates to a track-relative system. Positions were represented by a pair of values:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;int distance = how far around the track, stored in 16.16 &lt;a href="http://en.wikipedia.org/wiki/Fixed-point_arithmetic" target="_blank"&gt;fixed point&lt;/a&gt; format&amp;#160; &lt;ul&gt;       &lt;li&gt;0 = starting line &lt;/li&gt;        &lt;li&gt;0x8000 = half way around &lt;/li&gt;        &lt;li&gt;0x10000 = looped back to the start &lt;/li&gt;        &lt;li&gt;0x1C000 = three quarters of the way through the second lap &lt;/li&gt;     &lt;/ul&gt;      &lt;p&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;float cross = how far sideways across the track      &lt;ul&gt;       &lt;li&gt;0 = on the center line &lt;/li&gt;        &lt;li&gt;-1 = left edge of racing surface &lt;/li&gt;        &lt;li&gt;1 = right edge of racing surface &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;To convert between this and the cartesian coordinates used by our physics and rendering code, we stored a list of segments defining the shape of the racing surface:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;struct&lt;/span&gt; TrackSegment
    {
        Vector CenterPoint;
        &lt;span class="kwrd"&gt;float&lt;/span&gt; DistanceToLeftEdge;
        &lt;span class="kwrd"&gt;float&lt;/span&gt; DistanceToRightEdge;
    }&lt;/pre&gt;

&lt;p&gt;We created several hundred of these structures, spaced evenly around the track, by tessellating the Bezier curves from which the tracks were originally created. This gave us enough information to write the necessary coordinate conversion functions.&lt;/p&gt;

&lt;p&gt;With track-relative coordinates, many useful calculations become trivially simple:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;    if&lt;/span&gt; (abs(cross) &amp;gt; 1)
        &lt;span class="rem"&gt;// You are off the track and should steer back toward the center line&lt;/span&gt;


&lt;span class="kwrd"&gt;    if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;.distance &amp;gt; other.distance)
        &lt;span class="rem"&gt;// You are ahead of the other player (even though you may be&lt;/span&gt;
        &lt;span class="rem"&gt;// physically behind in 3D space if you have lapped them)&lt;/span&gt;


&lt;span class="kwrd"&gt;    short&lt;/span&gt; difference = (&lt;span class="kwrd"&gt;short&lt;/span&gt;)(&lt;span class="kwrd"&gt;this&lt;/span&gt;.distance - other.distance);

&lt;span class="kwrd"&gt;    if&lt;/span&gt; (abs(difference) &amp;lt; threshold)
        &lt;span class="rem"&gt;// These two bikes are physically close together,&lt;/span&gt;
        // so we should run obstacle avoidance checks&lt;/pre&gt;

&lt;p&gt;Because of the fixed point data format, casting the distance counter from 32 to 16 bits was an easy way to discard the lap number, so we could pick and choose which computations cared if two bikes were on different laps, versus wanting to know if they were close in physical space. Thanks to the magic of &lt;a href="http://en.wikipedia.org/wiki/Two%27s_complement" target="_blank"&gt;two's compliment&lt;/a&gt;, treating the difference as signed 16 bit gives the shortest distance regardless of which bike is in front (remember that in a &lt;a href="http://en.wikipedia.org/wiki/Modular_arithmetic" target="_blank"&gt;modulo arithmetic&lt;/a&gt; system such as a looping racetrack there are two possible distances, as you can measure in either direction around the track). This works even when the two bikes are on opposite sides of the starting line, a situation which would require error prone special case logic in most other coordinate systems.&lt;/p&gt;

&lt;p&gt;Flattening and straightening out this virtual gameplay area made it easy to reason about things like &amp;quot;&lt;em&gt;am I on the racing line?&lt;/em&gt;&amp;quot; or &amp;quot;&lt;em&gt;I'm coming up fast behind this other bike: do I have more room to pass them on the left or right?&lt;/em&gt;&amp;quot; which would have been tricky to implement in a full 3D world space. Once we decided to pass on the left, we would convert the resulting track-relative coordinate back into world space, at which point the curvature of the track gets taken into account, showing how we should steer to accomplish our chosen goal.&lt;/p&gt;

&lt;p&gt;Pathfinding can also benefit from specialized coordinate systems, the &lt;a href="http://en.wikipedia.org/wiki/Tube_map" target="_blank"&gt;London underground map&lt;/a&gt; being a classic example.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9942469" width="1" height="1"&gt;</description></item><item><title>Bug or feature?</title><link>http://blogs.msdn.com/shawnhar/archive/2009/12/29/bug-or-feature.aspx</link><pubDate>Wed, 30 Dec 2009 00:16:16 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9942116</guid><dc:creator>ShawnHargreaves</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/shawnhar/comments/9942116.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnhar/commentrss.aspx?PostID=9942116</wfw:commentRss><description>&lt;p&gt;Writing about &lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/12/17/the-psychology-of-randomness.aspx" target="_blank"&gt;randomness&lt;/a&gt; reminded me of an interesting bug in the first commercial game I ever released. &lt;a href="http://www.talula.demon.co.uk/xg/index.html" target="_blank"&gt;Extreme G&lt;/a&gt; was a futuristic racer for the Nintendo 64. Each vehicle had a limited number of turbo boosts, which increased your speed as long as you drove cleanly, but cut out as soon as you clipped the edge of the track. It was impossible to corner cleanly at turbo speed, so the best tactic was to save your boosts for the longest straight section, while trying to knock boosting opponents off the track.&lt;/p&gt;  &lt;p&gt;Ash (the lead programmer) wrote some AI code that decided when the computer players should use their turbo. They would boost when they reached a straight piece of track, and also (for variety) at occasional randomly chosen intervals.&lt;/p&gt;  &lt;p&gt;Shortly after the game came out, we read a review that went something like:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;&amp;quot;We especially loved the aggressive AI, which does everything in its power to stop you overtaking. If you pass a computer player, they will fight back by firing their turbo, even midway through a turn where that is sure to cause a massive pileup. Perhaps not the best winning strategy, but an awesome f-you attitude!&amp;quot;&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&amp;quot;Hah!&amp;quot;, quoth Ash, &amp;quot;what a foolish reviewer! That's not how it works. I bet the random number generator just happened to trigger its turbo at the same time he was overtaking, and he read too much into that. My actual AI code is nowhere near so subtle.&amp;quot;&lt;/p&gt;  &lt;p&gt;But then he went back to look at this actual AI code :-)&lt;/p&gt;  &lt;p&gt;A universal challenge of racing game design is how to keep the pack of vehicles close together. If they become too widely separated, the player can be left racing on what appears to be an empty track, with the computer players out of sight in front or behind them, which is no fun at all. In Extreme G, this problem was exacerbated by two things:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;For performance reasons, we could not afford as many computer vehicles as we ideally wanted, so the pack was overly small in the first place.      &lt;p&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;Weapons and turbo boosts made the gameplay less predictable than in a pure racer, tending to spread out the vehicles. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;To help keep the pack together, Ash biased the turbo AI based on race position. When a computer player was in front of the human they would rarely use their turbo, but if they were far behind they would fire it in an attempt to catch up.&lt;/p&gt;  &lt;p&gt;What he meant to write was:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (computerPlayer &lt;span class="kwrd"&gt;is&lt;/span&gt; behind human)
    {
        u&lt;span class="kwrd"&gt;short&lt;/span&gt; difference = human.TrackPos - computerPlayer.TrackPos;

        &lt;span class="kwrd"&gt;if&lt;/span&gt; (difference &amp;gt; catchUpThreshold)
            FireTurboBoost();
    }&lt;/pre&gt;

&lt;p&gt;The TrackPos field held a 16 bit counter of how far around the track each vehicle was, normalized so that 0 represented the starting line, 32768 was halfway around, and 65535 was a full lap nearly back to the start. This format was convenient because the rounding rules of integer arithmetic automatically handled the modulo operations necessary when comparing positions from different laps, or from either side of the start line.&lt;/p&gt;

&lt;p&gt;Thanks to an order of processing bug, what actually happened was:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (computerPlayer &lt;span class="kwrd"&gt;is&lt;/span&gt; behind human)
    {
        u&lt;span class="kwrd"&gt;short&lt;/span&gt; difference = human.TrackPos - computerPlayer.&lt;font color="#ff0000"&gt;TrackPosFromPreviousFrame&lt;/font&gt;;

        &lt;span class="kwrd"&gt;if&lt;/span&gt; (difference &amp;gt; catchUpThreshold)
            FireTurboBoost();
    }&lt;/pre&gt;

&lt;p&gt;This worked as intended, except when you overtook an AI vehicle:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Computer was in front of human &lt;/li&gt;

  &lt;li&gt;Now human is in front, so this code kicks in &lt;/li&gt;

  &lt;li&gt;Because it erroneously uses the computer position from the previous frame, the position difference comes out negative &lt;/li&gt;

  &lt;li&gt;Because the type is unsigned, this is interpreted as a large positive integer &lt;/li&gt;

  &lt;li&gt;It looks like the computer is a long way behind, so the turbo is triggered &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Oops!&lt;/p&gt;

&lt;p&gt;But the reviewer was absolutely right. Although accidental, the resulting behavior was good gameplay. We left this bug unchanged in the &lt;a href="http://www.talula.demon.co.uk/xg2/index.html" target="_blank"&gt;sequel&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9942116" width="1" height="1"&gt;</description></item><item><title>The psychology of randomness</title><link>http://blogs.msdn.com/shawnhar/archive/2009/12/17/the-psychology-of-randomness.aspx</link><pubDate>Fri, 18 Dec 2009 02:16:12 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9938517</guid><dc:creator>ShawnHargreaves</dc:creator><slash:comments>14</slash:comments><comments>http://blogs.msdn.com/shawnhar/comments/9938517.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnhar/commentrss.aspx?PostID=9938517</wfw:commentRss><description>&lt;p&gt;Due to some quirk of evolution, human beings are remarkably good at intuitively approximating solutions to complex calculus problems, but appallingly bad at estimating probability.&lt;/p&gt;  &lt;p&gt;Pretty much anyone is able to catch a ball, or judge when it is safe to pull out into traffic. These tasks require complex predictions at least up to the second derivative (involving position, velocity, and acceleration), yet our subconscious can solve them in seconds.&lt;/p&gt;  &lt;p&gt;Our intuitions are not so smart when dealing with probability:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;When asked to pick a random number between 1 and 100, most people will choose a number that is odd, often prime, and approximately 1/3 or 2/3 of the way between the lower and upper limits. For some reason we think these values are &amp;quot;more random&amp;quot; than other numbers. Try it sometime! It is amazing how many people will choose 67, while nobody ever goes for 50.      &lt;p&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;My mother, a smart lady who is generally good at math, is absolutely convinced that if you roll an (unloaded) dice 10 times and get a 6 each time, the odds of getting another 6 on your 11th attempt must be vanishingly small. Indeed, 11 in a row is unlikely, but her intuition simply cannot accept that, having already rolled 10, the odds of an 11th remain 1/6.      &lt;p&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;The &lt;a href="http://en.wikipedia.org/wiki/Birthday_problem" target="_blank"&gt;shared birthday party trick&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Monty_Hall_problem" target="_blank"&gt;Monty Hall problem&lt;/a&gt; are famous examples of how unintuitive even simple probability questions can be. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;This matters to game programmers, because we often use random numbers to control our game simulations. If I had a penny for every time I heard someone say &amp;quot;&lt;em&gt;I think the random number generator must be broken, because the numbers I get back aren't very random&lt;/em&gt;&amp;quot;, well, that would be a lot of pennies.&lt;/p&gt;  &lt;p&gt;I ran this test program:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;    Random random = &lt;span class="kwrd"&gt;new&lt;/span&gt; Random();

    &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 10; i++)
    {
        Trace.WriteLine(random.Next(100));
    }&lt;/pre&gt;

&lt;p&gt;Results:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    50
    76
    23
    1
    17
    16
    19    // Huh? Three similar numbers in a row
    8
    90
    90    // Yowzer! Same value twice in a row can't be right?&lt;/pre&gt;

&lt;p&gt;But these numbers are perfectly random. In fact, when you choose ten random numbers, there will often be strings of repeated or similar values. One of the most unlikely outcomes would be if the results were evenly distributed without any clustering! When we hear &amp;quot;&lt;em&gt;random&lt;/em&gt;&amp;quot;, we tend to think &amp;quot;&lt;em&gt;evenly distributed, with a slight random perturbation over the top&lt;/em&gt;&amp;quot;. These are not the same thing.&lt;/p&gt;

&lt;p&gt;Our brains are tremendously good at spotting subtle patterns in seemingly random noise. Perhaps too good. We are so focused on trying to identify a pattern that our subconscious fixates on even the slightest deviation from an even distribution. A truly random series of numbers will never be evenly spaced, but when you combine a talent for identifying patterns with a poor understanding of probability, it's no wonder our poor little brains get confused :-)&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Try this experiment some time: pick any movie other than &lt;/em&gt;Wizard of Oz&lt;em&gt;, any music other than &lt;/em&gt;Dark Side of the Moon&lt;em&gt; (preferably things you know well), and play them at the same time. Isn't it amazing how well they fit together? This occurs because our pattern detection skills focus on the handful of places where things do randomly happen to line up, and we are too bad at probability to contrast this with the much larger number of things that don't line up at all.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As game developers, we often use random number generators as an approximation for things that are not truly random at all, but which are too complex for us to properly evaluate.&amp;#160; We could simulate vegetation growth patterns, soil erosion, light and shade, the impacts of logging and lightning fires and deer grazing and the wind shadow of that distant mountain range. Nah. Let's just randomly scatter our tree sprites over the hillside...&lt;/p&gt;

&lt;p&gt;The trick to getting good results from random numbers is to think about what characteristics we would like the resulting data to have, and understand that a series of truly independent random numbers is rarely the best distribution.&lt;/p&gt;

&lt;p&gt;When planting trees, rather than just repeating a random position selection, we could cover our terrain with a regular grid. Perhaps we could perturb the grid on a coarse level, making some areas have smaller and denser cells than others. We can then plant one tree per cell, including a small random offset to hide the repeating pattern, and perhaps randomly skipping some cells while planting more than one tree in others. The resulting distribution will be far from random in the mathematical sense, but will look more random to the average human being, and that's what counts, right?&lt;/p&gt;

&lt;p&gt;Likewise, a random song shuffle algorithm should avoid repeating the same song too close together. Sure, playing it twice in a row is a valid random result, but probably not what the user wanted!&lt;/p&gt;

&lt;p&gt;Randomness in games is usually an approximation for something more complex, and not independent samples like you get when tossing a coin, rolling a dice, or calling Random.Next(). By understanding this, we can process our random numbers to produce results that are less random, yet more convincing and artistically pleasing.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9938517" width="1" height="1"&gt;</description></item><item><title>Algorithm versus implementation</title><link>http://blogs.msdn.com/shawnhar/archive/2009/12/14/algorithm-versus-implementation.aspx</link><pubDate>Mon, 14 Dec 2009 21:50:59 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9936772</guid><dc:creator>ShawnHargreaves</dc:creator><slash:comments>11</slash:comments><comments>http://blogs.msdn.com/shawnhar/comments/9936772.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnhar/commentrss.aspx?PostID=9936772</wfw:commentRss><description>&lt;p&gt;When I first started making games, most things were written in C, with critical pieces optimized in assembly language. A skilled assembly programmer could beat the C compilers of the day by a factor of two or more, so this was an important optimization (for instance the blit routines in &lt;a href="http://alleg.sourceforge.net/readme.html" target="_blank"&gt;Allegro&lt;/a&gt; were all written in assembly).&lt;/p&gt;  &lt;p&gt;But assembly language could be a dangerous pitfall. Rewriting a function in assembly language changed the details of the way it worked (the &lt;em&gt;how&lt;/em&gt;, or implementation), but did not fundamentally alter its purpose (the &lt;em&gt;what&lt;/em&gt;, or algorithm). Doing the same basic thing in a more efficient way could give a 2x, 3x, or even 4x speed boost, but larger gains could only be achieved by switching to a smarter algorithm.&lt;/p&gt;  &lt;p&gt;The danger of assembly language was that it made code faster, but also more complex and harder to understand. By obscuring the underlying algorithm, this 2x optimization often hid the potential for much more significant algorithmic improvements.&lt;/p&gt;  &lt;p&gt;I was reminded of this by a &lt;a href="http://forums.xna.com/forums/p/43976/261540.aspx#261540" target="_blank"&gt;recent thread on the creators.xna.com forums&lt;/a&gt;, where a word search algorithm was taking more than half a second. Early suggestions focused on optimizing the implementation:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Use StringBuilder to reduce garbage&lt;/li&gt;    &lt;li&gt;Pack short text strings into 64 bit integers to speed comparison&lt;/li&gt;    &lt;li&gt;Use threads to parallelize the work across multiple CPU cores&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;These techniques are the C# equivalent of rewriting something in assembly language. They did indeed work, reducing the half second search time to 80 milliseconds (a 6x gain), but there is a fairly low upper bound on how much such things can help. For instance on a quad core machine, threaded code can run at most 4x faster than a single core version (in practice the gain is usually far less).&lt;/p&gt;  &lt;p&gt;Then &lt;a href="http://forums.xna.com/forums/p/43976/262011.aspx#262011" target="_blank"&gt;Jon Watte suggested a better algorithm&lt;/a&gt;, using a tree structure to replace the original O(N!) (factorial) algorithm with a log(N) version.&lt;/p&gt;  &lt;p&gt;Result? &lt;a href="http://forums.xna.com/forums/p/43976/262202.aspx#262202" target="_blank"&gt;The search now completes in less than 1 millisecond&lt;/a&gt;. That's more than a 500x improvement!&lt;/p&gt;  &lt;p&gt;&lt;a title="http://en.wikipedia.org/wiki/The_Art_of_Computer_Programming" href="http://en.wikipedia.org/wiki/The_Art_of_Computer_Programming"&gt;&lt;font color="#333333"&gt;Just goes &lt;/font&gt;&lt;/a&gt;to show that, while languages and programming techniques continue to evolve, there are still few things as important as the &lt;a href="http://en.wikipedia.org/wiki/The_Art_of_Computer_Programming" target="_blank"&gt;fundamentals of algorithms and data structures&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9936772" width="1" height="1"&gt;</description></item><item><title>Premultiplied alpha content processor</title><link>http://blogs.msdn.com/shawnhar/archive/2009/11/11/premultiplied-alpha-content-processor.aspx</link><pubDate>Wed, 11 Nov 2009 16:10:01 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9920870</guid><dc:creator>ShawnHargreaves</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/shawnhar/comments/9920870.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnhar/commentrss.aspx?PostID=9920870</wfw:commentRss><description>&lt;p&gt;As mentioned in my &lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/11/10/premultiplied-alpha-in-xna-game-studio.aspx" target="_blank"&gt;previous post&lt;/a&gt;, a Content Processor that converts textures into &lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/11/06/premultiplied-alpha.aspx" target="_blank"&gt;premultiplied alpha&lt;/a&gt; format: &lt;/p&gt;  &lt;pre class="mypmacsharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; Microsoft.Xna.Framework;
&lt;span class="kwrd"&gt;using&lt;/span&gt; Microsoft.Xna.Framework.Content.Pipeline;
&lt;span class="kwrd"&gt;using&lt;/span&gt; Microsoft.Xna.Framework.Content.Pipeline.Graphics;
&lt;span class="kwrd"&gt;using&lt;/span&gt; Microsoft.Xna.Framework.Content.Pipeline.Processors;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; PremultipliedAlpha
{
    [ContentProcessor]
    &lt;span class="kwrd"&gt;class&lt;/span&gt; PremultipliedAlphaTextureProcessor : TextureProcessor
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; TextureContent Process(TextureContent input, ContentProcessorContext context)
        {
            input.ConvertBitmapType(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(PixelBitmapContent&amp;lt;Color&amp;gt;));

            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (MipmapChain mipChain &lt;span class="kwrd"&gt;in&lt;/span&gt; input.Faces)
            {
                &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (PixelBitmapContent&amp;lt;Color&amp;gt; bitmap &lt;span class="kwrd"&gt;in&lt;/span&gt; mipChain)
                {
                    &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; y = 0; y &amp;lt; bitmap.Height; y++)
                    {
                        &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; x = 0; x &amp;lt; bitmap.Width; x++)
                        {
                            Color c = bitmap.GetPixel(x, y);

                            c.R = (&lt;span class="kwrd"&gt;byte&lt;/span&gt;)(c.R * c.A / 255);
                            c.G = (&lt;span class="kwrd"&gt;byte&lt;/span&gt;)(c.G * c.A / 255);
                            c.B = (&lt;span class="kwrd"&gt;byte&lt;/span&gt;)(c.B * c.A / 255);

                            bitmap.SetPixel(x, y, c);
                        }
                    }
                }
            }

            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;base&lt;/span&gt;.Process(input, context);
        }
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;




.mypmacsharpcode, .mypmacsharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.mypmacsharpcode pre { margin: 0em; }
.mypmacsharpcode .rem { color: #008000; }
.mypmacsharpcode .kwrd { color: #0000ff; }
.mypmacsharpcode .str { color: #006080; }
.mypmacsharpcode .op { color: #0000c0; }
.mypmacsharpcode .preproc { color: #cc6633; }
.mypmacsharpcode .asp { background-color: #ffff00; }
.mypmacsharpcode .html { color: #800000; }
.mypmacsharpcode .attr { color: #ff0000; }
.mypmacsharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.mypmacsharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9920870" width="1" height="1"&gt;</description></item><item><title>Premultiplied alpha in XNA Game Studio</title><link>http://blogs.msdn.com/shawnhar/archive/2009/11/10/premultiplied-alpha-in-xna-game-studio.aspx</link><pubDate>Wed, 11 Nov 2009 03:24:36 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9920589</guid><dc:creator>ShawnHargreaves</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/shawnhar/comments/9920589.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnhar/commentrss.aspx?PostID=9920589</wfw:commentRss><description>&lt;p&gt;It is possible to use &lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/11/06/premultiplied-alpha.aspx" target="_blank"&gt;premultiplied alpha&lt;/a&gt; with XNA Game Studio, but the bad news is we don't do much to help you with it.&lt;/p&gt;  &lt;p&gt;Why not?&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Yeah&lt;/em&gt;.&amp;#160; Our bad.&amp;#160; In fact one of my biggest regrets about the design of the XNA Framework is that we didn't do more to make this easier!&lt;/p&gt;  &lt;p&gt;To use premultiplied alpha, you must do three things:&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;1 – Set The Blend State&lt;/h3&gt;  &lt;p&gt;Premultiplied alpha blending is configured like this:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;    graphicsDevice.RenderState.AlphaBlendEnable = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
    graphicsDevice.RenderState.SourceBlend = Blend.One; 
    graphicsDevice.RenderState.DestinationBlend = Blend.InverseSourceAlpha; &lt;/pre&gt;

&lt;p&gt;Or if you are using SpriteBatch:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None);
    graphicsDevice.RenderState.SourceBlend = Blend.One; &lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h3&gt;2 – Premultiply Your Colors&lt;/h3&gt;

&lt;p&gt;Premultiplied blending only works if all your color values are in premultiplied format. But most paint programs and image file formats do not use premultiplied alpha! So we must find a good place to apply this conversion.&lt;/p&gt;

&lt;p&gt;For most games, both 2D and 3D, the flow of color data goes something like this:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;img title="Untitled" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="156" alt="Untitled" src="http://blogs.msdn.com/blogfiles/shawnhar/WindowsLiveWriter/PremultipliedalphainXNAGameStudio_7D77/Untitled_8410bd1f-6787-4a26-b502-0743587b7402.png" width="731" border="0" /&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;Color values are edited in a paint program, then saved into a .bmp or .png file, which is built into .xnb format by the Content Pipeline, then loaded into a Texture2D object. 
    &lt;p&gt;&lt;/p&gt;
  &lt;/li&gt;

  &lt;li&gt;Other colors may be used to tint the texture. These can be specified as part of the vertex data, or passed as the color parameter to SpriteBatch.Draw. 
    &lt;p&gt;&lt;/p&gt;
  &lt;/li&gt;

  &lt;li&gt;Still more colors may be computed on the fly (eg. realtime lighting). 
    &lt;p&gt;&lt;/p&gt;
  &lt;/li&gt;

  &lt;li&gt;All these colors are passed into the shader, which could do all kinds of interesting things with them, but most often just multiplies them together. 
    &lt;p&gt;&lt;/p&gt;
  &lt;/li&gt;

  &lt;li&gt;The shader produces a final combined color, which is passed to the alpha blending operation. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are several options for where in this process we choose to convert from conventional to premultiplied format. Two in particular I think can be sensible depending on the situation:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;table cellspacing="0" cellpadding="4" width="680" border="1"&gt;&lt;tbody&gt;
      &lt;tr&gt;
        &lt;td width="332"&gt;&lt;strong&gt;Convert colors at the end of the pixel shader&lt;/strong&gt;&lt;/td&gt;

        &lt;td width="346"&gt;&lt;strong&gt;Convert colors in a custom Content Processor&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td width="330"&gt;Add &amp;quot;&lt;em&gt;result.rgb *= result.a&lt;/em&gt;&amp;quot; right before the end of all your shaders&lt;/td&gt;

        &lt;td width="348"&gt;Write a PremultipliedAlphaTextureProcessor, which automatically converts all your textures to premultiplied format while they are being built&lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td width="328"&gt;Requires custom pixel shaders&lt;/td&gt;

        &lt;td width="350"&gt;Does not require custom shaders, so works with SpriteBatch, BasicEffect, etc.&lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td width="327"&gt;Premultiplication happens after the shader has processed any tint colors, so tints are still specified in conventional, non-premultiplied format&lt;/td&gt;

        &lt;td width="351"&gt;All runtime colors, including tint values, are specified in premultiplied format&lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td width="327"&gt;Alpha blending is done with premultiplied colors, so &lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/11/07/premultiplied-alpha-and-image-composition.aspx" target="_blank"&gt;image composition&lt;/a&gt; works properly, but texture filtering happens before the premultiply conversion, so &lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/11/02/texture-filtering-alpha-cutouts.aspx" target="_blank"&gt;alpha cutouts&lt;/a&gt; remain a problem&lt;/td&gt;

        &lt;td width="352"&gt;All rendering uses premultiplied colors, so both &lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/11/07/premultiplied-alpha-and-image-composition.aspx" target="_blank"&gt;image composition&lt;/a&gt; and &lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/11/02/texture-filtering-alpha-cutouts.aspx" target="_blank"&gt;alpha cutouts&lt;/a&gt; work nicely&lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td width="327"&gt;Reasonably easy retrofit to existing code, or even just specific parts of that code, as long as you have custom shaders&lt;/td&gt;

        &lt;td width="352"&gt;Affects everywhere you do color math, which may be a lot of places, so it can be a pain to retrofit if you don't plan this from the start&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;&lt;/table&gt;
&lt;/blockquote&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h3&gt;3 – Use The Right Math&lt;/h3&gt;

&lt;p&gt;Any time you do computations on color values, you need to use the right math for the type of colors you are dealing with. Some things to bear in mind:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Keep track of which data is in which format. Mixing premultiplied with conventional colors is a recipe for chaos! 
    &lt;p&gt;&lt;/p&gt;
  &lt;/li&gt;

  &lt;li&gt;This distinction is only important for colors that have fractional or zero alpha. Opaque colors are the same in both formats, so nothing changes for computations that use RGB color without alpha. 
    &lt;p&gt;&lt;/p&gt;
  &lt;/li&gt;

  &lt;li&gt;Conventional colors change opacity by leaving RGB alone while decreasing alpha. For instance to draw a half transparent orange sprite we would specify a tint of (255, 128, 0, 128). But with premultiplied colors, we must also decrease the RGB values, so that same tint would be specified as (128, 64, 0, 128). 
    &lt;p&gt;&lt;/p&gt;
  &lt;/li&gt;

  &lt;li&gt;By far the most common color operation is tinting, which is done by multiplying two colors together (for instance this is how SpriteBatch.Draw combines its texture and color parameter). Color multiplication works the same for premultiplied and conventional colors, as long as both operands are in the same format. 
    &lt;p&gt;&lt;/p&gt;
  &lt;/li&gt;

  &lt;li&gt;This means that SpriteBatch works as-is with premultiplied data. 
    &lt;p&gt;&lt;/p&gt;
  &lt;/li&gt;

  &lt;li&gt;BasicEffect diffuse lighting and vertex coloring also use color multiplication, and therefore work correctly with premultiplied data. 
    &lt;p&gt;&lt;/p&gt;
  &lt;/li&gt;

  &lt;li&gt;The BasicEffect specular lighting and fog computations will not work correctly with premultiplied data. If you want specular lighting or fog while using premultiplied alpha, you will have to write a custom shader. &lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9920589" width="1" height="1"&gt;</description></item><item><title>Premultiplied alpha and image composition</title><link>http://blogs.msdn.com/shawnhar/archive/2009/11/07/premultiplied-alpha-and-image-composition.aspx</link><pubDate>Sat, 07 Nov 2009 20:34:28 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9919127</guid><dc:creator>ShawnHargreaves</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/shawnhar/comments/9919127.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnhar/commentrss.aspx?PostID=9919127</wfw:commentRss><description>&lt;p&gt;From &lt;a href="http://en.wikipedia.org/wiki/Alpha_compositing" target="_blank"&gt;Wikipedia&lt;/a&gt;:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;&amp;quot;Alpha compositing is the process of combining an image with a background to create the appearance of partial transparency. It is often useful to render image elements in separate passes, and then combine the resulting multiple 2D images into a single, final image in a process called compositing.&amp;quot;&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Example&lt;/h3&gt;  &lt;p&gt;I am making a Pong game. I start by clearing my background to CornflowerBlue (100, 149, 237). I then draw a translucent grey box (128, 128, 128, 128) at the top of the screen, which will form the background of my score display. With conventional alpha blending:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;((128, 128, 128) * 0.5)&amp;#160; +&amp;#160; ((100, 149, 237) * (1 - 0.5))&amp;#160; =&amp;#160; (114, 138, 182)&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Well and good. But over time, my overlays get more complex, including a map, radar, waypoint indicators, mission objectives, leaderboard rankings, etc. (what can I say, this is a &lt;em&gt;complex &lt;/em&gt;Pong game :-)&amp;#160; To avoid redrawing so much stuff every frame, wouldn't it be cool if I could draw the overlays just once to a rendertarget, then copy the resulting static image over the top of my animating gameplay?&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;A Problem&lt;/h3&gt;  &lt;p&gt;Unfortunately, this doesn't work using conventional alpha blending:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Clear rendertarget to (0, 0, 0, 0)&lt;/p&gt;    &lt;p&gt;Blend 50% grey into the rendertarget:&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ((128, 128, 128, 128) * 0.5)&amp;#160; +&amp;#160; ((0, 0, 0, 0) * (1 - 0.5))&amp;#160; =&amp;#160; (64, 64, 64, 64)&lt;/p&gt;    &lt;p&gt;Clear backbuffer to CornflowerBlue (100, 149, 237)&lt;/p&gt;    &lt;p&gt;Blend rendertarget over the backbuffer:&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ((64, 64, 64) * 0.25)&amp;#160; +&amp;#160; ((100, 149, 237) * (1 - 0.25))&amp;#160; =&amp;#160; (91, 127, 194)&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Whoah! That's not even remotely the same result as before. The blend operation is happening twice: first when we draw into the rendertarget, then again when we draw the rendertarget into the backbuffer. Our alpha value ends up getting squared, so 0.5 becomes 0.25.&lt;/p&gt;  &lt;p&gt;We could fix this by removing one of the blend operations:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Disable blending while drawing to the rendertarget&lt;/li&gt;    &lt;li&gt;Or disable blending while drawing the rendertarget over the backbuffer&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;But these are rarely good solutions, since you most likely need blending in both places&amp;#160; (the overlays in my Pong game are built from many layers of alpha blended graphics, and the gameplay scene should be visible behind them).&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Some Math&lt;/h3&gt;  &lt;p&gt;Given a series of drawing operations which blend over the top of each other:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;result = a -&amp;gt; b -&amp;gt; c -&amp;gt; d&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;we would like to be able to group a set of calls from the middle of this sequence, storing their result in a rendertarget, then later replace that set of calls with the contents of the rendertarget:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;tmp = b -&amp;gt; c&lt;/p&gt;    &lt;p&gt;result = a -&amp;gt; tmp -&amp;gt; d&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The problem is that this changes the order of the blend operations. What was:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;result = blend(blend(blend(a, b), c), d)&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;becomes:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;result = blend(blend(a, blend(b, c)), d)&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Because conventional alpha blending is not associative, changing the order of evaluation changes the result.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;The Solution&lt;/h3&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/11/06/premultiplied-alpha.aspx" target="_blank"&gt;Premultiplied alpha blending&lt;/a&gt; is associative, so any number of blending operations can be grouped and reordered without affecting the final result.&lt;/p&gt;  &lt;p&gt;To use premultiplied alpha, we make two changes:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Convert our source colors into premultiplied format, so translucent grey becomes (64, 64, 64, 128) rather than (128, 128, 128, 128)      &lt;p&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;Change RenderState.SourceBlend from Blend.SourceAlpha to Blend.One &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Working through the same example as before:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Clear rendertarget to (0, 0, 0, 0)&lt;/p&gt;    &lt;p&gt;Blend 50% grey into the rendertarget:&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; (64, 64, 64, 128) +&amp;#160; ((0, 0, 0, 0) * (1 - 0.5))&amp;#160; =&amp;#160; (64, 64, 64, 128)&lt;/p&gt;    &lt;p&gt;Clear backbuffer to CornflowerBlue (100, 149, 237)&lt;/p&gt;    &lt;p&gt;Blend rendertarget over the backbuffer:&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; (64, 64, 64) +&amp;#160; ((100, 149, 237) * (1 - 0.5))&amp;#160; =&amp;#160; (114, 138, 182)&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Tada! That's the same result as when we were drawing everything directly to the backbuffer.&lt;/p&gt;  &lt;p&gt;Premultiplied alpha r0x0rz.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Historical Aside&lt;/h3&gt;  &lt;p&gt;Alvy Ray Smith writes about the &lt;a href="http://www.alvyray.com/memos/7_alpha.pdf" target="_blank"&gt;invention of the alpha channel&lt;/a&gt; and &lt;a href="http://www.alvyray.com/memos/4_comp.pdf" target="_blank"&gt;image composition&lt;/a&gt;. I find it interesting that this was invented in the 1970s, and fully grokked as of the classic &lt;a href="http://portal.acm.org/citation.cfm?id=808606" target="_blank"&gt;Porter-Duff paper&lt;/a&gt; in 1984, yet here we are a quarter of a century later, still having a hard time making composition work right because for some reason premultiplied alpha never became as widely understood as it deserves to be.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9919127" width="1" height="1"&gt;</description></item><item><title>Premultiplied alpha</title><link>http://blogs.msdn.com/shawnhar/archive/2009/11/06/premultiplied-alpha.aspx</link><pubDate>Fri, 06 Nov 2009 19:39:49 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9918762</guid><dc:creator>ShawnHargreaves</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.msdn.com/shawnhar/comments/9918762.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnhar/commentrss.aspx?PostID=9918762</wfw:commentRss><description>&lt;p&gt;Remember when you first figured out Santa Claus wasn't real? The growing doubt, tempered by the fact that all your friends believed in him, and surely they can't ALL be wrong, then the gradual realization that everybody was in fact wrong...&lt;/p&gt;  &lt;p&gt;Well, I've got another one for you: the way most people do alpha blending is bogus!&lt;/p&gt;  &lt;p&gt;At a fundamental level, alpha has no special meaning at all. Graphics cards manipulate numeric values, but what they do with these values is entirely determined by what shader code you write and which render states you set. The hardware works with Vector4 data types. Because these often represent colors, it is natural to use the first three components for red, green, and blue. That leaves a spare component, called alpha, which can be used for absolutely anything we like.&lt;/p&gt;  &lt;p&gt;Some people use alpha to store shininess, or ambient occlusion, or a collision material ID. In the &lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/02/17/motogp-particles.aspx" target="_blank"&gt;MotoGP particle system&lt;/a&gt; I used it to pass a per-particle random number into my vertex shader physics. But most often, alpha is used to represent transparency. It is important to understand that this is just a convention, and there are several different ways it can be done.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Conventional Alpha Blending&lt;/h3&gt;  &lt;p&gt;The majority of programmers, programs, programming APIs, file formats, etc, define transparency as:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;RGB specifies the color of the object &lt;/li&gt;    &lt;li&gt;Alpha specifies how solid it is &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;In math:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;blend(source, dest)&amp;#160; =&amp;#160; (source.rgb * source.a) + (dest.rgb * (1 - source.a)) &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;In code:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;    RenderState.SourceBlend = Blend.SourceAlpha; 
    RenderState.DestinationBlend = Blend.InverseSourceAlpha; &lt;/pre&gt;

&lt;p&gt;In this world, RGB and alpha are independent. You can change one without affecting the other. Even when an object is fully transparent it still has the same RGB as if it was opaque. Thus 100% transparency can be represented by many different color values.&lt;/p&gt;

&lt;p&gt;There isn't really a direct physical analogy for this. I guess it's similar to how a magic cloak of invisibility works in a fantasy universe, where I can be wearing the same red sweater as I am right now, and it remains red even though it currently happens to be invisible.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h3&gt;Premultiplied Alpha Blending&lt;/h3&gt;

&lt;p&gt;Here's a different way to think about transparency:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;RGB specifies how much color the object contributes to the scene &lt;/li&gt;

  &lt;li&gt;Alpha specifies how much it obscures whatever is behind it &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In math:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;blend(source, dest)&amp;#160; =&amp;#160; source.rgb + (dest.rgb * (1 - source.a)) &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In code:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    RenderState.SourceBlend = Blend.One; 
    RenderState.DestinationBlend = Blend.InverseSourceAlpha; &lt;/pre&gt;

&lt;p&gt;In this world, RGB and alpha are linked. To make an object transparent you must reduce both its RGB (to contribute less color) and also its alpha (to obscure less of whatever is behind it). Fully transparent objects no longer have any RGB color, so there is only one value that represents 100% transparency (RGB and alpha all zero).&lt;/p&gt;

&lt;p&gt;This is more like how light behaves in the real world. What is the RGB of my car windscreen? &lt;em&gt;None: it is transparent, so has no color&lt;/em&gt;. How about my sunglasses? &lt;em&gt;These have a fractional alpha value (letting some light some through, while blocking some) and also contribute some RGB for that nice rose-tinted glow&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;To use premultiplied alpha, in addition to setting the appropriate renderstates, you must also convert your source graphics into premultiplied format. Drawing a non premultiplied color with premultiplied blending will not give sensible results!&lt;/p&gt;

&lt;p&gt;To convert a non premultiplied color into premultiplied format:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;color.rgb *= color.a&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;(hence why this is called &amp;quot;premultiplied&amp;quot; format)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Look at the blend equations for conventional vs. premultiplied alpha. If you substitute this color format conversion into the premultiplied blend function, you get the conventional blend function, so either way produces the same end result. The difference is that premultiplied alpha applies the (source.rgb * source.a) computation as a preprocess rather than inside the blending hardware.&lt;/p&gt;

&lt;p&gt;I will write more about how to convert graphics into premultiplied format in a later post.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h3&gt;Why premultiplied r0x0rz&lt;/h3&gt;

&lt;p&gt;Premultiplied alpha is better than conventional blending for several reasons:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It works properly when filtering alpha cutouts &lt;em&gt;(see below)&lt;/em&gt; 

    &lt;p&gt;&lt;/p&gt;
  &lt;/li&gt;

  &lt;li&gt;It works properly when doing image composition &lt;em&gt;(stay tuned for my next post)&lt;/em&gt; 

    &lt;p&gt;&lt;/p&gt;
  &lt;/li&gt;

  &lt;li&gt;It is a superset of both conventional and additive blending. If you set alpha to zero while RGB is non zero, you get an additive blend. This can be handy for particle systems that want to smoothly transition from additive glowing sparks to dark pieces of soot as the particles age.
    &lt;p&gt;&lt;/p&gt;
  &lt;/li&gt;

  &lt;li&gt;It plays nice with &lt;a href="http://blogs.msdn.com/shawnhar/archive/2008/10/28/texture-compression.aspx" target="_blank"&gt;DXT compression&lt;/a&gt;, which only supports transparent pixels with an RGB of zero. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h3&gt;Premultiplied alpha cutouts&lt;/h3&gt;

&lt;p&gt;Remember how &lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/11/02/texture-filtering-alpha-cutouts.aspx" target="_blank"&gt;filtering can produce ugly fringes around the edges of alpha cutouts&lt;/a&gt;? Not a problem when using premultiplied alpha! Revisiting the example from my previous post:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;tree&amp;#160; =&amp;#160; (0, 255, 0, 255)&lt;/p&gt;

  &lt;p&gt;border&amp;#160; =&amp;#160; (0, 0, 0, 0)&lt;/p&gt;

  &lt;p&gt;background&amp;#160; =&amp;#160; (0, 0, 255)&lt;/p&gt;

  &lt;p&gt;filtered&amp;#160; =&amp;#160; (tree + border) / 2&amp;#160; =&amp;#160; (0, 128, 0, 128)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With conventional alpha blending, the result is darker than we wanted:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;result&amp;#160; =&amp;#160; lerp(background, filtered.rgb, filtered.a)&amp;#160; =&amp;#160; (0, 64, 128)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But premultiplied blending produces the right answer:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;result&amp;#160; =&amp;#160; filtered.rgb + (background * filtered.a)&amp;#160; =&amp;#160; (0, 128, 128)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This works because texture filtering and premultiplied blending are both linear transforms, and are therefore associative:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;blend(filter(a, b),&amp;#160; c)&amp;#160; ==&amp;#160; filter(blend(a, c),&amp;#160; blend(b, c)) &lt;/p&gt;&lt;/blockquote&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9918762" width="1" height="1"&gt;</description></item><item><title>Texture filtering: alpha cutouts</title><link>http://blogs.msdn.com/shawnhar/archive/2009/11/02/texture-filtering-alpha-cutouts.aspx</link><pubDate>Mon, 02 Nov 2009 15:21:26 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9916173</guid><dc:creator>ShawnHargreaves</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/shawnhar/comments/9916173.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnhar/commentrss.aspx?PostID=9916173</wfw:commentRss><description>&lt;p&gt;Consider a cutout texture that contains a solid shape surrounded by transparency. Let's say this is a tree, although it could equally well be a &lt;a href="http://blogs.msdn.com/shawnhar/archive/2007/03/07/return-of-the-son-of-programmer-art.aspx" target="_blank"&gt;cat&lt;/a&gt; or an overweight Italian plumber. Our tree is opaque and colored green:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;tree&amp;#160; =&amp;#160; (0, 255, 0, 255)&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The surrounding pixels are transparent:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;border&amp;#160; =&amp;#160; (0, 0, 0, 0)&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;We are drawing over the top of a blue sky:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;background&amp;#160; =&amp;#160; (0, 0, 255)&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;If we draw without filtering, everything works as expected. Opaque pixels will replace the background, leaving solid green, while the transparent pixels have no effect, leaving solid blue.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Problem&lt;/h3&gt;  &lt;p&gt;What if the texture needs to be &lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/09/08/texture-filtering.aspx" target="_blank"&gt;filtered&lt;/a&gt;? For instance our tree could be positioned in such a way that some destination pixels are covered half by opaque green and half by the transparent border. First the filtering hardware interpolates between these two parts of the texture:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;filtered&amp;#160; =&amp;#160; (tree + border) / 2&amp;#160; =&amp;#160; (0, 128, 0, 128)&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Now the alpha blending hardware combines this filtered color with our blue background:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;result&amp;#160; =&amp;#160; lerp(background, filtered.rgb, filtered.a)&amp;#160; =&amp;#160; (0, 64, 128)&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Huh? Halfway between a green tree and blue background should be (0, 128, 128), not (0, 64, 128). The output is darker than we wanted.&lt;/p&gt;  &lt;p&gt;It seems logical that if a pixel has zero alpha, its RGB value should be irrelevant, right? Not so when filtering is enabled...&lt;/p&gt;  &lt;p&gt;Filtering applies equally to the RGB and alpha channels. When used on the alpha channel of a cutout texture it will produce new fractional alpha values around the edge of the shape, which makes things look nice and antialiased. But filtering also produces new RGB colors, part way in between the RGB of the solid and transparent parts of the texture. Thus the RGB values of supposedly transparent pixels can bleed into our final image.&lt;/p&gt;  &lt;p&gt;This most often results in dark borders around alpha cutouts, since the RGB of transparent pixels is often black. Depending on the texture, the bleeding could alternatively be white, pink, etc.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Alternative Explanation For The Mathematically Inclined&lt;/h3&gt;  &lt;p&gt;What we really wanted was:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;filter( blend(tree, background),&amp;#160; blend(border, background) )&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;But instead we got:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;blend( filter(tree, border),&amp;#160; background )&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Because texture filtering and alpha blending are not associative, these do not produce the same result.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Workaround&lt;/h3&gt;  &lt;p&gt;What if we change our tree texture to have green in the RGB channels of its transparent areas, replacing (0, 0, 0, 0) with (0, 255, 0, 0)? We will still get color bleeding around the edges, but because the transparent RGB now matches the color of the main image, this will not look so ugly.&lt;/p&gt;  &lt;p&gt;This workaround can be useful, but is far from perfect:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Not every paint program is able to edit the RGB values of transparent pixels.      &lt;p&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;Even if your paint program supports this, beware of codecs that may discard these colors when saving out the image, incorrectly figuring that since these pixels are transparent, their RGB values must be irrelevant (for some reason .png codecs seem especially bad at this).      &lt;p&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;Can't use &lt;a href="http://blogs.msdn.com/shawnhar/archive/2008/10/28/texture-compression.aspx" target="_blank"&gt;DXT1 compression&lt;/a&gt;, which only supports transparent pixels with an RGB of zero. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;If you get bored of having to manually fix-up alpha cutout textures, you could automate it using a custom content processor. This could check your textures as part of the build process, automatically replacing the RGB of transparent pixels with a copy of the RGB from the closest opaque pixel.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Solution&lt;/h3&gt;  &lt;p&gt;The best way to fix this is by using premultiplied alpha.&amp;#160; &lt;em&gt;Stay tuned for my next post...&lt;/em&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9916173" width="1" height="1"&gt;</description></item><item><title>New Game Studio samples</title><link>http://blogs.msdn.com/shawnhar/archive/2009/10/22/new-game-studio-samples.aspx</link><pubDate>Thu, 22 Oct 2009 17:31:43 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9911549</guid><dc:creator>ShawnHargreaves</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/shawnhar/comments/9911549.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnhar/commentrss.aspx?PostID=9911549</wfw:commentRss><description>&lt;p&gt;Hot off the press, &lt;a href="http://creators.xna.com/en-US/sample/primitives3D" target="_blank"&gt;this sample&lt;/a&gt; provides handy classes for generating cubes, spheres, and teapots (great for debug rendering!) while &lt;a href="http://creators.xna.com/en-US/tutorial/skinnedmodelextensions" target="_blank"&gt;this one&lt;/a&gt; shows how to do various hopefully useful things with skinned character models.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Notice how Skinned Model Extensions reuses code from the Primitives3D sample for drawing the collision spheres? You'd almost think Primitives3D was created because halfway through writing the skinning stuff I realized I had no way to display that data :-)&lt;/em&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9911549" width="1" height="1"&gt;</description></item><item><title>Texture filtering: mipmapped sprite sheets</title><link>http://blogs.msdn.com/shawnhar/archive/2009/10/22/texture-filtering-mipmapped-sprite-sheets.aspx</link><pubDate>Thu, 22 Oct 2009 17:23:40 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9911536</guid><dc:creator>ShawnHargreaves</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/shawnhar/comments/9911536.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnhar/commentrss.aspx?PostID=9911536</wfw:commentRss><description>&lt;p&gt;&lt;a&gt;Beringela&lt;/a&gt; comments on my &lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/10/21/texture-filtering-sprite-sheets.aspx" target="_blank"&gt;previous post&lt;/a&gt;:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;&amp;quot;Why don't spritesheets (with an edge around each sprite) and mipmaps go well together and are there any workarounds other than not using spritesheets or not using mipmaps?&amp;quot;&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Let's work through an example, which I shall simplify down to one dimension for clarity. Let's say we have two textures, sized 4x1:&lt;/p&gt;  &lt;blockquote&gt;   &lt;table cellspacing="0" cellpadding="2" width="200" border="1"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td valign="top" align="center" width="52"&gt;&lt;strong&gt;A&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="48"&gt;&lt;strong&gt;B&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="49"&gt;&lt;strong&gt;C&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="49"&gt;&lt;strong&gt;D&lt;/strong&gt;&lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/blockquote&gt;  &lt;p&gt;and 2x1:&lt;/p&gt;  &lt;blockquote&gt;   &lt;table cellspacing="0" cellpadding="2" width="100" border="1"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td valign="top" align="center" width="49"&gt;&lt;strong&gt;E&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="49"&gt;&lt;strong&gt;F&lt;/strong&gt;&lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/blockquote&gt;  &lt;p&gt;With gutters, we could pack these into a 10x1 sprite sheet:&lt;/p&gt;  &lt;blockquote&gt;   &lt;table cellspacing="0" cellpadding="2" width="450" border="1"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td valign="top" align="center" width="52"&gt;&lt;em&gt;a&lt;/em&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="43"&gt;&lt;strong&gt;A&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="44"&gt;&lt;strong&gt;B&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="44"&gt;&lt;strong&gt;C&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="44"&gt;&lt;strong&gt;D&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="44"&gt;&lt;em&gt;d&lt;/em&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="44"&gt;&lt;em&gt;e&lt;/em&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="45"&gt;&lt;strong&gt;E&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="45"&gt;&lt;strong&gt;F&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="43"&gt;&lt;em&gt;f&lt;/em&gt;&lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/blockquote&gt;  &lt;p&gt;Now let's compute the first mip level:&lt;/p&gt;  &lt;blockquote&gt;   &lt;table cellspacing="0" cellpadding="2" width="399" border="1"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td valign="top" align="center" width="78"&gt;A&lt;/td&gt;          &lt;td valign="top" align="center" width="93"&gt;(B+C)/2&lt;/td&gt;          &lt;td valign="top" align="center" width="75"&gt;D&lt;/td&gt;          &lt;td valign="top" align="center" width="76"&gt;E&lt;/td&gt;          &lt;td valign="top" align="center" width="75"&gt;F&lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/blockquote&gt;  &lt;p&gt;Hmm. That does somewhat resemble the original sheet, but it no longer has proper gutters, so filtering will bleed from one sprite to the other.&lt;/p&gt;  &lt;p&gt;Real trouble starts with the second mip level:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;/p&gt;    &lt;table cellspacing="0" cellpadding="2" width="350" border="1"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td valign="top" align="center" width="174"&gt;(A*2 + B + C + D) / 5&lt;/td&gt;          &lt;td valign="top" align="center" width="174"&gt;(D + E*2 + F*2) / 5&lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/blockquote&gt;  &lt;p&gt;Our second sprite has disappeared entirely! That rightmost pixel includes colors E and F from sprite #2, but also some amount of color D from sprite #1.&lt;/p&gt;  &lt;p&gt;And of course the final mip is entirely meaningless:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;/p&gt;    &lt;table cellspacing="0" cellpadding="2" width="300" border="1"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td valign="top" align="center" width="298"&gt;(A*2 + B + C + D*2 + E*2 + F*2) / 10&lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/blockquote&gt;  &lt;p&gt;There are two ways you can try to make sprite sheets and mipmaps play together:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;em&gt;Wishful thinking&lt;/em&gt;: include gutters wider than a single pixel, cross your fingers, and hope it turns out ok. Any time you see color bleeding problems, increase the gutter size until they go away.       &lt;p&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;&lt;em&gt;The scientific approach&lt;/em&gt;: restrict all sprites in a sheet to be the same size, so you can terminate your mip chain at the point where an individual sprite has reached 1x1. Calculate the gutter size so you will still have an entire pixel gutter at this smallest mip level, with corresponding larger gutters for larger mips. Generate mip images separately for each sprite, rather than for the sheet as a whole, and regenerate the gutter with different colors for each mip. This is a considerable pain, and wastes a lot of memory (you end up with significantly more gutter pixels than actual data!) but it does work.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Personally, I would avoid using mipmaps and sprite sheets at the same time. Sprite sheets are never &lt;em&gt;necessary&lt;/em&gt;: they're just an optimization to reduce texture switching. When an optimization ends up causing this amount of trouble, you have to wonder if it's really worth it?&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9911536" width="1" height="1"&gt;</description></item><item><title>Texture filtering: sprite sheets</title><link>http://blogs.msdn.com/shawnhar/archive/2009/10/21/texture-filtering-sprite-sheets.aspx</link><pubDate>Wed, 21 Oct 2009 18:25:36 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9910801</guid><dc:creator>ShawnHargreaves</dc:creator><slash:comments>10</slash:comments><comments>http://blogs.msdn.com/shawnhar/comments/9910801.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnhar/commentrss.aspx?PostID=9910801</wfw:commentRss><description>&lt;p&gt;You can control what happens when &lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/10/20/texture-filtering-the-edge-of-the-world.aspx" target="_blank"&gt;texture filtering reads from past the edge of a texture&lt;/a&gt; using the SamplerState.AddressU and AddressV properties. But what if you are using a sprite sheet? The sampler address modes know nothing about how your sprites have been packed together, so when you filter a sprite from a sheet, the GPU will happily sample from outside the area you told it to draw. This causes colors from one sprite to show up along the edges of whatever happens to be packed next to it, which is unlikely to be what you wanted!&lt;/p&gt;  &lt;p&gt;Possible solutions:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Don't use sprite sheets. This is especially a good idea if you want &lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/09/14/texture-filtering-mipmaps.aspx" target="_blank"&gt;mipmaps&lt;/a&gt;, as it is near impossible to make sprite sheets and mipmaps play nice together.       &lt;p&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;Don't use filtering. &lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/09/08/texture-filtering.aspx" target="_blank"&gt;Point sampling&lt;/a&gt; will never read past the edge of the region you specify, so it has no problem with sprite sheets. But then, point sampling tends to look rather ugly, and who wants that?       &lt;p&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;Roll your own filtering in the pixel shader. If you set the GPU to point sampling mode, you could write a shader that implements bilinear filtering by averaging several point samples, and this shader could know about your sprite sheet and thus avoid reading from outside the current sprite. This is likely to be slower than not using sprite sheets at all, though, so not usually a good idea.      &lt;p&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;Add a gutter region around each sprite. Given this 3x3 source image: &lt;/li&gt; &lt;/ul&gt;  &lt;blockquote&gt;   &lt;table cellspacing="0" cellpadding="2" width="100" border="1"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td valign="top" align="center" width="30"&gt;&lt;strong&gt;A&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="34"&gt;&lt;strong&gt;B&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="34"&gt;&lt;strong&gt;C&lt;/strong&gt;&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td valign="top" align="center" width="30"&gt;&lt;strong&gt;D&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="34"&gt;&lt;strong&gt;E&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="34"&gt;&lt;strong&gt;F&lt;/strong&gt;&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td valign="top" align="center" width="30"&gt;&lt;strong&gt;G&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="34"&gt;&lt;strong&gt;H&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="34"&gt;&lt;strong&gt;I&lt;/strong&gt;&lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt;    &lt;p&gt;Expand it to 5x5:&lt;/p&gt;    &lt;table cellspacing="0" cellpadding="2" width="166" border="1"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td valign="top" align="center" width="32"&gt;&lt;em&gt;a&lt;/em&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="33"&gt;&lt;em&gt;a&lt;/em&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="33"&gt;&lt;em&gt;b&lt;/em&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="33"&gt;&lt;em&gt;c&lt;/em&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="33"&gt;&lt;em&gt;c&lt;/em&gt;&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td valign="top" align="center" width="33"&gt;&lt;em&gt;a&lt;/em&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="33"&gt;&lt;strong&gt;A&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="33"&gt;&lt;strong&gt;B&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="33"&gt;&lt;strong&gt;C&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="33"&gt;&lt;em&gt;c&lt;/em&gt;&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td valign="top" align="center" width="33"&gt;&lt;em&gt;d&lt;/em&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="33"&gt;&lt;strong&gt;D&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="33"&gt;&lt;strong&gt;E&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="33"&gt;&lt;strong&gt;F&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="33"&gt;&lt;em&gt;f&lt;/em&gt;&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td valign="top" align="center" width="33"&gt;&lt;em&gt;g&lt;/em&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="33"&gt;&lt;strong&gt;G&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="33"&gt;&lt;strong&gt;H&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="33"&gt;&lt;strong&gt;I&lt;/strong&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="33"&gt;&lt;em&gt;i&lt;/em&gt;&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td valign="top" align="center" width="33"&gt;&lt;em&gt;g&lt;/em&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="33"&gt;&lt;em&gt;g&lt;/em&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="33"&gt;&lt;em&gt;h&lt;/em&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="33"&gt;&lt;em&gt;i&lt;/em&gt;&lt;/td&gt;          &lt;td valign="top" align="center" width="34"&gt;&lt;em&gt;i&lt;/em&gt;&lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt;    &lt;p&gt;Pack the 5x5 version into your sprite sheet, but just draw the inner 3x3 (shown in bold). Now the filtering hardware can happily read past the edge of the specified region, and will pick up sensible color values from the gutter pixels (shown in italic).&lt;/p&gt;    &lt;p&gt;Adding gutters by hand soon gets boring, but this is easy to automate. Our &lt;a href="http://creators.xna.com/en-US/sample/spritesheet" target="_blank"&gt;Sprite Sheet sample&lt;/a&gt; provides a content processor that will pack any number of textures into a sprite sheet, automatically adding the necessary gutters to make filtering work correctly.&lt;/p&gt;&lt;/blockquote&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9910801" width="1" height="1"&gt;</description></item><item><title>Texture filtering: the edge of the world</title><link>http://blogs.msdn.com/shawnhar/archive/2009/10/20/texture-filtering-the-edge-of-the-world.aspx</link><pubDate>Tue, 20 Oct 2009 23:20:38 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9910253</guid><dc:creator>ShawnHargreaves</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/shawnhar/comments/9910253.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnhar/commentrss.aspx?PostID=9910253</wfw:commentRss><description>&lt;p&gt;&lt;em&gt;Long time no post.&amp;#160; But don't worry, &lt;/em&gt;&lt;a href="http://www.youtube.com/watch?v=dGFXGwHsD_A" target="_blank"&gt;&lt;em&gt;I'm not dead yet&lt;/em&gt;&lt;/a&gt;&lt;em&gt;...&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;One of the more surprising things about &lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/09/08/texture-filtering.aspx" target="_blank"&gt;texture filtering&lt;/a&gt; is how easily it can read past the edge of the texture. Consider a 4x1 texture containing four color values:&lt;/p&gt;  &lt;blockquote&gt;   &lt;table cellspacing="0" cellpadding="2" width="250" border="1"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td valign="top" align="center" width="60"&gt;A&lt;/td&gt;          &lt;td valign="top" align="center" width="62"&gt;B&lt;/td&gt;          &lt;td valign="top" align="center" width="62"&gt;C&lt;/td&gt;          &lt;td valign="top" align="center" width="64"&gt;D&lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/blockquote&gt;  &lt;p&gt;If we draw this using SpriteBatch with an integer destination location and no scaling or rotation, these values will be copied directly to the screen. But if we draw with scaling, rotation, or a fractional destination location, the output colors will be computed by filtering between the four input values. As long as our source texture coordinates lie in the range 0-1, these filtering computations should never read past the edge of the texture, right?&lt;/p&gt;  &lt;p&gt;Right?&lt;/p&gt;  &lt;p&gt;&lt;em&gt;(you can probably guess this isn't right, on account of how much of this article is still to read :-)&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Consider what happens if we scale up to cover an 8x1 destination region. The output pixels will be:&lt;/p&gt;  &lt;blockquote&gt;   &lt;table cellspacing="0" cellpadding="2" width="500" border="1"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td valign="top" align="center" width="62"&gt;A&lt;/td&gt;          &lt;td valign="top" align="center" width="66"&gt;(A+B)/2&lt;/td&gt;          &lt;td valign="top" align="center" width="59"&gt;B&lt;/td&gt;          &lt;td valign="top" align="center" width="66"&gt;(B+C)/2&lt;/td&gt;          &lt;td valign="top" align="center" width="59"&gt;C&lt;/td&gt;          &lt;td valign="top" align="center" width="66"&gt;(C+D)/2&lt;/td&gt;          &lt;td valign="top" align="center" width="59"&gt;D&lt;/td&gt;          &lt;td valign="top" align="center" width="61"&gt;&lt;strong&gt;???&lt;/strong&gt;&lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/blockquote&gt;  &lt;p&gt;What should go in that last cell?&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;We could just repeat D again, but that seems kind of odd. If we are drawing a tile map with the same sprite repeated many times to cover a grid, it would cause an ugly discontinuity where one tile joins the next.      &lt;p&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;We could continue the interpolation pattern, wrapping around to fill this last cell with (D+A)/2. This would look good along the joins between tiles, but not so good if we were drawing a character where it could cause colors from one side of the sprite to wrap around and appear on the other! &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The right solution depends on what you are drawing, so there is no universally correct behavior. You can choose which you want by setting the SamplerState.AddressU and AddressV properties to TextureAddressMode.Clamp or TextureAddressMode.Wrap.&lt;/p&gt;  &lt;p&gt;Many people assume these addressing modes are only important if your texture coordinates go outside the range 0-1, but as we see here, filtering can read past the edge of the texture even when the source texture coordinates lie inside it.&lt;/p&gt;  &lt;p&gt;AddressU and AddressV are usually set to the same value, but they do not have to be. For instance the sky.fx shader from our &lt;a href="http://creators.xna.com/en-US/sample/generatedgeometry" target="_blank"&gt;Generated Geometry sample&lt;/a&gt; sets AddressU to Wrap and AddressV to Clamp, because the sky is a cylinder which should wrap from left to right, but we do not want stray pixels from the bottom of the ground wrapping around and appearing directly overhead!&lt;/p&gt;  &lt;p&gt;Scaling is not the only way to run into these issues. Consider what happens if we slide our sprite half a pixel sideways. Now the four output colors are:&lt;/p&gt;  &lt;blockquote&gt;   &lt;table cellspacing="0" cellpadding="2" width="324" border="1"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td valign="top" align="center" width="85"&gt;(A+B)/2&lt;/td&gt;          &lt;td valign="top" align="center" width="85"&gt;(B+C)/2&lt;/td&gt;          &lt;td valign="top" align="center" width="85"&gt;(C+D)/2&lt;/td&gt;          &lt;td valign="top" align="center" width="67"&gt;&lt;strong&gt;???&lt;/strong&gt;&lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/blockquote&gt;  &lt;p&gt;Same dilemma.&amp;#160; Should that last cell contain D, or (D+A)/2?&lt;/p&gt;  &lt;p&gt;Drawing at fractional positions is especially confusing because we intuitively expect the result to be something like:&lt;/p&gt;  &lt;blockquote&gt;   &lt;table cellspacing="0" cellpadding="2" width="400" border="1"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td align="center" width="75"&gt;A (half alpha)&lt;/td&gt;          &lt;td align="center" width="82"&gt;(A+B)/2&lt;/td&gt;          &lt;td align="center" width="83"&gt;(B+C)/2&lt;/td&gt;          &lt;td align="center" width="84"&gt;(C+D)/2&lt;/td&gt;          &lt;td align="center" width="74"&gt;D (half alpha)&lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/blockquote&gt;  &lt;p&gt;But that's not how it works.&amp;#160; &lt;em&gt;Exercise for the reader: what would go wrong if it did?&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;I think the confusing part is that there isn't actually any such thing as drawing at a fractional screen position. Screen pixels can either be written or left alone: you can't change just half a pixel (at least not without alpha blending, which introduces its &lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/02/18/depth-sorting-alpha-blended-objects.aspx" target="_blank"&gt;own set of problems&lt;/a&gt;). So when we ask the GPU to draw at a fractional location, it rounds to the nearest integer, then slides the texture in the opposite direction to make the output appear fractionally positioned. This produces coordinate values outside the original range.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;&amp;quot;But I want my sprite to be rendered like in your last example, with half alpha on both edges!&amp;quot;&lt;/em&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Easy: just make sure the outermost pixels of your texture have zero alpha (give it a single pixel transparent border). Now when you filter using TextureAddressMode.Clamp, the edges will smoothly fade to zero no matter how things are positioned.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;em&gt;&amp;quot;Couldn't I do that automatically using TextureAddressMode.Border?&amp;quot;&lt;/em&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Why yes, indeed you could. But border address mode is not supported by all graphics cards.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;em&gt;&amp;quot;What about rotation?&amp;quot;&lt;/em&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Hopefully by now it will be obvious that filtered rotation can read from outside the source texture region, just like scaling and fractional positioning.&lt;/p&gt;&lt;/blockquote&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9910253" width="1" height="1"&gt;</description></item><item><title>Texture filtering: anisotropy</title><link>http://blogs.msdn.com/shawnhar/archive/2009/09/24/texture-filtering-anisotropy.aspx</link><pubDate>Fri, 25 Sep 2009 02:00:18 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9899217</guid><dc:creator>ShawnHargreaves</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/shawnhar/comments/9899217.aspx</comments><wfw:commentRss>http://blogs.msdn.com/shawnhar/commentrss.aspx?PostID=9899217</wfw:commentRss><description>&lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/09/14/texture-filtering-mipmaps.aspx" target="_blank"&gt;Mipmapping&lt;/a&gt; allows textures to be scaled down by any amount while maintaining high quality filtering and cache-friendly memory access patterns. But mipmaps don't work so well when different axes are scaled by different amounts:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&amp;#160;&lt;img title="Untitled" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="125" alt="Untitled" src="http://blogs.msdn.com/blogfiles/shawnhar/WindowsLiveWriter/Anisotropicfiltering_9F72/Untitled_fa820c4d-c299-4885-a46a-7484451da0bf.png" width="295" border="0" /&gt; &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;How do we choose which mip level to use for the elongated cat?&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;By default the GPU will select mipmaps according to whichever axis has the smallest scale. This is efficient and avoids aliasing artifacts, but can lead to unwanted blurriness along the larger axis.      &lt;p&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;You can use SamplerState.MipMapLevelOfDetailBias to force selection of a larger mip level, which reduces blurriness at the cost of aliasing artifacts and poor cache efficiency. Basically heading back toward the bad old days when we had no mipmaps at all. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Non uniform scaling is rare in 2D (&lt;em&gt;although my cat has been eating so much lately, he is well on the way to horizontally scaling up his belly exactly like the above image &lt;/em&gt;:-) but it happens all the time in 3D:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&amp;#160;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="180" alt="Untitled8" src="http://blogs.msdn.com/blogfiles/shawnhar/WindowsLiveWriter/Anisotropicfiltering_9F72/Untitled8_6a1c4ddd-afcc-4959-a4fd-d1a561dab791.png" width="185" border="0" /&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Any time you apply a perspective transform to a textured triangle which is not exactly facing the camera, non uniform scaling will result.&lt;/p&gt;  &lt;p&gt;Anisotropic filtering improves the quality of these situations by recognizing when textures are being scaled differently in different directions, and taking a larger number of samples to compensate.&lt;/p&gt;  &lt;p&gt;To enable it:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;    device.SamplerStates[0].MinFilter = TextureFilter.Anisotropic;
    device.SamplerStates[0].MagFilter = TextureFilter.Linear;
    device.SamplerStates[0].MipFilter = TextureFilter.Linear;
    device.SamplerStates[0].MaxAnisotropy = &amp;lt;n&amp;gt;;&lt;/pre&gt;

&lt;p&gt;MaxAnisotropy is typically set to 2 or 4. Some recent cards support as high as 16, so check the caps to see how high yours can go.&lt;/p&gt;

&lt;p&gt;How it works:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Compute the aspect ratio between the larger and smaller scaling axes&lt;/li&gt;

  &lt;li&gt;If this is greater than MaxAnisotropy, clamp to MaxAnisotropy&lt;/li&gt;

  &lt;li&gt;Choose mip level according to this value (which will usually be whichever axis is larger)&lt;/li&gt;

  &lt;li&gt;To avoid aliasing, sample the texture multiple times along a line determined by the axis which is being shrunk the most, averaging the results&lt;/li&gt;

  &lt;li&gt;The number of samples depends on the ratio between the larger and smaller axes&lt;/li&gt;

  &lt;li&gt;GPUs are smart: if the scaling happens to be uniform, they will only take a single sample even when anisotropic filtering is enabled&lt;/li&gt;

  &lt;li&gt;Thanks to the aspect ratio clamping, there will never be more than MaxAnisotropy samples per destination pixel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How does it look? Here is our favorite landscape with mipmaps but no anisotropic filtering:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;img height="333" alt="image11" src="http://blogs.msdn.com/blogfiles/shawnhar/WindowsLiveWriter/Anisotropicfiltering_9F72/image11_38ecf7e8-d4b4-40da-baa4-43dd7b4da357.png" width="585" border="0" /&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt; And now with mipmaps plus anisotropic filtering:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;img height="333" alt="image14" src="http://blogs.msdn.com/blogfiles/shawnhar/WindowsLiveWriter/Anisotropicfiltering_9F72/image14_03e61e73-6df2-42bb-9095-3e1e5e96f7e1.png" width="585" border="0" /&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Both images are free from noisy aliasing, but the anisotropic version has better texture detail on surfaces which are angled relative to the camera, and is less blurry.&lt;/p&gt;

&lt;p&gt;So why doesn't everyone use anisotropic filtering all the time?&lt;/p&gt;

&lt;p&gt;Because this quality improvement comes at a price! Sometimes a high price. All these extra samples take time for the texture unit to compute, and cost extra memory bandwidth too.&lt;/p&gt;

&lt;p&gt;Or it might be free. If your game is &lt;a href="http://blogs.msdn.com/shawnhar/archive/2008/04/07/how-to-tell-if-you-are-cpu-or-gpu-bound.aspx" target="_blank"&gt;CPU bound&lt;/a&gt;, or &lt;a href="http://blogs.msdn.com/shawnhar/archive/2008/04/11/santa-s-production-line.aspx" target="_blank"&gt;bottlenecked by a different part of the GPU&lt;/a&gt;, anisotropic texture fetches might not actually slow things down at all. So try turning it on and see what happens. If it is too slow with a high MaxAnisotropy setting, try a smaller value to find the right balance between quality and performance.&lt;/p&gt;

&lt;p&gt;Back when I was working on &lt;a href="http://www.talula.demon.co.uk/blogindex.html#motogp" target="_blank"&gt;MotoGP&lt;/a&gt;, we wanted anisotropic filtering for quality reasons, but couldn't afford to use it everywhere. We ended up tweaking MaxAnisotropy differently for every texture, setting it to 4 for billboard adverts where the quality improvement was especially noticeable, to 3 for most of the road surface and grass, and 2 for less important things like trees and crowds. We sometimes even used different settings for each layer of a multitexturing shader, for instance a high anisotropy for the base texture but none at all for the &lt;a href="http://blogs.msdn.com/shawnhar/archive/2008/11/03/detail-textures.aspx" target="_blank"&gt;detail texture&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9899217" width="1" height="1"&gt;</description></item></channel></rss>