<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><title type="html">Shawn Hargreaves Blog</title><subtitle type="html" /><id>http://blogs.msdn.com/b/shawnhar/atom.aspx</id><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/" /><link rel="self" type="application/atom+xml" href="http://blogs.msdn.com/b/shawnhar/atom.aspx" /><generator uri="http://telligent.com" version="5.6.583.20496">Telligent Community 5.6.583.20496 (Build: 5.6.583.20496)</generator><updated>2011-04-20T13:04:09Z</updated><entry><title>Bloom on Windows Phone</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2012/01/19/bloom-on-windows-phone.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2012/01/19/bloom-on-windows-phone.aspx</id><published>2012-01-20T01:04:11Z</published><updated>2012-01-20T01:04:11Z</updated><content type="html">&lt;p&gt;Ok, &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/12/29/is-spritebatch-turing-complete.aspx" target="_blank"&gt;silliness aside&lt;/a&gt;, is it possible to implement an efficient bloom effect on Windows Phone without custom shaders?&lt;/p&gt;  &lt;p&gt;Bloom consists of three operations:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Identify which parts of the image should be bloomed &lt;/li&gt;    &lt;li&gt;Blur those parts &lt;/li&gt;    &lt;li&gt;Combine blurred bloomy bits with the original image &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;There are many choices for how each operation should be implemented, the combination of which determines the visual result.&amp;#160; In the &lt;a href="http://create.msdn.com/en-US/education/catalog/sample/bloom" target="_blank"&gt;XNA bloom sample&lt;/a&gt;:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Bright areas are identified by subtracting a threshold value, then scaling back up to preserve full color range: (value - threshold) / (1 - threshold) &lt;/li&gt;    &lt;li&gt;Blur is applied using a two pass separable Gaussian filter &lt;/li&gt;    &lt;li&gt;To avoid excessively bright areas, the final combine operation is: (base * (1 – bloom)) + bloom&amp;#160; (done in a pixel shader that also provides brightness and saturation adjustment for both images) &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;There is no good way to adjust saturation without shaders, but everything else in this design can be done with simple alpha blending operations:&lt;/p&gt;  &lt;pre class="_shawn_csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;span class="kwrd"&gt;using&lt;/span&gt; Microsoft.Xna.Framework;
&lt;span class="kwrd"&gt;using&lt;/span&gt; Microsoft.Xna.Framework.Graphics;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; BloomPostprocess
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; BloomComponent : DrawableGameComponent
    {
        &lt;span class="rem"&gt;// Adjust these values to change visual appearance.&lt;/span&gt;
        &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;float&lt;/span&gt; BloomThreshold = 0.25f;
        &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;float&lt;/span&gt; BloomIntensity = 1.5f;
        &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; BlurPasses = 4;


        &lt;span class="rem"&gt;// result = source - destination&lt;/span&gt;
        &lt;span class="kwrd"&gt;static&lt;/span&gt; BlendState extractBrightColors = &lt;span class="kwrd"&gt;new&lt;/span&gt; BlendState
        {
            ColorSourceBlend = Blend.One,
            AlphaSourceBlend = Blend.One,

            ColorDestinationBlend = Blend.One,
            AlphaDestinationBlend = Blend.One,

            ColorBlendFunction = BlendFunction.Subtract,
            AlphaBlendFunction = BlendFunction.Subtract,
        };


        &lt;span class="rem"&gt;// result = source + destination&lt;/span&gt;
        &lt;span class="kwrd"&gt;static&lt;/span&gt; BlendState additiveBlur = &lt;span class="kwrd"&gt;new&lt;/span&gt; BlendState
        {
            ColorSourceBlend = Blend.One,
            AlphaSourceBlend = Blend.One,

            ColorDestinationBlend = Blend.One,
            AlphaDestinationBlend = Blend.One,
        };


        &lt;span class="rem"&gt;// result = source + (destination * (1 - source))&lt;/span&gt;
        &lt;span class="kwrd"&gt;static&lt;/span&gt; BlendState combineFinalResult = &lt;span class="kwrd"&gt;new&lt;/span&gt; BlendState
        {
            ColorSourceBlend = Blend.One,
            AlphaSourceBlend = Blend.One,

            ColorDestinationBlend = Blend.InverseSourceColor,
            AlphaDestinationBlend = Blend.InverseSourceColor,
        };


        SpriteBatch spriteBatch;

        RenderTarget2D scene;
        RenderTarget2D halfSize;
        RenderTarget2D quarterSize;
        RenderTarget2D quarterSize2;


        &lt;span class="kwrd"&gt;public&lt;/span&gt; BloomComponent(Game game)
            : &lt;span class="kwrd"&gt;base&lt;/span&gt;(game)
        { }


        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; LoadContent()
        {
            spriteBatch = &lt;span class="kwrd"&gt;new&lt;/span&gt; SpriteBatch(GraphicsDevice);

            PresentationParameters pp = GraphicsDevice.PresentationParameters;

            &lt;span class="kwrd"&gt;int&lt;/span&gt; w = pp.BackBufferWidth;
            &lt;span class="kwrd"&gt;int&lt;/span&gt; h = pp.BackBufferHeight;

            scene = &lt;span class="kwrd"&gt;new&lt;/span&gt; RenderTarget2D(GraphicsDevice, w, h, &lt;span class="kwrd"&gt;false&lt;/span&gt;, pp.BackBufferFormat, pp.DepthStencilFormat, pp.MultiSampleCount, RenderTargetUsage.DiscardContents);
            halfSize = &lt;span class="kwrd"&gt;new&lt;/span&gt; RenderTarget2D(GraphicsDevice, w / 2, h / 2, &lt;span class="kwrd"&gt;false&lt;/span&gt;, pp.BackBufferFormat, DepthFormat.None);
            quarterSize = &lt;span class="kwrd"&gt;new&lt;/span&gt; RenderTarget2D(GraphicsDevice, w / 4, h / 4, &lt;span class="kwrd"&gt;false&lt;/span&gt;, pp.BackBufferFormat, DepthFormat.None);
            quarterSize2 = &lt;span class="kwrd"&gt;new&lt;/span&gt; RenderTarget2D(GraphicsDevice, w / 4, h / 4, &lt;span class="kwrd"&gt;false&lt;/span&gt;, pp.BackBufferFormat, DepthFormat.None);
        }


        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; BeginDraw()
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (Visible)
            {
                GraphicsDevice.SetRenderTarget(scene);
            }
        }


        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Draw(GameTime gameTime)
        {
            &lt;span class="rem"&gt;// Shrink to half size.&lt;/span&gt;
            GraphicsDevice.SetRenderTarget(halfSize);
            DrawSprite(scene, BlendState.Opaque);

            &lt;span class="rem"&gt;// Shrink again to quarter size, at the same time applying the threshold subtraction.&lt;/span&gt;
            GraphicsDevice.SetRenderTarget(quarterSize);
            GraphicsDevice.Clear(&lt;span class="kwrd"&gt;new&lt;/span&gt; Color(BloomThreshold, BloomThreshold, BloomThreshold));
            DrawSprite(halfSize, extractBrightColors);

            &lt;span class="rem"&gt;// Kawase blur filter (see http://developer.amd.com/media/gpu_assets/Oat-ScenePostprocessing.pdf)&lt;/span&gt;
            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; BlurPasses; i++)
            {
                GraphicsDevice.SetRenderTarget(quarterSize2);
                GraphicsDevice.Clear(Color.Black);

                &lt;span class="kwrd"&gt;int&lt;/span&gt; w = quarterSize.Width;
                &lt;span class="kwrd"&gt;int&lt;/span&gt; h = quarterSize.Height;

                &lt;span class="kwrd"&gt;float&lt;/span&gt; brightness = 0.25f;

                &lt;span class="rem"&gt;// On the first pass, scale brightness to restore full range after the threshold subtraction.&lt;/span&gt;
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (i == 0)
                    brightness /= (1 - BloomThreshold);

                &lt;span class="rem"&gt;// On the final pass, apply tweakable intensity adjustment.&lt;/span&gt;
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (i == BlurPasses - 1)
                    brightness *= BloomIntensity;

                Color tint = &lt;span class="kwrd"&gt;new&lt;/span&gt; Color(brightness, brightness, brightness);

                spriteBatch.Begin(0, additiveBlur);

                spriteBatch.Draw(quarterSize, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(0.5f, 0.5f), &lt;span class="kwrd"&gt;new&lt;/span&gt; Rectangle(i + 1, i + 1, w, h), tint);
                spriteBatch.Draw(quarterSize, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(0.5f, 0.5f), &lt;span class="kwrd"&gt;new&lt;/span&gt; Rectangle(-i, i + 1, w, h), tint);
                spriteBatch.Draw(quarterSize, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(0.5f, 0.5f), &lt;span class="kwrd"&gt;new&lt;/span&gt; Rectangle(i + 1, -i, w, h), tint);
                spriteBatch.Draw(quarterSize, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(0.5f, 0.5f), &lt;span class="kwrd"&gt;new&lt;/span&gt; Rectangle(-i, -i, w, h), tint);
                
                spriteBatch.End();

                Swap(&lt;span class="kwrd"&gt;ref&lt;/span&gt; quarterSize, &lt;span class="kwrd"&gt;ref&lt;/span&gt; quarterSize2);
            }

            &lt;span class="rem"&gt;// Combine the original scene and bloom images.&lt;/span&gt;
            GraphicsDevice.SetRenderTarget(&lt;span class="kwrd"&gt;null&lt;/span&gt;);
            DrawSprite(scene, BlendState.Opaque);
            DrawSprite(quarterSize, combineFinalResult);
        }


        &lt;span class="kwrd"&gt;void&lt;/span&gt; DrawSprite(Texture2D source, BlendState blendState)
        {
            spriteBatch.Begin(0, blendState);
            spriteBatch.Draw(source, GraphicsDevice.Viewport.Bounds, Color.White);
            spriteBatch.End();
        }


        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Swap&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;ref&lt;/span&gt; T a, &lt;span class="kwrd"&gt;ref&lt;/span&gt; T b)
        {
            T tmp = a;
            a = b;
            b = tmp;
        }
    }
}&lt;/pre&gt;


&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;High quality blur filters can be expensive, so most bloom implementations do a cheap bilinear downsample to lower resolution before the ‘real’ blur.&amp;#160; The original XNA sample operates at half resolution, but in a nod to the limited bandwidth of mobile GPUs, I made this version shrink to quarter size.&lt;/p&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;p&gt;It is possible to implement Gaussian blur (or indeed any multi-tap filter) as a series of additive and subtractive blends with suitable offsets, but that gets expensive for large filter kernels.&amp;#160; Instead I chose a Kawase blur (originally developed by Masaki Kawase for the Xbox1 game Wreckless), which cunningly exploits GPU bilinear filtering to get a not-quite-as-good-but-still-ok result more cheaply.&lt;/p&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;p&gt;The threshold subtraction is perhaps the least intuitive operation.&amp;#160; We want (source - threshold), but the alpha blending hardware only gives us (source - destination).&amp;#160; So, we simply clear the destination rendertarget to our desired threshold value before drawing the source image!&lt;/p&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;p&gt;There are two scaling operations in this bloom design: one to preserve full color range after the threshold subtraction, and a second after the blur to adjust intensity of the bloom.&amp;#160; For efficiency, I apply these adjustments during the first and last blur passes, getting them for free as a side effect of drawing work that was already taking place.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So how does it look?&lt;/p&gt;

&lt;p&gt;With BloomThreshold = 0.25f,&amp;#160; BloomIntensity = 1.5f,&amp;#160; BlurPasses = 4:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;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="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/3286.image_5F00_27321E14.png" width="640" height="406" /&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With BloomThreshold = 0.5f,&amp;#160; BloomIntensity = 3,&amp;#160; BlurPasses = 6:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;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="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/0363.image_5F00_0F4B36EE.png" width="640" height="406" /&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With BloomThreshold = 0,&amp;#160; BloomIntensity = 1.5f,&amp;#160; BlurPasses = 3:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;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="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/0363.image_5F00_13750EB3.png" width="640" height="406" /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10258697" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Voting results are in!</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2012/01/19/voting-results-are-in.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2012/01/19/voting-results-are-in.aspx</id><published>2012-01-19T20:04:00Z</published><updated>2012-01-19T20:04:00Z</updated><content type="html">&lt;p&gt;Thanks for the comments about &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/12/29/what-should-i-write-about-next.aspx" target="_blank"&gt;what I should write about next&lt;/a&gt;.&amp;#160; Hopefully I managed to count these more accurately than the &lt;a href="http://www.guardian.co.uk/world/2012/jan/19/mitt-romney-iowa-win-recount" target="_blank"&gt;Iowa Republican party&lt;/a&gt;&amp;#160; :-)&lt;/p&gt;  &lt;blockquote&gt;   &lt;table border="1" cellspacing="0" cellpadding="2" width="184"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td valign="top" width="130"&gt;C++&lt;/td&gt;          &lt;td valign="top" width="52"&gt;16&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td valign="top" width="130"&gt;How GPU’s work&lt;/td&gt;          &lt;td valign="top" width="52"&gt;11&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td valign="top" width="130"&gt;3D math&lt;/td&gt;          &lt;td valign="top" width="52"&gt;10&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td valign="top" width="130"&gt;Game design&lt;/td&gt;          &lt;td valign="top" width="52"&gt;10&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td valign="top" width="130"&gt;SIMD optimization&lt;/td&gt;          &lt;td valign="top" width="52"&gt;3&lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/blockquote&gt;  &lt;p&gt;Of course my blog is not a democracy, so I’m not promising to actually cover these topics in that order!&amp;#160; But it is useful to know that for instance I have more readers interested in C++ than in SIMD optimization.&lt;/p&gt;  &lt;p&gt;There were also several write-in nominations:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;     &lt;p&gt;Specifics of how XNA is implemented.&amp;#160; &lt;em&gt;It does seem like there should be a couple of interesting articles to be had here. I will have to think about exactly what they might be.&lt;/em&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;Managed &amp;lt;-&amp;gt; native interop (esp. WinRT).&amp;#160; &lt;em&gt;Hmm. My immediate reaction is I don’t know enough about this topic, but I will mull it over and see if anything worthwhile comes to mind.&lt;/em&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;A couple of requests to talk about future XNA plans.&amp;#160; &lt;em&gt;Sorry, no can do. Not my team any more!&lt;/em&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;Single-vote requests to write about input, component based entities, and XACT garbage.&amp;#160; &lt;em&gt;Unlikely (due to lack of knowledge / opinions / info to share) but I will bear them in mind.&lt;/em&gt;&lt;/p&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Thank you all!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10258609" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Is SpriteBatch Turing complete?</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/12/29/is-spritebatch-turing-complete.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/12/29/is-spritebatch-turing-complete.aspx</id><published>2011-12-29T22:58:56Z</published><updated>2011-12-29T22:58:56Z</updated><content type="html">&lt;p&gt;&lt;em&gt;Time for some end-of-year silliness...&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Inspired by this recent Twitter exchange:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Scionwest - &lt;em&gt;@shawnhargreaves @nickgravelyn How about post processing for WP7? I've seen people do Bloom effects and thought P.P. was not part of WP7?&lt;/em&gt;&lt;/p&gt;    &lt;p&gt;nickgravelyn - &lt;em&gt;@Scionwest Shaders aren't available, but I've seen some clever post-processing done without custom shaders.&amp;#160; You theoretically could do CPU based &amp;quot;shaders&amp;quot;, but you can also use blend states in fun ways to achieve effects&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;(which is actually an interesting topic that I may someday return to)&lt;/p&gt;  &lt;p&gt;I found myself thinking &amp;quot;&lt;em&gt;well, of course you &lt;/em&gt;could &lt;em&gt;implement bloom, because the no-programmable-shaders Reach graphics subset on Windows Phone is &lt;a href="http://en.wikipedia.org/wiki/Turing_completeness" target="_blank"&gt;Turing complete&lt;/a&gt;, so can do anything you can imagine given sufficient ingenuity. It might not be &lt;/em&gt;easy&lt;em&gt;, &lt;/em&gt;efficient&lt;em&gt;, or &lt;/em&gt;sensible&lt;em&gt;, but anything is possible...&lt;/em&gt;&amp;quot;&lt;/p&gt;  &lt;p&gt;And then I found myself thinking, is that really true?&lt;/p&gt;  &lt;p&gt;We can add and subtract via blend states, and perform comparisons with AlphaTestEffect, which seems like it should be enough to enable arbitrary algorithms (at least if we ignore mundane practicalities such as time and space constraints :-)&amp;#160; But can I &lt;em&gt;prove &lt;/em&gt;that XNA on Windows Phone is enough to enable Turing complete GPU computation?&lt;/p&gt;  &lt;p&gt;Conway's &lt;a href="http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life" target="_blank"&gt;Game of Life&lt;/a&gt; is already proven to be a form of universal Turing machine, so I set out to see if I could implement that on the GPU without custom shaders.&lt;/p&gt;  &lt;p&gt;Starting with the default Game template, I declared two rendertargets to hold the state of my simulation:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; width = 256;
    &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; height = 128;

    RenderTarget2D currentState;
    RenderTarget2D nextState;&lt;/pre&gt;

&lt;p&gt;Plus two helper objects:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    AlphaTestEffect alphaTestEffect;

    Texture2D singleWhitePixel;&lt;/pre&gt;

&lt;p&gt;These are initialized in LoadContent:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    currentState = &lt;span class="kwrd"&gt;new&lt;/span&gt; RenderTarget2D(GraphicsDevice, width, height, &lt;span class="kwrd"&gt;false&lt;/span&gt;, SurfaceFormat.Color, DepthFormat.Depth24Stencil8);
    nextState    = &lt;span class="kwrd"&gt;new&lt;/span&gt; RenderTarget2D(GraphicsDevice, width, height, &lt;span class="kwrd"&gt;false&lt;/span&gt;, SurfaceFormat.Color, DepthFormat.Depth24Stencil8);

    alphaTestEffect = &lt;span class="kwrd"&gt;new&lt;/span&gt; AlphaTestEffect(GraphicsDevice);

    singleWhitePixel = &lt;span class="kwrd"&gt;new&lt;/span&gt; Texture2D(GraphicsDevice, 1, 1);&lt;br /&gt;
    singleWhitePixel.SetData(&lt;span class="kwrd"&gt;new&lt;/span&gt; Color[] { Color.White });&lt;/pre&gt;

&lt;p&gt;In order for it to do anything interesting, the Game of Life must be initialized to more than just zeros. This code (at the end of LoadContent) creates a single glider that will move diagonally across the screen:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    Color[] initialData = &lt;span class="kwrd"&gt;new&lt;/span&gt; Color[width * height];

    initialData[3 + 1 * width] = Color.White;
    initialData[3 + 2 * width] = Color.White;
    initialData[3 + 3 * width] = Color.White;
    initialData[2 + 3 * width] = Color.White;
    initialData[1 + 2 * width] = Color.White;

    currentState.SetData(initialData);&lt;/pre&gt;

&lt;p&gt;For a more interesting initial state, add this (before the currentState.SetData call) to randomize the cells:&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; 10000; i++)
    {
        initialData[random.Next(width * height)] = Color.White;
    }&lt;/pre&gt;

&lt;p&gt;My Draw code is simple.&amp;#160; It uses SamplerState.PointClamp to scale up the current simulation state to fill the entire screen, without any filtering:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    SimulateLife();

    GraphicsDevice.Clear(Color.CornflowerBlue);

    spriteBatch.Begin(SpriteSortMode.Deferred, &lt;span class="kwrd"&gt;null&lt;/span&gt;, SamplerState.PointClamp, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;);
    spriteBatch.Draw(currentState, GraphicsDevice.Viewport.Bounds, Color.White);
    spriteBatch.End();&lt;/pre&gt;

&lt;p&gt;Ok, that's the boilerplate taken care of.&amp;#160; How are we actually going to implement this SimulateLife method?&amp;#160; Wikipedia defines the rules as:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Any live cell with fewer than two live neighbours dies, as if caused by under-population
      &lt;br /&gt;Any live cell with two or three live neighbours lives on to the next generation

      &lt;br /&gt;Any live cell with more than three live neighbours dies, as if by overcrowding

      &lt;br /&gt;Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But I found it useful to rearrange this to a different (equivalent) form:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Rule 1:&amp;#160; If there are two live neighbours, preserve the current state of the cell
      &lt;br /&gt;Rule 2:&amp;#160; If there are three live neighbours, set the cell to alive

      &lt;br /&gt;Rule 3:&amp;#160; Otherwise set the cell to dead&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ok, let's do it!&amp;#160; SimulateLife starts by drawing onto the nextState rendertarget, and setting up the AlphaTestEffect to only accept pixels with alpha greater than 128, i.e.. cells that are currently alive:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    GraphicsDevice.SetRenderTarget(nextState);

    GraphicsDevice.Clear(Color.Transparent);

    Viewport viewport = GraphicsDevice.Viewport;

    Matrix projection = Matrix.CreateOrthographicOffCenter(0, viewport.Width, viewport.Height, 0, 0, 1);
    Matrix halfPixelOffset = Matrix.CreateTranslation(-0.5f, -0.5f, 0);

    alphaTestEffect.Projection = halfPixelOffset * projection;

    alphaTestEffect.AlphaFunction = CompareFunction.Greater;
    alphaTestEffect.ReferenceAlpha = 128;&lt;/pre&gt;

&lt;p&gt;We are going to count how many alive neighbours each cell has, accumulating this value in the stencil buffer (which was previously cleared to zero).&amp;#160; We do this by drawing the current simulation state texture 8 times, shifted one pixel to the top left, top, top right, left, etc.&amp;#160; We use a blend state that prevents drawing anything to the color buffer, because we are only interested in generating stencil values.&amp;#160; This code combines AlphaTestEffect (which rejects dead neighbour pixels) and the stencil buffer (which counts how many neighbour pixels pass the alpha test):&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    spriteBatch.Begin(SpriteSortMode.Deferred, blendNone, &lt;span class="kwrd"&gt;null&lt;/span&gt;, stencilAdd, &lt;span class="kwrd"&gt;null&lt;/span&gt;, alphaTestEffect);

    spriteBatch.Draw(currentState, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(-1, -1), Color.White);
    spriteBatch.Draw(currentState, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2( 0, -1), Color.White);
    spriteBatch.Draw(currentState, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2( 1, -1), Color.White);
    spriteBatch.Draw(currentState, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(-1,  0), Color.White);
    spriteBatch.Draw(currentState, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2( 1,  0), Color.White);
    spriteBatch.Draw(currentState, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(-1,  1), Color.White);
    spriteBatch.Draw(currentState, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2( 0,  1), Color.White);
    spriteBatch.Draw(currentState, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2( 1,  1), Color.White);

    spriteBatch.End();&lt;/pre&gt;

&lt;p&gt;This uses two custom state objects:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; BlendState blendNone = &lt;span class="kwrd"&gt;new&lt;/span&gt; BlendState
    {
        ColorSourceBlend = Blend.Zero,
        ColorDestinationBlend = Blend.One,

        AlphaSourceBlend = Blend.Zero,
        AlphaDestinationBlend = Blend.One,

        ColorWriteChannels = ColorWriteChannels.None,
    };

    &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; DepthStencilState stencilAdd = &lt;span class="kwrd"&gt;new&lt;/span&gt; DepthStencilState
    {
        DepthBufferEnable = &lt;span class="kwrd"&gt;false&lt;/span&gt;,
        StencilEnable = &lt;span class="kwrd"&gt;true&lt;/span&gt;,
        StencilFunction = CompareFunction.Always,
        StencilPass = StencilOperation.Increment,
    };&lt;/pre&gt;

&lt;p&gt;We now have our rendertarget cleared to zero (which means all dead, so we have already implemented rule #3),&amp;#160; while stencil contains a count of live neighbour cells.&amp;#160; It is but the work of a moment to draw a copy of the current simulation state, using stencil to only accept cells that have 2 live neighbours, thus implementing rule #1:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, &lt;span class="kwrd"&gt;null&lt;/span&gt;, stencilDrawIf2, &lt;span class="kwrd"&gt;null&lt;/span&gt;);
    spriteBatch.Draw(currentState, Vector2.Zero, Color.White);
    spriteBatch.End();&lt;/pre&gt;

&lt;p&gt;The last draw call implements rule #2 by rendering solid white (which means alive) over only those cells which have 3 live neighbours:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, &lt;span class="kwrd"&gt;null&lt;/span&gt;, stencilDrawIf3, &lt;span class="kwrd"&gt;null&lt;/span&gt;);
    spriteBatch.Draw(singleWhitePixel, viewport.Bounds, Color.White);
    spriteBatch.End();&lt;/pre&gt;

&lt;p&gt;This requires two new state objects:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; DepthStencilState stencilDrawIf2 = &lt;span class="kwrd"&gt;new&lt;/span&gt; DepthStencilState
    {
        DepthBufferEnable = &lt;span class="kwrd"&gt;false&lt;/span&gt;,
        StencilEnable = &lt;span class="kwrd"&gt;true&lt;/span&gt;,
        StencilFunction = CompareFunction.Equal,
        ReferenceStencil = 2,
    };

    &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; DepthStencilState stencilDrawIf3 = &lt;span class="kwrd"&gt;new&lt;/span&gt; DepthStencilState
    {
        DepthBufferEnable = &lt;span class="kwrd"&gt;false&lt;/span&gt;,
        StencilEnable = &lt;span class="kwrd"&gt;true&lt;/span&gt;,
        StencilFunction = CompareFunction.Equal,
        ReferenceStencil = 3,
    };&lt;/pre&gt;

&lt;p&gt;Finally, the end of SimulateLife unsets our output rendertarget, then swap the two rendertargets, replacing the current state with the new one we just computed:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    GraphicsDevice.SetRenderTarget(&lt;span class="kwrd"&gt;null&lt;/span&gt;);

    Swap(&lt;span class="kwrd"&gt;ref&lt;/span&gt; currentState, &lt;span class="kwrd"&gt;ref&lt;/span&gt; nextState);&lt;/pre&gt;

&lt;p&gt;Swap is a handy little helper, implemented like so:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;    static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Swap&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;ref&lt;/span&gt; T a, &lt;span class="kwrd"&gt;ref&lt;/span&gt; T b)
    {
        T temp = a;
        a = b;
        b = temp;
    }&lt;/pre&gt;

&lt;p&gt;So, does it work?&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/3716.image_5F00_1305EC40.png"&gt;&lt;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="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/2234.image_5F00_thumb_5F00_32B4C608.png" width="640" height="406" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tada!&amp;#160; SpriteBatch is Turing complete :-)&lt;/p&gt;

&lt;p&gt;Exercise for the reader: is it possible to do the same thing &lt;em&gt;without &lt;/em&gt;using stencil?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10251913" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>What should I write about next?</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/12/29/what-should-i-write-about-next.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/12/29/what-should-i-write-about-next.aspx</id><published>2011-12-29T19:34:46Z</published><updated>2011-12-29T19:34:46Z</updated><content type="html">&lt;p&gt;I have a couple more articles planned about aliasing and motion blur, but am curious to hear where you would like me to take this blog next.&lt;/p&gt;  &lt;p&gt;Some topics I am considering:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;C++&lt;/strong&gt;.&amp;#160; Dirty secret: although I've mostly blogged about C# programming, much of XNA itself is written in C++, so I've actually been straddling both worlds for years.&amp;#160; And interesting things are happening in C++ land right now, with the arrival of C++11 and maturity of the standard library affecting best practices and recommended style.&amp;#160; But are my readers interested in such things?&amp;#160; You tell me!&lt;/p&gt;  &lt;p&gt;More about &lt;strong&gt;how GPU's work&lt;/strong&gt;.&amp;#160; Tiling, swizzling, caching, parallelism, predication, etc.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;3D Math&lt;/strong&gt;.&amp;#160; Vectors, matrices, what really is an orientation, how to think in multiple coordinate spaces, and why rotation angles are Teh Evil.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Game design&lt;/strong&gt;.&amp;#160; What makes it fun?&amp;#160; What makes a good AI?&amp;#160; How does one persuade customers to try/buy your work?&amp;#160; I've been reluctant to cover these topics because it's not really my area of expertise, but I do have some opinions about it so who knows, maybe a few worthwhile articles to be had here.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;SIMD optimization&lt;/strong&gt;, SSE, DirectXMath.&lt;/p&gt;  &lt;p&gt;Other?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10251836" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>From games to telephones</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/12/13/from-games-to-telephones.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/12/13/from-games-to-telephones.aspx</id><published>2011-12-14T00:22:45Z</published><updated>2011-12-14T00:22:45Z</updated><content type="html">&lt;p&gt;After six years working on XNA, I decided it was time to take on a new challenge.&amp;#160; I am moving to the Windows Phone team, where I will be working on things I'm not sure how much I can say about here&amp;#160; (leaking future business plans on MSDN might not be the best way to endear myself to my new boss :-)&lt;/p&gt;  &lt;p&gt;Writing this post is a bittersweet moment for me.&amp;#160; I'm excited by what the future holds for Windows Phone, and looking forward to my chance to be part of that, but also sad to leave a team and product that have given me so much satisfaction.&amp;#160; There'll be no going back once I hit that &lt;em&gt;Publish &lt;/em&gt;button a few minutes from now...&lt;/p&gt;  &lt;p&gt;I feel an urge to wax nostalgic about some of my favorite times with XNA:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;     &lt;p&gt;Staying up all night to &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2006/12/11/mysterious-goings-on-in-the-night.aspx" target="_blank"&gt;watch Michael purchase the first ever Creators Club subscription&lt;/a&gt;.&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;The first Dream Build Play competition, when we got to see the first actual games made with our technology&amp;#160; (&lt;a href="http://create.msdn.com/en-US/community/spotlight/dishwasher" target="_blank"&gt;Dishwasher FTW&lt;/a&gt;!)&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;On stage with Mitch at Gamefest, where I wrote a network game 'from scratch'&amp;#160; (if you ignore some minor snippet cheating :-)&amp;#160; in less than an hour.&amp;#160; I'm still blown away by the fact that our APIs were simple enough to make this possible.&amp;#160; Also amazed that the demo actually worked, considering what an unstable early build we were using!&amp;#160; Unfortunately there is no video of this, and the &lt;a href="http://download.microsoft.com/download/7/2/a/72afc5a1-17a9-452a-a4cf-b975e8f3225e/Networking%20with%20the%20XNA%20Framework.zip" target="_blank"&gt;slides&lt;/a&gt; don't do it justice since the whole point was the live coding demo.&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;On stage once more at MIX, demonstrating &lt;a href="http://channel9.msdn.com/events/MIX/MIX10/CL22" target="_blank"&gt;XNA graphics on the new Windows Phone&lt;/a&gt; with a frighteningly last minute demo cobbled together just a few days earlier using a hot-off-the-presses build of XNA on an even more experimental frankenbuild of the phone OS.&amp;#160; Then rushing back to my hotel room to blog about the new features coming in XNA 4.0&amp;#160; (which, modesty aside, I still think is some of the best design work I have done to date).&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;Trying to decide, of all the lines of code I have written in my life, which one has been executed the most times?&amp;#160; I think it must be the default SpriteBatch pixel shader.&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;Last but not least, spending time with y'all on forums and this blog, where I got to know so many great people and see the amazing things you create.&lt;/p&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;I'm not yet sure what this means for my blog.&amp;#160; I want to keep writing, but will probably cover more general graphics and game development topics, and will obviously no longer have inside scoop on XNA implementation details.&amp;#160; I'm also not sure how much time I will have for writing, especially in the early months as I settle into the new job, but I will do my best.&lt;/p&gt;  &lt;p&gt;Ok, I'm off now to meet some new people and learn my way around a whole new product.&lt;/p&gt;  &lt;p&gt;&amp;lt;nervously excited&amp;gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10247403" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Temporal sampling frequency (aka 'framerate')</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/11/18/temporal-sampling-frequency-aka-framerate.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/11/18/temporal-sampling-frequency-aka-framerate.aspx</id><published>2011-11-19T00:21:47Z</published><updated>2011-11-19T00:21:47Z</updated><content type="html">&lt;blockquote&gt;   &lt;p&gt;Game player:&amp;#160; &amp;quot;&lt;em&gt;d00d, teh framerate totally sux0rz!&lt;/em&gt;&amp;quot;&lt;/p&gt;    &lt;p&gt;Game developer:&amp;#160; &amp;quot;&lt;em&gt;we are experiencing aliasing due to low sampling frequency along the temporal axis...&lt;/em&gt;&amp;quot;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;One of the many decisions that goes into making a game is whether it is better to run at a high framerate, which means drawing many frames per second and thus having little time to spend on each, or should we choose a lower framerate, get more time per frame, and thus be able to draw larger numbers of higher quality objects?&amp;#160; The perfect balance is a matter of heated debate, varying with the game, genre, and personal preference, but there are some widely accepted truths:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Dropping below 30 fps is rarely a good idea &lt;/li&gt;    &lt;li&gt;30 fps is generally considered ok, but 60 is better&lt;/li&gt;    &lt;li&gt;Higher than 60 fps offers rapidly diminishing returns &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Yet movies are animated at a mere 24 fps!&amp;#160; Why has Hollywood chosen a framerate so much lower than most game developers?&lt;/p&gt;  &lt;p&gt;Perhaps this is just a historical legacy, preserved for backward compatibility with decisions made in the 1920s?&amp;#160; But when IMAX was designed in the late 1960s, they specified new cameras, film, projectors, and screens, while keeping the 24 fps sampling frequency.&amp;#160; And in the early 21st century, Blu-ray and HD DVD fought an entire format war during the transition to high definition digital video, but oh look, still 24 fps.&amp;#160; It sure looks like the movie world just doesn't see any reason to go higher, similar to how few game developers care to go above 60 fps.&lt;/p&gt;  &lt;p&gt;Ok, next theory: perhaps the difference is because games are interactive, while movies are just prerecorded entertainment?&amp;#160; The lower the framerate, the more latency there will be between providing an input and seeing the resulting change on screen.&amp;#160; The pause button on my DVR remote has ~.5 sec latency, which is irrelevant when watching my favorite romantic comedy but would be a showstopper when trying to nail a Halo headshot.&lt;/p&gt;  &lt;p&gt;And a final theory: perhaps the difference is due to aliasing?&amp;#160; Realtime graphics are usually point sampled along the time axis, as we render individual frames based on the state of the game at a single moment in time, with no consideration of what came before or what will happen next.&amp;#160; Movies, on the other hand, are beautifully antialiased, as the physical nature of a camera accumulates all light that reaches the sensor while the shutter is open.&amp;#160; We've all seen the resulting blurry photos when we try to snap something that is moving too quickly, or fail to hold the camera properly still.&amp;#160; Motion blur is usually considered a flaw when it shows up uninvited in our vacation snapshots, but when capturing video it provides wonderfully high quality temporal antialiasing.&lt;/p&gt;  &lt;p&gt;So which theory is correct?&amp;#160; Do games care more than movies about framerate because of latency, or because of aliasing?&lt;/p&gt;  &lt;p&gt;We can find out with a straightforward experiment.&amp;#160; Write a game that runs at 60 fps.&amp;#160; Make another version of the same game that runs at 30 fps.&amp;#160; Make a third version at 30 fps with super high quality temporal antialiasing (aka motion blur).&amp;#160; Get some people to play all three versions.&amp;#160; Get more people to watch the first people playing.&amp;#160; Compare their reactions.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;If aliasing is a significant factor, the watchers will be able to distinguish 60 fps from 30 fps, but unable to distinguish 60 fps from motion blurred 30 fps &lt;/li&gt;    &lt;li&gt;If latency is a significant factor, people playing the game will be able to distinguish 60 fps from motion blurred 30 fps, even though the watchers cannot &lt;/li&gt;    &lt;li&gt;If everybody can tell the versions apart, both theories must be wrong&lt;/li&gt;    &lt;li&gt;If nobody can tell any difference, we might as well just leave the whole game at 30 fps and be done with it&amp;#160; :-)&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;If you try this experiment, you will find the results depend on which game you choose to test with.&amp;#160; Many observers do indeed think motion blurred 30 fps looks the same as 60 fps, so temporal aliasing is surely important.&amp;#160; Players also find the two equivalent with some games, while reporting a big difference with other games.&amp;#160; So the significance of latency depends on the game in question.&lt;/p&gt;  &lt;p&gt;Sensitivity to latency is directly proportional to how hands-on the input mechanism is.&amp;#160; When you move a mouse, even the slightest lag in cursor motion will feel very bad (which is why the mouse has a dedicated hardware cursor, allowing it to update at a higher framerate than the rest of whatever app is using it).&amp;#160; Likewise for looking around in an FPS, or pinch zooming on a touch screen.&amp;#160; You are directly manipulating something, so expect it to respond straight away and for the motion to feel pinned to your finger.&amp;#160; Less direct control schemes, such as pressing a fire button, moving around in an FPS, driving a vehicle, or clicking on a unit in an RTS, can tolerate higher latencies.&amp;#160; The more indirect things become, the less latency matters, which is why third person games can often tolerate lower framerates than would be acceptable in an FPS.&lt;/p&gt;  &lt;p&gt;What can we learn from all this rambling?&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;     &lt;p&gt;If we have a game at 60 fps, and are trying to find room to add more sophisticated graphics, an interesting option might be to drop down to 30 fps while adding motion blur.&amp;#160; As long as we can implement a good blur for less than the cost of drawing one 60 fps frame, we may be able to achieve equivalent visual quality while freeing up a bunch of GPU cycles.&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;If we have a game at 30 fps or lower, we should avoid the sort of input behaviors that will make this latency objectionable to the player.&amp;#160; Conversely, if we have a game that uses only the sort of input not sensitive to latency, there is less point bothering to make it run at 60 fps! &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;em&gt;Yeah. yeah, so I should talk about how to actually&lt;/em&gt; &lt;strong&gt;&lt;em&gt;implement&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;motion blur.&amp;#160; Next time...&lt;/em&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10238714" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Stand still and they won't see you</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/11/07/stand-still-and-they-won-t-see-you.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/11/07/stand-still-and-they-won-t-see-you.aspx</id><published>2011-11-08T01:54:06Z</published><updated>2011-11-08T01:54:06Z</updated><content type="html">&lt;p&gt;So far I have &lt;a href="http://www.shawnhargreaves.com/blogindex.html#antialiasing" target="_blank"&gt;written about aliasing&lt;/a&gt; in the context of rendering single images, but neglected to consider what happens when we string a series of images together, attempting to create the illusion of smooth motion.&amp;#160; Animation introduces the temporal (time) axis, which we sample by rendering frames usually 30 or 60 times per second.&amp;#160; And remember, &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/20/why-sampling-a-signal-causes-aliasing.aspx" target="_blank"&gt;whenever we sample from a theoretically continuous signal, aliasing can ensue&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Yet the biggest impact of animation is often not new aliasing at all, but how it makes any existing aliasing far more objectionable. If you have aliased &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/27/multisampling.aspx" target="_blank"&gt;triangle edges&lt;/a&gt;, &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/29/texture-aliasing.aspx" target="_blank"&gt;textures&lt;/a&gt;, &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/05/18/geometry-aliasing.aspx" target="_blank"&gt;geometry&lt;/a&gt;, or &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/10/31/shader-aliasing.aspx" target="_blank"&gt;shaders&lt;/a&gt;, some portion of your output pixels will be determined by aliasing noise as opposed to an accurate representation of the desired image.&amp;#160; A small amount of random noise may be unnoticeable in a still image, but when the camera moves even a fraction, the nature of aliasing means these random elements will be different for every frame.&amp;#160; Because the human eye is drawn to motion, even a few percent aliasing noise over an otherwise stable image becomes painfully obvious as the scene shimmers, strobes, flickers, and crawls.&lt;/p&gt;  &lt;p&gt;When testing graphics code, always view with a camera that moves the same way as your final game.&amp;#160; That is the only way to judge whether you have aliasing under control.&lt;/p&gt;  &lt;p&gt;Aliasing can sometimes be 'fixed' simply by getting rid of motion!&amp;#160; In &lt;a href="http://www.shawnhargreaves.com/blogindex.html#motogp" target="_blank"&gt;MotoGP&lt;/a&gt; we mapped special cameras for use during replays, trying to emulate how a race would be filmed for TV.&amp;#160; Some of these cameras were low to the ground, looking down a straight section of track with an extremely narrow field of view (aka telephoto lens).&amp;#160; These unusual angles let to nasty aliasing that was not visible during normal gameplay.&amp;#160; We fixed it by locking the problematic cameras in place, setting a flag that forbade them from rotating or changing zoom level.&amp;#160; The aliasing was technically still as bad, but because it no longer moved, the game looked much better.&lt;/p&gt;  &lt;p&gt;A similar technique is used in some shadow mapping implementations, which calculate light projections in such a way as to snap shadow map texels to a fixed worldspace grid. The shadow map no longer moves through texel space, so aliasing is less noticeable.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10234830" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Shader aliasing</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/10/31/shader-aliasing.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/10/31/shader-aliasing.aspx</id><published>2011-11-01T01:07:24Z</published><updated>2011-11-01T01:07:24Z</updated><content type="html">&lt;p&gt;&lt;em&gt;Looking through my backlog of half written articles, I realized I have a couple more topics in my &lt;/em&gt;&lt;a href="http://www.talula.demon.co.uk/blogindex.html#antialiasing" target="_blank"&gt;&lt;em&gt;series about antialiasing&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, which I had entirely forgotten about!&amp;#160; Oops...&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Actually, though, today is a good day to finish this article.&amp;#160; Forget your ghosts, ghouls, and goblins, for I have something &lt;strong&gt;Really Truly Very Scarily Horrible &lt;/strong&gt;indeed.&amp;#160; Yes, boys and girls, today marks the return of the &lt;strong&gt;ALIASING MONSTER!&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;A shader is really just a program that computes what color pixels should end up on the screen.&amp;#160; Depending on the details of what this program does, it could cause aliasing, or it could use any imaginable technique (including any of the things I previously discussed) to avoid aliasing.&lt;/p&gt;  &lt;p&gt;For instance, consider a pixel shader that implements a vector rasterization algorithm.&amp;#160; Invoked by C# code that draws a simple square:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;    spriteBatch.Begin(0, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;, effect); 
    spriteBatch.Draw(flatWhiteDummyTexture, &lt;span class="kwrd"&gt;new&lt;/span&gt; Rectangle(0, 0, 128, 128), Color.White); 
    spriteBatch.End();&lt;/pre&gt;

&lt;p&gt;If we apply this pixel shader:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    float2 circleCenter = { 0.5, 0.5 }; 
    &lt;span class="kwrd"&gt;float&lt;/span&gt; circleRadius = 0.4; 
    &lt;span class="kwrd"&gt;float&lt;/span&gt; spriteSize = 128;

    float4 PixelShaderFunction(float4 color : COLOR0, float2 uv : TEXCOORD0) : COLOR0 
    { 
        &lt;span class="kwrd"&gt;float&lt;/span&gt; distanceFromCenter = length(circleCenter - uv); 
        &lt;span class="kwrd"&gt;float&lt;/span&gt; distanceFromCircle = abs(circleRadius - distanceFromCenter) * spriteSize; 
    
        &lt;span class="kwrd"&gt;float&lt;/span&gt; alpha = (distanceFromCircle &amp;lt; 0.5) ? 1 : 0;

        &lt;span class="kwrd"&gt;return&lt;/span&gt; color * alpha; 
    }

    technique Technique1 
    { 
        pass Pass1 
        { 
            PixelShader = compile ps_2_0 PixelShaderFunction(); 
        } 
    } &lt;/pre&gt;

&lt;p&gt;We get a circle:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/4617.image_5F00_31E90FB9.png"&gt;&lt;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="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/1563.image_5F00_thumb_5F00_7A7EEA8B.png" width="128" height="128" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But it is an aliased circle.&amp;#160; We can fix this by changing the alpha computation in our pixel shader to:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;float&lt;/span&gt; alpha = saturate(1 - distanceFromCircle);&lt;/pre&gt;

&lt;p&gt;Which gives a nicer, antialiased result:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/0572.image_5F00_36F34B37.png"&gt;&lt;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="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/0363.image_5F00_thumb_5F00_4F425153.png" width="128" height="128" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Zoomed in so you can see the difference more clearly:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/3000.image_5F00_529FD4FC.png"&gt;&lt;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="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/0842.image_5F00_thumb_5F00_3D018860.png" width="192" height="192" /&gt;&lt;/a&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/1513.image_5F00_7975E90B.png"&gt;&lt;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="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/1184.image_5F00_thumb_5F00_78C91EE2.png" width="192" height="192" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ok, so this is a contrived case.&amp;#160; And the way I implemented this antialiasing is specific to this particular circle algorithm.&amp;#160; It isn't especially useful to say &amp;quot;&lt;em&gt;depending on what they do, some shaders may cause aliasing, but there may be specialized ways you can change them to antialias their computations&lt;/em&gt;&amp;quot; :-)&amp;#160;&amp;#160; Is there some more general principle that be extracted here?&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;Vertex Shader Aliasing&lt;/h4&gt;

&lt;p&gt;Perhaps surprisingly, vertex shaders are not usually a source of aliasing problems, at least so long as your triangles remain large enough to avoid &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/05/18/geometry-aliasing.aspx" target="_blank"&gt;geometry aliasing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The vertex shader is responsible for computing two things:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Position of each vertex on the screen, which causes geometry aliasing if the resulting triangles are too small&lt;/li&gt;

  &lt;li&gt;Values such as colors and texture coordinates, which are interpolated and then passed to the pixel shader&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Regardless of whether these interpolated values are looked up from vertex buffers or computed by whatever crazy piece of math you can imagine, it is basically impossible for them to cause aliasing.&amp;#160; Remember that aliasing occurs when we resample a signal containing frequencies above the &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/20/how-to-resample-a-signal-without-aliasing.aspx" target="_blank"&gt;Nyquist threshold&lt;/a&gt;.&amp;#160; We can think of color or texture coordinate channels as a waveform:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Frequency is determined by the distance between vertices (aka triangle size)&lt;/li&gt;

  &lt;li&gt;Changing the value of the color or texture coordinate alters the amplitude of the waveform, but not usually its frequency&lt;/li&gt;

  &lt;li&gt;Changing values can reduce frequency if several adjacent vertices share identical values, but can never increase it above the limit determined by triangle size&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means that, having taken care to avoid small triangles that would cause geometry aliasing, you need not worry about aliasing elsewhere in your vertex processing.&lt;/p&gt;

&lt;p&gt;Note that, although choice of color or texture coordinates cannot introduce aliasing that was not previously present, it can affect how noticeable previously existing aliasing is in practice.&amp;#160; If you had a model with nasty geometry aliasing, but colored the whole thing subtle shades of grey, the aliasing might not be too offensive.&amp;#160; Change the colors to a rainbow of primary shades, and even though we altered the amplitude but not frequency of our color signal, the geometry aliasing will now be clear for all to see.&amp;#160; It was there all along, but our choice of colors can make the problem more or less obvious.&amp;#160; Regardless, such problems are best tackled by fixing the geometry aliasing at source (which means using larger triangles) rather than trying to paper over them by changing vertex color or texture coordinate mappings.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;Pixel Shader Aliasing&lt;/h4&gt;

&lt;p&gt;The pixel shader is where things get interesting.&amp;#160; This is a function that takes interpolated values from the vertex shader, applies an arbitrary computation, and produces an output color for a single screen pixel.&amp;#160; The previous section explained how, as long as your triangles are not too small, the pixel shader input values will not be aliased, but it is both possible and common for pixel shader computations to introduce entirely new aliasing of their own.&lt;/p&gt;

&lt;p&gt;Whenever a pixel shader applies a computation to an input value it is useful to ask yourself, does this alter the frequency of the signal, or change its amplitude, or both?&amp;#160; If the former, aliasing may ensue, but if the latter, we are safe.&lt;/p&gt;

&lt;p&gt;Consider these common shader operations:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    color = textureColor * lightColor;

    alpha *= 2;

    result = lerp(baseTexture, environmentMap, fresnelAmount);

    intensity = dot(normal, lightDirection);&lt;/pre&gt;

&lt;p&gt;These are all linear computations, which means they change amplitude but not frequency, and so will not cause aliasing.&lt;/p&gt;

&lt;p&gt;These, on the other hand, are not linear. They have the potential to increase the frequency of the output signal above that of the input, so aliasing must be a concern any time you encounter a shader that does such things:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    color = (alpha &amp;lt; 0.5) ? red : green;

    color = lookupTable[alpha];

    result = pow(nDotL, 16);&lt;/pre&gt;

&lt;p&gt;The act of indexing into a lookup table is especially important to graphics programmers, because this is exactly what we do each time we sample a texture map!&amp;#160; Fortunately, GPUs provide &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/29/texture-aliasing.aspx" target="_blank"&gt;sophisticated mechanisms to avoid aliasing when performing such lookups&lt;/a&gt;.&amp;#160; If your pixel shader contains other nonlinear math that is causing aliasing artifacts, a good solution is often to replace these computations with a texture lookup, thus bringing the power of bilinear filtering and mipmaps to bear on the problem.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;Specular Light Aliasing&lt;/h4&gt;

&lt;p&gt;One of the most everyday and yet pernicious examples of shader aliasing is the humble &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2007/04/12/specularity.aspx" target="_blank"&gt;specular light&lt;/a&gt;.&amp;#160; This is so common and inoffensive that we built it into the standard BasicEffect lighting model, and yet specular lighting involves a power computation which is inherently nonlinear, and thus a source of aliasing.&amp;#160; The higher you crank the specular power setting, the shiner the object looks, and also the worse the aliasing becomes.&lt;/p&gt;

&lt;p&gt;Surprisingly for something that is so widely used, there is no universally accepted solution for specular aliasing problems.&amp;#160; Many people just turn down their specular intensity or specular power for whichever models show the worst artifacts, put up with minor remaining flaws, and call it good.&lt;/p&gt;

&lt;p&gt;A full discussion of how to antialias specular lighting is beyond the scope of this article.&amp;#160; The &lt;a href="http://blog.selfshadow.com/2011/07/22/specular-showdown/" target="_blank"&gt;Self Shadow blog has a great summary of the topic&lt;/a&gt;.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10231896" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>RIP John McCarthy</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/10/25/rip-john-mccarthy.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/10/25/rip-john-mccarthy.aspx</id><published>2011-10-25T19:05:03Z</published><updated>2011-10-25T19:05:03Z</updated><content type="html">&lt;p&gt;What a sad month for those of us who program computers.&lt;/p&gt;  &lt;p&gt;Take a moment to reflect on &lt;a href="http://www-formal.stanford.edu/jmc/recursive/recursive.html" target="_blank"&gt;this paper&lt;/a&gt;, published in April 1960:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;No provision need be made for the user to program the return of registers to the free-storage list. &lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;This return takes place automatically, approximately as follows (it is necessary to give a simplified description of this process in this report): There is a fixed set of base registers in the program which contains the locations of list structures that are accessible to the program. Of course, because list structures branch, an arbitrary number of registers may be involved. Each register that is accessible to the program is accessible because it can be reached from one or more of the base registers by a chain of &lt;/em&gt;car &lt;em&gt;and &lt;/em&gt;cdr&lt;em&gt; operations. When the contents of a base register are changed, it may happen that the register to which the base register formerly pointed cannot be reached by a &lt;/em&gt;car - cdr&lt;em&gt; chain from any base register. Such a register may be considered abandoned by the program because its contents can no longer be found by any possible program; hence its contents are no longer of interest, and so we would like to have it back on the free-storage list. This comes about in the following way. &lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;Nothing happens until the program runs out of free storage. When a free register is wanted, and there is none left on the free-storage list, a reclamation cycle starts. &lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;First, the program finds all registers accessible from the base registers and makes their signs negative. This is accomplished by starting from each of the base registers and changing the sign of every register that can be reached from it by a &lt;/em&gt;car - cdr&lt;em&gt; chain. If the program encounters a register in this process which already has a negative sign, it assumes that this register has already been reached. &lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;After all of the accessible registers have had their signs changed, the program goes through the area of memory reserved for the storage of list structures and puts all the registers whose signs were not changed in the previous step back on the free-storage list, and makes the signs of the accessible registers positive again. &lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;This process, because it is entirely automatic, is more convenient for the programmer than a system in which he has to keep track of and erase unwanted lists. Its efficiency depends upon not coming close to exhausting the available memory with accessible lists. This is because the reclamation process requires several seconds to execute, and therefore must result in the addition of at least several thousand registers to the free-storage list if the program is not to spend most of its time in reclamation.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;This was on a computer with single digit kilobytes of memory, in a world where high level languages were still an unproven, experimental idea.&amp;#160; Yet to this day, much of what we consider 'new' in mainstream programming languages (C# 3.0, anyone?) boils down to pieces of Lisp wrapped up with a more friendly syntax!&lt;/p&gt;  &lt;p&gt;A great man, truly ahead of his time, whose work benefited us all.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10229955" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Silverlight 3D and the composition thread</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/10/18/silverlight-3d-and-the-composition-thread.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/10/18/silverlight-3d-and-the-composition-thread.aspx</id><published>2011-10-18T18:51:43Z</published><updated>2011-10-18T18:51:43Z</updated><content type="html">&lt;h4&gt;A simple test&lt;/h4&gt;  &lt;p&gt;Load the Silverlight 5 port of the XNA bloom sample (which you can find in &lt;em&gt;c:/Program Files (x86)/Microsoft SDKs/Silverlight/v5.0/Toolkit/Sep11/Source/Sample source code.zip/Xna &lt;/em&gt;after installing the Silverlight toolkit).&amp;#160; Run it, and observe the shiny tank.&lt;/p&gt;  &lt;p&gt;Now open up MainPage.xaml.cs, find the OnDraw method, and add this line:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;    int&lt;/span&gt; test = SettingsCombo.SelectedIndex;&lt;/pre&gt;

&lt;p&gt;Run the sample again:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;&lt;strong&gt;CrossAppDomainMarshaledException was unhandled 
        &lt;br /&gt;&lt;/strong&gt;System.UnauthorizedAccessException: Invalid cross-thread access. 

      &lt;br /&gt;at MS.Internal.XcpImports.CheckThread() 

      &lt;br /&gt;at System.Windows.DependencyObject.GetValueInternal(DependencyProperty dp) 

      &lt;br /&gt;at System.Windows.FrameworkElement.GetValueInternal(DependencyProperty dp) 

      &lt;br /&gt;at System.Windows.Controls.Primitives.Selector.get_SelectedIndex() 

      &lt;br /&gt;at Bloom.MainPage.OnDraw(Object sender, DrawEventArgs e)&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;What's going on?&lt;/h4&gt;

&lt;p&gt;The traditional XNA Game class is not multithreaded.&amp;#160; Sure, you can create threads of your own if you want, but parallel programming is strictly opt-in, so if you don't do anything special to make it happen, you won't have to worry about the insanity that is threaded programming.&lt;/p&gt;

&lt;p&gt;Silverlight used to work the same way.&amp;#160; It has a single UI thread which is responsible for all user code, event handlers, and XAML rendering.&amp;#160; But &lt;a href="http://www.wintellect.com/CS/blogs/jprosise/archive/2011/04/20/silverlight-5-s-new-and-improved-threading-architecture.aspx" target="_blank"&gt;Silverlight 5 adds a new composition thread&lt;/a&gt;, which takes care of GPU accelerated rendering (although software rendering still runs on the UI thread).&amp;#160; The advantage of this architecture is that, even if you block the UI thread running some lengthy operation, the composition thread can independently continue to play back XAML animations, thus providing a smoother UI with less glitching.&amp;#160; Of course, the downside is that threaded programming is REALLY HARD, but since all your code still runs on the UI thread, you don't generally have to worry about this.&amp;#160; Those clever coding gnomes on the Silverlight team have taken care of the necessary synchronization so the composition thread can do its thing without customer code needing to know or care that things are now running in parallel behind the scenes.&lt;/p&gt;

&lt;p&gt;Enter the 3D DrawingSurface...&lt;/p&gt;

&lt;p&gt;Unlike the rest of Silverlight, which uses a retained mode XAML rendering architecture, DrawingSurface provides an immediate mode 3D API.&amp;#160; Because this rendering is GPU accelerated, the DrawingSurface.Draw event must occur, not on the UI thread along with the rest of your code, but directly on the composition thread.&lt;/p&gt;

&lt;p&gt;Here be dragons!&amp;#160; Even though you never created any threads of your own, the simple act of hooking the Draw event means your 3D rendering code can run in parallel with regular UI code.&amp;#160; Thus you find yourself inadvertently deep in the land of locks, interlocks, deadlocks, race conditions, and suchlike fun stuff&amp;#160; :-)&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;What does this mean for me?&lt;/h4&gt;

&lt;p&gt;If you are making a game that uses only 3D rendering without any XAML UI, you can put all your code (both Update and Draw) inside the DrawingSurface.Draw event.&amp;#160; Regardless of whether you choose &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/10/17/game-timing-in-silverlight-5.aspx" target="_blank"&gt;variable or fixed timestep logic&lt;/a&gt;, this means the UI thread will be entirely unused, so there is no parallelism to worry about and everything will Just Work™ the way you expect.&lt;/p&gt;

&lt;p&gt;If you combine 3D rendering with XAML UI, you must figure out how to synchronize access to any data that is shared between the two.&amp;#160; In the bloom sample (which uses XAML UI to alter bloom settings) you will notice the rendering code does not read its settings directly from the Silverlight controls.&amp;#160; Instead, MainPage.xaml hooks the change events from these controls (which run on the UI thread) and copies their settings into fields which can be safely accessed by the composition thread.&amp;#160; If the shared data structure was more complex, we would need a lock to coordinate this access.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10227082" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Game timing in Silverlight 5</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/10/17/game-timing-in-silverlight-5.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/10/17/game-timing-in-silverlight-5.aspx</id><published>2011-10-17T23:18:30Z</published><updated>2011-10-17T23:18:30Z</updated><content type="html">&lt;p&gt;One thing missing from the &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/10/05/silverlight-5-brings-xna-3d-to-the-web.aspx" target="_blank"&gt;new 3D functionality in Silverlight 5&lt;/a&gt; is an equivalent of the XNA Game class.&amp;#160; I previously wrote about how to provide XNA style &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2010/12/06/when-winforms-met-game-loop.aspx" target="_blank"&gt;Update and Draw methods in a WinForms environment&lt;/a&gt;.&amp;#160; What is the Silverlight equivalent of that?&lt;/p&gt;  &lt;p&gt;After installing the Silverlight Toolkit, create a new project using the &lt;em&gt;Silverlight 3D Application &lt;/em&gt;template.&amp;#160; Open up MainPage.xaml, and note how this declares a DrawingSurface object and hooks its Draw event.&amp;#160; Now open MainPage.xaml.cs, and observe the implementation of the myDrawingSurface_Draw event handler method. After calling scene.Draw(), this calls e.InvalidateSurface(), which tells Silverlight this object needs to be redrawn.&amp;#160; Normally Silverlight would draw the object once at startup, then only redraw it when something changed about the scene (perhaps because the object was resized, or some other shape moved over the top of it).&amp;#160; But when the draw handler invalidates the surface, that causes it to be drawn again, which invalidates it again, which causes it to be drawn again, which { rinse, lather, repeat }.&amp;#160; This effectively creates an infinite loop, with the surface constantly being redrawn, just like we want for a game loop.&lt;/p&gt;  &lt;p&gt;Note also the UserControl_Loaded method in MainPage.xaml.cs, which is hooked up to the UserControl.Loaded event via MainPage.xaml.&amp;#160; This is the Silverlight equivalent of the XNA Initialize and LoadContent methods.&lt;/p&gt;  &lt;p&gt;Well and good, but how do we build an actual game on top of this system?&amp;#160; Check out the Silverlight port of the XNA Platformer starter kit (in &lt;em&gt;c:/Program Files (x86)/Microsoft SDKs/Silverlight/v5.0/Toolkit/Sep11/Source/Sample source code.zip/Xna&lt;/em&gt;).&amp;#160; Again look at the myDrawingSurface_Draw method in MainPage.xaml.cs.&amp;#160; This is very simple:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; myDrawingSurface_Draw(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, DrawEventArgs e)
    {
        platformerGame.Update(e);
        platformerGame.Draw(e);

        e.InvalidateSurface();
    }&lt;/pre&gt;

&lt;p&gt;What we have here is a variable timestep game loop.&amp;#160; Thanks to the InvalidateSurface call, it will loop forever, calling Update and then Draw as fast as possible.&lt;/p&gt;

&lt;p&gt;If you prefer to use a &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2007/07/25/understanding-gametime.aspx" target="_blank"&gt;fixed timestep&lt;/a&gt; system, you can make one like so:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;readonly&lt;/span&gt; TimeSpan TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 60);
    &lt;span class="kwrd"&gt;readonly&lt;/span&gt; TimeSpan MaxElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 10);

    TimeSpan accumulatedTime;


    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; myDrawingSurface_Draw(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, DrawEventArgs e)
    {
        TimeSpan elapsedTime = e.DeltaTime;

        &lt;span class="kwrd"&gt;if&lt;/span&gt; (elapsedTime &amp;gt; MaxElapsedTime)
        {
            elapsedTime = MaxElapsedTime;
        }

        accumulatedTime += elapsedTime;

        &lt;span class="kwrd"&gt;while&lt;/span&gt; (accumulatedTime &amp;gt;= TargetElapsedTime)
        {
            Update();
            accumulatedTime -= TargetElapsedTime;
        }

        Draw();
        e.InvalidateSurface();
    }&lt;/pre&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10226686" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Silverlight 5 version of Ito's XNA AppWeek game</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/10/07/silverlight-5-version-of-ito-s-xna-appweek-game.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/10/07/silverlight-5-version-of-ito-s-xna-appweek-game.aspx</id><published>2011-10-07T22:59:37Z</published><updated>2011-10-07T22:59:37Z</updated><content type="html">&lt;p&gt;Could this be the first ever 3D Silverlight game?&lt;/p&gt;  &lt;p&gt;My colleague Ito ported the rail shooter that he originally wrote for &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2010/09/28/appweek-2010.aspx"&gt;AppWeek 2010&lt;/a&gt; to use the new &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/10/05/silverlight-5-brings-xna-3d-to-the-web.aspx"&gt;3D features in Silverlight 5&lt;/a&gt;.&amp;#160; First get the &lt;a href="http://go.microsoft.com/fwlink/?LinkId=213904"&gt;SL5 RC&lt;/a&gt; plugin (if you don't have it already).&amp;#160; Then &lt;a href="http://higeneko.net/app/SL5/CR/"&gt;play the game here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Once the intro animation finishes playing, mouse over enemy ships to target them, and left click to fire.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;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="Untitled" border="0" alt="Untitled" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/1663.Untitled_5F00_2E86DF86.jpg" width="640" height="429" /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10222014" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Silverlight 5 brings XNA 3D to the web</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/10/05/silverlight-5-brings-xna-3d-to-the-web.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/10/05/silverlight-5-brings-xna-3d-to-the-web.aspx</id><published>2011-10-06T00:13:00Z</published><updated>2011-10-06T00:13:00Z</updated><content type="html">&lt;p&gt;I have been remiss in not mentioning this on my blog before, but if you are an XNA developer who hasn't been paying attention to Silverlight 5, now might be a good time to start!&lt;/p&gt;
&lt;p&gt;A quick history:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;At the MIX11 conference in April, we announced that &lt;a href="http://channel9.msdn.com/Events/MIX/MIX11/MED06"&gt;Silverlight 5 was adding a new 3D API&lt;/a&gt;.&amp;nbsp; This is based on XNA, so included familiar types such as GraphicsDevice, VertexBuffer, and Texture2D, but it was not a full port of XNA.&amp;nbsp; In particular it did not include many of the higher level helper features, so there was no BasicEffect, no SpriteBatch, no math library, and no Content Pipeline.&amp;nbsp; It did support custom shaders, but using a low level DX9 style constant register API as opposed to the friendlier Effect system used by XNA.&amp;nbsp; This beta release made it possible to use high performance 3D in a Silverlight web app, but it wasn't exactly easy to do so!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In September, the Silverlight 5 RC added new features including the same &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2010/04/28/new-built-in-effects-in-xna-game-studio-4-0.aspx"&gt;five built-in effects as XNA 4.0&lt;/a&gt;, plus an XNA compatible math library.&amp;nbsp; &lt;a href="http://blogs.msdn.com/b/eternalcoding/archive/2011/09/01/silverlight-5-rc-what-s-new-in-the-3d-world.aspx"&gt;David Catuhe writes about these changes&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now, the &lt;a href="http://silverlight.codeplex.com/releases/view/74436"&gt;Silverlight Toolkit&lt;/a&gt; provides vastly improved XNA compatibility, including ContentManager, Model, SpriteBatch, Mouse, Keyboard, custom effects, and new Visual Studio templates for getting started with Silverlight 3D.&amp;nbsp; Again &lt;a href="http://blogs.msdn.com/b/eternalcoding/archive/2011/10/04/silverlight-toolkit-september-2011-for-silverlight-5-what-s-new.aspx"&gt;David has a great intro&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is still not &lt;em&gt;all &lt;/em&gt;of XNA (for instance there is no Game class) but with this new toolkit, enough pieces are the same that porting existing Xbox or Windows Phone games to the web can be quite easy.&amp;nbsp; It took us just a few hours to port several existing XNA samples, which are included in the toolkit (&lt;em&gt;Toolkit/Sep11/Source/Sample source code.zip&lt;/em&gt;):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/3583.image_5F00_4617D4F7.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/7823.image_5F00_thumb_5F00_321E4261.png" border="0" height="407" width="640" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you want to use the Content Pipeline in a Silverlight 5 app, you will also need to install XNA Game Studio 4.0 on your development PC.&amp;nbsp; But don't worry, this doesn't mean you will have to redistribute XNA to your web clients, or have it installed on every computer that runs the app.&amp;nbsp; Remember this diagram from an old &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2008/11/24/content-pipeline-assemblies.aspx"&gt;article about the Content Pipeline&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/0550.Untitled_5F00_959e27ef_2D00_8b80_2D00_42e7_2D00_b2df_2D00_102e4f20199c_5F00_03C4BCB4.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="Untitled_959e27ef-8b80-42e7-b2df-102e4f20199c" alt="Untitled_959e27ef-8b80-42e7-b2df-102e4f20199c" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/7416.Untitled_5F00_959e27ef_2D00_8b80_2D00_42e7_2D00_b2df_2D00_102e4f20199c_5F00_thumb_5F00_63A9AFF6.png" border="0" height="233" width="651" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The way this works with Silverlight 5 is that the blue boxes, which run at build time on your development PC, use the original XNA Game Studio 4.0 Content Pipeline assemblies.&amp;nbsp; Only the red boxes, which execute at runtime on the client machine, use the new code from the Silverlight Toolkit.&amp;nbsp; This is similar to when you build an XNA game for Xbox or Windows Phone, but the remote device is now a web browser.&amp;nbsp; If you are extending the Content Pipeline to add new types, you will need to provide both an XNA version of these types for use at build time, and also a Silverlight version for runtime.&amp;nbsp; Check out the Silverlight port of the Skinning sample for an example of how to set this up.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I don't normally name names, as I'm lucky to work with so many talented people and this blog is my chance to take credit for all their hard work :-)&amp;nbsp; But in this case I want to give a shout out to Aaron Oneal and David Catuhe, who went above and beyond to pull all the pieces together and make this happen.&amp;nbsp; Nice job guys!&lt;/em&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10220948" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Content pipeline builds no longer need a D3D device starting in the XNA Game Studio 4.0 Refresh Beta 2</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/07/07/content-pipeline-builds-no-longer-need-a-d3d-device-starting-in-the-xna-game-studio-4-0-refresh-beta-2.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/07/07/content-pipeline-builds-no-longer-need-a-d3d-device-starting-in-the-xna-game-studio-4-0-refresh-beta-2.aspx</id><published>2011-07-07T21:02:21Z</published><updated>2011-07-07T21:02:21Z</updated><content type="html">&lt;p&gt;&lt;em&gt;(shamelessly stealing the title of a post by my colleague Aaron)&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;In fact, why don't I let him provide the content as well as title:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://blogs.msdn.com/b/astebner/archive/2011/07/07/10184338.aspx" href="http://blogs.msdn.com/b/astebner/archive/2011/07/07/10184338.aspx"&gt;http://blogs.msdn.com/b/astebner/archive/2011/07/07/10184338.aspx&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10184343" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>XNB file format documentation</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/07/07/xnb-file-format-documentation.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/07/07/xnb-file-format-documentation.aspx</id><published>2011-07-07T17:51:43Z</published><updated>2011-07-07T17:51:43Z</updated><content type="html">&lt;p&gt;&lt;em&gt;Recent silence notwithstanding, I'm still here, and will have more to say about aliasing as soon as I find myself less busy!&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;In the meantime, check out this latest App Hub release:&amp;#160; &lt;a title="http://create.msdn.com/en-US/sample/xnb_format" href="http://create.msdn.com/en-US/sample/xnb_format"&gt;http://create.msdn.com/en-US/sample/xnb_format&lt;/a&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;This article documents the format of the compiled data files (.xnb) produced by the XNA Game Studio 4.0 Content Pipeline build process. This information may be useful if you wish to write your own code to load .xnb files into a programming environment other than XNA / .NET, or if you wish to create .xnb files independently of the usual Content Pipeline build process.&lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;It also includes an example .xnb parser, written in native C++, which demonstrates how to parse a compiled XNB file by printing its contents to the screen. This can be used as a reference to help you understand how to write your own XNB loader, and also as a debugging tool for investigating exactly what data is contained within an XNB file.&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10184280" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Reza's blog</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/06/06/reza-s-blog.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/06/06/reza-s-blog.aspx</id><published>2011-06-06T19:05:56Z</published><updated>2011-06-06T19:05:56Z</updated><content type="html">&lt;p&gt;My colleague Reza recently started a blog at &lt;a href="http://blogs.msdn.com/b/rezanour"&gt;http://blogs.msdn.com/b/rezanour&lt;/a&gt;.&amp;#160; He already has some good posts about vector math, and is a smart guy so I'm betting will be writing many interesting things in the future :-)&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10171739" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Geometry aliasing</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/05/18/geometry-aliasing.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/05/18/geometry-aliasing.aspx</id><published>2011-05-18T22:01:32Z</published><updated>2011-05-18T22:01:32Z</updated><content type="html">&lt;p&gt;Back when &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/27/multisampling.aspx"&gt;multisampling&lt;/a&gt; first showed up, GPU hardware was slow, so triangle counts were low.&amp;#160; Complex curved shapes were approximated by a small number of faceted triangles, each of which was big enough to cover many screen pixels.&lt;/p&gt;  &lt;p&gt;This created an odd situation where early articles about multisampling focused on how it could smooth jaggies along the straight edges of these enormous triangles.&amp;#160; We’d become so used to the faceted appearance of computer graphics that we could geek out over how beautifully antialiased our triangle edges were, without ever stopping to notice “&lt;em&gt;whoah, that dude’s entire head is made of just 5 triangles!&lt;/em&gt;”&lt;/p&gt;  &lt;p&gt;But hardware improved.&amp;#160; Triangle counts went up.&amp;#160; A high end modern game typically uses somewhere between 4000 and 6000 triangles for a main character.&lt;/p&gt;  &lt;p&gt;Consider a typical gameplay situation:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The character is drawn in such a way that it occupies 1/8 the height of the screen &lt;/li&gt;    &lt;li&gt;The game is rendering at 720p, so the resulting image is 90 pixels high &lt;/li&gt;    &lt;li&gt;That means it covers ~2000 screen pixels &lt;/li&gt;    &lt;li&gt;Assume half of our 6000 triangles are backfacing &lt;/li&gt;    &lt;li&gt;We are left with 3000 triangles, covering 2000 output pixels &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;With this much detail in our models, faceted geometry is a thing of the past.&amp;#160; Instead we have a new problem: we just got Nyquisted!&lt;/p&gt;  &lt;p&gt;Remember: &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/20/how-to-resample-a-signal-without-aliasing.aspx"&gt;to avoid aliasing we must take at least twice as many output samples as our highest frequency input signal&lt;/a&gt;.&amp;#160; But here we have FEWER output pixels than input triangles.&amp;#160; It is intuitively obvious that this must cause aliasing. With fewer pixels than triangles, some triangles will inevitably not appear in the output image at all. As the object moves, which triangles are lucky enough to get themselves a pixel will randomly vary, so the image shimmers with aliasing as individual triangles pop in and out of view.&lt;/p&gt;  &lt;p&gt;In fact there is a narrow sweet spot for how many triangles a model should contain.&amp;#160; For best quality, you want each triangle to cover exactly two screen pixels.&amp;#160; If triangles are smaller than this, you cross the Nyquist threshold and get aliasing.&amp;#160; If larger, your silhouette will appear polygonal and faceted.&lt;/p&gt;  &lt;p&gt;It is not entirely intuitive that the sweet spot is two pixels per triangle as opposed to just one, yet this is true.&amp;#160; Consider a circle being approximated as a series of straight line segments. As you increase the number of segments, the circle becomes more perfectly round.&amp;#160; By the time each line segment reaches two pixels in length, the circle is perfect.&amp;#160; Adding more line segments beyond this point will not give any improvement to the curvature of the shape.&lt;/p&gt;  &lt;p&gt;It is obviously impractical to keep all our triangles exactly the same size on screen, given that models must be drawn at different sizes as they or the player move around the world.&amp;#160; So how can we draw high detail geometry without aliasing?&lt;/p&gt;  &lt;p&gt;Multisampling (or supersampling if you can afford it) helps by giving more headroom before we hit the Nyquist threshold, but this alone is not enough to avoid all geometry aliasing.&lt;/p&gt;  &lt;p&gt;Normalmaps can be a powerful technique. We have &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/29/texture-aliasing.aspx"&gt;great features for avoiding aliasing when resampling textures&lt;/a&gt;, so any time we can take fine detail out of our geometry and replace it with a normalmap, that will help control aliasing.&amp;#160; We often think of normalmaps as purely a performance optimization (replacing expensive geometry with a cheap texture map) but they can also boost visual quality (replacing a data representation that cannot be easily filtered with one that supports anisotropic filtering and mipmaps).&lt;/p&gt;  &lt;p&gt;Finally, it is important to consider level-of-detail model variants. When the object is far away, replacing that 6000 triangle model with a simpler 1000 or 500 triangle alternative will not only boost perf, but also reduce geometry aliasing artifacts.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Moral: when it comes to triangle counts, more is not always better!&amp;#160; Beware of trying to draw more triangles than you have screen pixels to represent. That way lieth the land of aliasing.&lt;/em&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10166069" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Antialiasing alpha cutouts</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/05/06/antialiasing-alpha-cutouts.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/05/06/antialiasing-alpha-cutouts.aspx</id><published>2011-05-06T21:29:11Z</published><updated>2011-05-06T21:29:11Z</updated><content type="html">&lt;p&gt;Alpha cutouts (where you use the alpha channel of a texture to determine the shape of a sprite or billboard) are the cause of many an aliasing problem. There are basically two ways to do alpha cutouts, both tragically flawed.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Alpha blended cutouts&lt;/h4&gt;  &lt;p&gt;As long as you start with high quality source textures, and draw them using bilinear filtering and mipmaps, alpha blended cutout textures can be pleasingly free of aliasing artifacts.&lt;/p&gt;  &lt;p&gt;But &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2009/02/18/depth-sorting-alpha-blended-objects.aspx" target="_blank"&gt;alpha blending does not play nice with the depth buffer&lt;/a&gt;, and it can be a PITA to manually depth sort every piece of alpha cutout geometry!&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Alpha tested cutouts&lt;/h4&gt;  &lt;p&gt;In an attempt to make the hardware depth buffer work with alpha cutouts, many developers switch from full alpha blending to alpha testing (using the XNA AlphaTestEffect, or the clip() HLSL pixel shader intrinsic). This does indeed avoid the complexity of manually sorting alpha blended objects, but at the cost of aliasing.&lt;/p&gt;  &lt;p&gt;The problem is that alpha testing only provides a boolean on/off decision, with no ability to draw fractional alpha values.&lt;/p&gt;  &lt;p&gt;In mathematical terms, when we quantize a smoothly varying signal such as the alpha channel of a texture into a binary on/off decision, we are increasing the amount of high frequency data in our signal, which moves the Nyquist threshold in the wrong direction and hence increases aliasing.&lt;/p&gt;  &lt;p&gt;Or I can avoid the math and try a common sense explanation:&lt;/p&gt;  &lt;p&gt;We would normally &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/05/03/antialiased-source-textures.aspx" target="_blank"&gt;antialias our source textures&lt;/a&gt; by including fractional values around shape borders, but alpha testing does not support fractional alpha values, so this is no longer possible.&lt;/p&gt;  &lt;p&gt;We would normally avoid aliasing when resampling textures via &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/29/texture-aliasing.aspx" target="_blank"&gt;bilinear filtering and mipmapping&lt;/a&gt;. But even if the original texture uses only on/off boolean alpha, when we filter between multiple texels, or scale it down to create 1/2, 1/4, and 1/8 size mip levels, these will inevitably end up with fractional alpha values. To use alpha testing, we must round all such values to either fully transparent or fully opaque, which entirely defeats the point of filtering and mipmapping.&lt;/p&gt;  &lt;p&gt;We would normally avoid aliasing along the edges of triangle geometry by &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/27/multisampling.aspx" target="_blank"&gt;multisampling&lt;/a&gt;, but remember this only runs the pixel shader one per final output pixel. Since each group of multisamples gets a single alpha value from this single shader invocation, each multisample inevitably also has the same alpha test result, so multisampling is useless when it comes to smoothing our alpha cutout silhouette.&lt;/p&gt;  &lt;p&gt;Yowser!&amp;#160; Our entire arsenal of antialiasing techniques just vanished in a puff of smoke...&lt;/p&gt;  &lt;p&gt;The only common antialiasing technique that works with alpha tested cutouts is &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/26/supersampling.aspx" target="_blank"&gt;supersampling&lt;/a&gt;.&amp;#160; Which is great if you can afford it, but most games cannot.&lt;/p&gt;  &lt;p&gt;Example time.&amp;#160; Consider this image, taken from the XNA &lt;a href="http://create.msdn.com/en-US/education/catalog/sample/billboard" target="_blank"&gt;billboard sample&lt;/a&gt;, which uses full alpha blending with a two pass depth sorting technique:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;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="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/1205.image_5F00_02F11F3F.png" width="684" height="429" /&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;If I change the code to use alpha testing instead of blending, standard depth buffer sorting works with no more need for that expensive two pass technique, but at the cost of nasty aliasing on the thinner parts of the grass fronds:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;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="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/3771.image_5F00_1D216296.png" width="684" height="429" /&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;How to fix this?&lt;/p&gt;  &lt;p&gt;You don't.&amp;#160; There are really just three choices for alpha cutouts:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Go for quality over simplicity. Use full alpha blending, and manually sort by depth.&lt;/li&gt;    &lt;li&gt;Put up with sorting artifacts. Use full alpha blending, but don't bother to depth sort.&lt;/li&gt;    &lt;li&gt;Put up with aliasing problems. Use alpha testing, and let the depth buffer handle sorting.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;In &lt;a href="http://www.talula.demon.co.uk/blogindex.html#motogp" target="_blank"&gt;MotoGP&lt;/a&gt; we used a mixture of #2 and #3, and let the artists choose which was the lesser evil for each alpha cutout texture.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10161961" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Antialiasing source textures</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/05/03/antialiased-source-textures.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/05/03/antialiased-source-textures.aspx</id><published>2011-05-03T19:12:34Z</published><updated>2011-05-03T19:12:34Z</updated><content type="html">&lt;p&gt;This is almost too obvious to be worth pointing out, but no amount of clever tricks like bilinear filtering and mipmapping will help if your input data is itself already aliased!&lt;/p&gt;  &lt;p&gt;Yet the example texture used in my &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/29/texture-aliasing.aspx" target="_blank"&gt;previous post&lt;/a&gt; had nasty pixelization along the diagonal black lines:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;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="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/3157.image_5F00_0984F028.png" width="128" height="128" /&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I can improve this just by editing the source image in a paint program:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;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="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/6675.image_5F00_68FDB075.png" width="128" height="128" /&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Compare these two versions at original size:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;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="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/1817.image_5F00_76CFF670.png" width="32" height="32" /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;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="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/6607.image_5F00_28C796FB.png" width="32" height="32" /&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;When a sprite is drawn without any resampling (at an integer pixel location, with no scaling or rotation) the resulting image is an exact copy of the source data, so it is obviously important that this source data contain as little aliasing as possible. Perhaps less obvious is that manually antialiasing my source data also helps when the texture is resampled. In mathematical terms, by smoothing the diagonal lines I have reduced the amount of high frequency information in my source signal, thus gaining more headroom to resample this signal before I will run into the Nyquist threshold and encounter aliasing.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Simple moral of this story: &lt;/em&gt; high quality antialiased textures are better than crappy ones with aliasing problems :-)&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Alternative moral for those who find themselves suspicious of oversimplification: &lt;/em&gt; if you find yourself with the occasional texture that just won't stop aliasing no matter what you do, consider applying a blur to the relevant source images. Blurring removes high frequency data, which shifts the Nyquist threshold, which may be enough to fix the aliasing. This can obviously be taken too far (it's no good if we fix aliasing by making everything blurry!) but the occasional subtle blur, judiciously applied, can be a valuable weapon in the antialiasing arsenal.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10160565" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Texture aliasing</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/29/texture-aliasing.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/04/29/texture-aliasing.aspx</id><published>2011-04-29T23:18:07Z</published><updated>2011-04-29T23:18:07Z</updated><content type="html">&lt;p&gt;Aliasing can occur any time you &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/20/why-sampling-a-signal-causes-aliasing.aspx" target="_blank"&gt;resample a texture&lt;/a&gt;, for instance to scale it, rotate it, or map it onto a 3D model. Thanks to our friend the &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/20/how-to-resample-a-signal-without-aliasing.aspx" target="_blank"&gt;Nyquist threshold&lt;/a&gt;, the resulting problems get worse the lower a frequency you sample at, ie. the smaller you shrink it.&lt;/p&gt;  &lt;p&gt;Check out this awesome 32x32 test image:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;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="Untitled" border="0" alt="Untitled" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/2705.Untitled_5F00_15AECA6E.png" width="32" height="32" /&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Zoomed 4x so you can see in detail:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/0652.image_5F00_5C2BBA76.png" width="128" height="128" /&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;This test code draws six copies, first with no transform, then rotated, followed by straight and rotated versions at half and quarter size:&lt;/p&gt;  &lt;p&gt;   &lt;pre class="csharpcode"&gt;    spriteBatch.Begin(0, &lt;span class="kwrd"&gt;null&lt;/span&gt;, SamplerState.PointClamp, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;);

    spriteBatch.Draw(testTexture, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(20, 24), &lt;span class="kwrd"&gt;null&lt;/span&gt;, Color.White, 0, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(16, 16), 1, 0, 0);
    spriteBatch.Draw(testTexture, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(60, 24), &lt;span class="kwrd"&gt;null&lt;/span&gt;, Color.White, 1, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(16, 16), 1, 0, 0);

    spriteBatch.Draw(testTexture, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(95, 24), &lt;span class="kwrd"&gt;null&lt;/span&gt;, Color.White, 0, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(16, 16), 0.5f, 0, 0);
    spriteBatch.Draw(testTexture, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(120, 24), &lt;span class="kwrd"&gt;null&lt;/span&gt;, Color.White, 1, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(16, 16), 0.5f, 0, 0);

    spriteBatch.Draw(testTexture, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(140, 24), &lt;span class="kwrd"&gt;null&lt;/span&gt;, Color.White, 0, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(16, 16), 0.25f, 0, 0);
    spriteBatch.Draw(testTexture, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(155, 24), &lt;span class="kwrd"&gt;null&lt;/span&gt;, Color.White, 1, &lt;span class="kwrd"&gt;new&lt;/span&gt; Vector2(16, 16), 0.25f, 0, 0);

    spriteBatch.End();&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;Note the use of SamplerState.PointClamp, which turns off the antialiasing SpriteBatch would normally apply by default.&lt;/p&gt;

&lt;p&gt;Resulting image:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;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="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/5432.image_5F00_3C10ADB9.png" width="163" height="49" /&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Zoomed 4x:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/2388.image_5F00_401AFB8B.png" width="652" height="196" /&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This has almost too many aliasing problems to mention! Some that I find particularly bothersome are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The black diagonal lines have pieces missing in the full size rotated image&lt;/li&gt;

  &lt;li&gt;The half size non rotated image has lots of problems:&lt;/li&gt;

  &lt;ul&gt;
    &lt;li&gt;The green vertical line, and also the red and blue horizontal lines, are entirely missing&lt;/li&gt;

    &lt;li&gt;It ended up with just two rather than three sets of black diagonal lines&lt;/li&gt;

    &lt;li&gt;The black border remains on the bottom and right, but is missing on the top and left&lt;/li&gt;
  &lt;/ul&gt;

  &lt;li&gt;The two quarter size images are entirely different:&lt;/li&gt;

  &lt;ul&gt;
    &lt;li&gt;Non rotated version has only a blue line, no red or green at all&lt;/li&gt;

    &lt;li&gt;Rotated version has scattered red and green pixels, but no blue&lt;/li&gt;

    &lt;li&gt;Imagine how horrible it would look if we animated this sprite spinning, as it would flicker back and forth between different colors!&lt;/li&gt;
  &lt;/ul&gt;
&lt;/ul&gt;

&lt;p&gt;Remember how &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/27/multisampling.aspx" target="_blank"&gt;multisampling&lt;/a&gt; smooths triangle edges but does not affect their interior? We can confirm this by turning on 4x multisampling, and noting how the only difference is smoother borders on the rotated images:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/6521.image_5F00_34F17141.png" width="652" height="196" /&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With 4x &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/26/supersampling.aspx" target="_blank"&gt;supersampling&lt;/a&gt;, on the other hand, texture aliasing is indeed reduced:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/1715.image_5F00_7FE4E210.png" width="652" height="196" /&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But this is still far from perfect. The full size rotated and half size non rotated images look pretty nice, but the half size rotated and both quarter size versions have flaws. We'd still get nasty color pulsation if we animated a rotation of that quarter size version. This is because 4x supersampling only gives a 2x improvement in sampling frequency along each of the horizontal and vertical axes. That can reduce aliasing, but is not enough to keep us above the Nyquist threshold if we transform the texture by a factor of more than 2x.&lt;/p&gt;

&lt;p&gt;Whatever is a poor graphics programmer to do?&lt;/p&gt;

&lt;p&gt;To start with, we shouldn't have made life difficult for ourselves by specifying point sampling! If we turn off supersampling and multisampling, then change our SpriteBatch.Begin call to use the default SamplerState.LinearClamp, &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2009/09/08/texture-filtering.aspx" target="_blank"&gt;bilinear filtering&lt;/a&gt; produces a much nicer image than the point sampled version we started out with:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/8662.image_5F00_0DB7280C.png" width="652" height="196" /&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unlike multisampling and supersampling, texture filtering does not smooth the border of the rotated images, but it does a nice job to reduce aliasing inside our full size rotated and half size non rotated images. Bilinear filtering lets us down in the same places as supersampling. Because the GPU only takes four filter taps per texture fetch (two horizontal and two vertical), we get 2x more headroom before we will run into aliasing problems, but a 2x improvement cannot entirely eliminate the Nyquist threshold, so our quarter size images remain nasty.&lt;/p&gt;

&lt;p&gt;The solution is to combine bilinear filtering with precalculated &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2009/09/14/texture-filtering-mipmaps.aspx" target="_blank"&gt;mipmaps&lt;/a&gt; (plus &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2009/09/24/texture-filtering-anisotropy.aspx" target="_blank"&gt;anisotropic filtering&lt;/a&gt; if you can afford it). No matter how small the texture is scaled, the GPU can now simply select the appropriate mip level to sample from, always remaining just below the Nyquist threshold regardless of what transforms are applied.&lt;/p&gt;

&lt;p&gt;With mipmaps enabled, even our smallest images now keep the same color intensity and hue, with no stray pixels or random changes of shape, so we can animate our sprite rotating or scaling with no aliasing problems at all:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-70-20-metablogapi/6518.image_5F00_1B896E07.png" width="652" height="196" /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10159661" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Multisampling</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/27/multisampling.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/04/27/multisampling.aspx</id><published>2011-04-27T22:51:00Z</published><updated>2011-04-27T22:51:00Z</updated><content type="html">&lt;p&gt;Multisampling is a compromise for people who really want to use &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/26/supersampling.aspx" target="_blank"&gt;supersampling&lt;/a&gt;, but can't afford it.&lt;/p&gt;
&lt;p&gt;The idea is simple: instead of increasing the resolution for all rendering, what if we do triangle rasterization and depth/stencil tests at the higher resolution, but leave pixel shading and texture lookups at the original, lower resolution?&lt;/p&gt;
&lt;p&gt;Where standard rendering goes like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For each final output pixel covered by a triangle:
&lt;ul&gt;
&lt;li&gt;Run the pixel shader&lt;/li&gt;
&lt;li&gt;Perform the depth test&lt;/li&gt;
&lt;li&gt;Write the pixel color&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And supersampling is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For each high resolution supersampled pixel covered by a triangle:
&lt;ul&gt;
&lt;li&gt;Run the pixel shader&lt;/li&gt;
&lt;li&gt;Perform the depth test&lt;/li&gt;
&lt;li&gt;Write the pixel color&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;After all geometry is drawn, downsample the high resolution image to the final size&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The process for multisampling is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For each final output pixel covered by a triangle:
&lt;ul&gt;
&lt;li&gt;Run the pixel shader&lt;/li&gt;
&lt;li&gt;For each high resolution multisampled pixel covered by the intersection of the triangle and the current output pixel:
&lt;ul&gt;
&lt;li&gt;Perform the depth test&lt;/li&gt;
&lt;li&gt;Write the pixel color&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;After all geometry is drawn, downsample the high resolution image to the final size&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Unlike supersampling, which can be implemented by drawing to a standard rendertarget and using a pixel shader to apply the final downsize filter, multisampling requires dedicated hardware support. In XNA, it is enabled by adding this to your Game constructor:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;    graphics.PreferMultiSampling = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;/pre&gt;
&lt;p&gt;Because triangle rasterization and depth testing are performed at the higher resolution, multisampling is every bit as good as supersampling at combating triangle edge and geometry aliasing. But because the pixel shader only runs once per final output pixel, it does not help at all with texture map or shader aliasing.&lt;/p&gt;
&lt;p&gt;This is an important and easily missed point:&amp;nbsp; &lt;i&gt;multisampling only knows about the edges of polygonal geometry.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;Multisampling can smooth the edges of triangles, and also the edges formed where one zbuffered triangle intersects another, but it knows nothing about what happens within the interior of each triangle. Texturing, shading, and lighting produce exactly the same results as if multisampling was not used at all (think about it: the pixel shader runs just once, then we write out 2 or 4 copies of the same color, after which the downsample filter averages these identical colors, producing the exact same value we started with). If your triangles have interior borders caused by texture lookups or shader code (for instance the border of an alpha cutout sprite), multisampling will be irrelevant. This often surprises people when they see aliasing on cutout sprites and turn on multisampling in an attempt to fix it, but nothing changes. Yet this is the nature of the beast. If you want to antialias alpha cutout borders within a triangle, you need supersampling, or one of the texture/shader based techniques I will talk about later.&lt;/p&gt;
&lt;p&gt;So why is multisampling popular?&amp;nbsp; (&lt;i&gt;and it is very popular, to the extent where many people confuse the generic term "antialiasing" with the specific technique "multisampling"&lt;/i&gt;)&lt;/p&gt;
&lt;p&gt;Simple: it's cheap. On some hardware (notably Xbox 360) it can be very cheap indeed.&lt;/p&gt;
&lt;p&gt;Remember that the GPU is an &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2008/04/11/santa-s-production-line.aspx" target="_blank"&gt;asynchronous parallel processing pipeline&lt;/a&gt;. Multisampling increases the cost of some stages along this pipeline (notably rasterization, depth/stencil testing, and framebuffer writes), but it does not affect the areas that are most often performance bottlenecks (vertex fetch, vertex shading, texture fetch, and pixel shading). Adding work to things that were not the perf bottleneck can sometimes even be entirely free, so multisampling often turns out to improve visual quality for low cost.&lt;/p&gt;
&lt;p&gt;Even if you are bottlenecked by framebuffer bandwidth, hardware designers are clever and can pull all sorts of neat silicon tricks to make multisampling efficient, taking advantage of the coherency where the same color value is usually written many times in a row. Why waste memory bandwidth saying "write X, ok, write X again, and again, and one more 'gain", when you could send just a single copy of X over the bus, followed by a couple of bit flags indicating which multisamples this pixel shader result should cover?&lt;/p&gt;
&lt;p&gt;Oh yeah, before I go I should show you how it looks. Here's our favorite tank model, first with no antialiasing, then using 4x multisampling:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;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="image" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-70-20-metablogapi/5001.image_5F00_1EBD84D2.png" border="0" width="128" height="128" /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;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="image" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-70-20-metablogapi/2352.image_5F00_6AA8E57E.png" border="0" width="128" height="128" /&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And the same images zoomed in:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;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="image" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-70-20-metablogapi/5008.image_5F00_4E982693.png" border="0" width="384" height="384" /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;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="image" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-70-20-metablogapi/6177.image_5F00_75663CD3.png" border="0" width="384" height="384" /&gt;&lt;/p&gt;
&lt;/blockquote&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10158860" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Supersampling</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/26/supersampling.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/04/26/supersampling.aspx</id><published>2011-04-27T00:14:25Z</published><updated>2011-04-27T00:14:25Z</updated><content type="html">&lt;p&gt;Supersampling is the simple, brute force approach to antialiasing computer graphics.&lt;/p&gt;  &lt;p&gt;In order to &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/20/how-to-resample-a-signal-without-aliasing.aspx" target="_blank"&gt;avoid aliasing&lt;/a&gt;, the Nyquist theorem says we must take at least twice as many samples as the highest frequency detail in our input signal. So how about we just render our scene at a really, really high output resolution?&lt;/p&gt;  &lt;p&gt;Of course, we may not want our final image to be at such a silly high resolution. It is no good if we end up with more pixels than our screen is capable of displaying! So once we have our beautiful, high resolution, alias-free image, we shrink it down to the final output size, using a high quality filter to maximize image quality.&lt;/p&gt;  &lt;p&gt;Here is an example model, first rendered at 64x64 with no antialiasing, and then rendered at 256x256 (16x supersampling) before shrinking down to 64x64 using the &amp;quot;Best Quality&amp;quot; image resize filter in Paint.NET (if you were doing this on the fly in a game, you could use a pixel shader to apply a similar high quality scaling filter):&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-70-20-metablogapi/0458.image_5F00_0FA78C48.png" width="64" height="64" /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-70-20-metablogapi/5756.image_5F00_3A13BD65.png" width="64" height="64" /&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;And the same images zoomed to show more detail:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-70-20-metablogapi/6327.image_5F00_47E60360.png" width="256" height="256" /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-70-20-metablogapi/4274.image_5F00_27CAF6A3.png" width="256" height="256" /&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Because it increases the resolution for all rendering operations, supersampling addresses many different kinds of aliasing in one fell swoop:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Triangle edge aliasing&lt;/li&gt;    &lt;li&gt;Geometry aliasing&lt;/li&gt;    &lt;li&gt;Texture map aliasing&lt;/li&gt;    &lt;li&gt;Shader aliasing&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;In fact the only common aliasing problem that supersampling does not help with is temporal (time based) aliasing.&lt;/p&gt;  &lt;p&gt;The problem is cost. Even if you only double the horizontal and vertical resolution (giving 4x supersampling), you now have four times as many pixels to render. Four times as many texture fetches and pixel shader computations, not to mention four times the amount of framebuffer and depth buffer memory, leaves your GPU performing at roughly quarter speed. And that's just for 4x supersampling, which is nowhere near enough to get rid of all geometry, texture, and shader aliasing.&lt;/p&gt;  &lt;p&gt;Remember that pesky Nyquist theorem? To avoid aliasing, it is important to consider the ratio between the maximum and minimum scale at which a &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/20/why-sampling-a-signal-causes-aliasing.aspx" target="_blank"&gt;signal can be sampled&lt;/a&gt;:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Consider a texture map, such as the side of a building&lt;/li&gt;    &lt;li&gt;How close is the player likely to get to the building?&lt;/li&gt;    &lt;li&gt;To keep the graphics looking crisp, we want our texture to be high enough resolution to remain detailed when sampled at this maximum scale&lt;/li&gt;    &lt;li&gt;Now the player starts to back away from the building&lt;/li&gt;    &lt;li&gt;The texture shrinks in size, ie. is sampled at a lower frequency&lt;/li&gt;    &lt;li&gt;After a while, it will be sampled at too low a rate, below the Nyquist threshold, so aliasing will occur&lt;/li&gt;    &lt;li&gt;Supersampling to the rescue!&lt;/li&gt;    &lt;li&gt;We turn on 2x supersampling, so the aliasing goes away&lt;/li&gt;    &lt;li&gt;But the player continues to back away from the building&lt;/li&gt;    &lt;li&gt;When the texture reaches half the scale at which we previously saw aliasing, the problem returns&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;It is common for objects to change size by a factor of 100 or more as you move around the world. But it would be wildly impractical to increase our rendering resolution by 100x in both width and height, as this would increase the GPU pixel workload by a factor of 10,000!&lt;/p&gt;  &lt;p&gt;For this reason, supersampling is not widely used, and hence this series of articles is not over. But it is an important starting point for understanding other more advanced antialiasing techniques.&lt;/p&gt;  &lt;p&gt;One place you probably have used supersampling is if you ever connected an Xbox 360 to a standard definition TV. Most Xbox games will continue to render at an HD resolution such as 1280x720, relying on the hardware scaler to shrink the resulting images to the output video resolution. That's supersampling, right there! Thanks to the high quality scaling hardware, those extra high resolution pixels are not wasted, but instead used to create a nicely antialiased 640x480 image.&lt;/p&gt;  &lt;p&gt;Another place some games use supersampling is when taking screenshots for marketing materials. Internal builds of &lt;a href="http://www.talula.demon.co.uk/blogindex.html#motogp" target="_blank"&gt;MotoGP&lt;/a&gt; included a special mode that would render the same scene many times using different projection matrices, combining literally hundreds of 640x480 tiles to build up a massive 16384*16384 screenshot image, which we would then downsample to a more sane resolution in Photoshop. Cheating? Kinda. But it was the normal in-game rendering engine and shaders, using the regular in-game models and textures, running on the actual Xbox hardware. Yet the resulting images were so nicely antialiased, they looked great when printed on a giant poster.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10158421" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>How to resample a signal without aliasing</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/20/how-to-resample-a-signal-without-aliasing.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/04/20/how-to-resample-a-signal-without-aliasing.aspx</id><published>2011-04-21T01:19:00Z</published><updated>2011-04-21T01:19:00Z</updated><content type="html">&lt;p&gt;My &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/20/why-sampling-a-signal-causes-aliasing.aspx" target="_blank"&gt;previous post&lt;/a&gt; described how resampling a signal can cause aliasing problems. The worst problems occur when dramatically reducing the number of samples used to represent a signal, or when the source includes lots of high frequency detail. Specifically, there is a magic value called the &lt;a href="http://en.wikipedia.org/wiki/Nyquist_frequency" target="_blank"&gt;Nyquist frequency&lt;/a&gt;, which is half the rate at which are you taking output samples. If the source signal contains information with a higher frequency than this threshold, you will have aliasing problems.&lt;/p&gt;
&lt;p&gt;To put this another way: in order to avoid aliasing, you must take at least twice as many output samples as the finest detail in your input signal.&lt;/p&gt;
&lt;p&gt;That leaves us with basically just two ways to avoid aliasing:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Take more output samples&lt;/li&gt;
&lt;li&gt;Or have less fine detail in the input signal&lt;ol&gt;
&lt;li&gt;Smooth (aka. blur) the input data to remove fine detail&lt;/li&gt;
&lt;li&gt;Or smooth (aka. filter) on the fly as we read our sample values&lt;/li&gt;
&lt;/ol&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Option 2.1 can often be applied to the input data as a preprocess, which makes it very efficient. But this is no good if we need to sample the data at different frequencies depending on the situation! (for instance textures often need to be scaled by different amounts depending on distance from the camera). If we pre-smooth our input data according to the lowest frequency we will ever sample it at, the result will be excessively blurry when sampled at higher frequencies. Or if we pre-smooth to match a higher frequency, we will still have aliasing when sampling at the lower rate.&lt;/p&gt;
&lt;p&gt;Option 2.2 can dynamically adjust to different sampling frequencies, but tends to be expensive to implement, as it must average many different samples from slightly different locations in the input.&lt;/p&gt;
&lt;p&gt;A third option is to declare this whole digital sampling business a mug's game and refuse to play at all. In some situations it is possible to work entirely with mathematical equations, transforming one signal into another by applying mathematical transformations to the equations which describe them. This approach inherently avoids digital approximation, so will not produce any aliasing, but the math tends to get very complex. It is not widely used in realtime computer graphics, but many offline renderers (eg. RenderMan) work this way.&lt;/p&gt;
&lt;p&gt;Ok, that's enough theory. Next, let's get practical...&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10156489" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Why sampling a signal causes aliasing</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/20/why-sampling-a-signal-causes-aliasing.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/04/20/why-sampling-a-signal-causes-aliasing.aspx</id><published>2011-04-21T00:56:48Z</published><updated>2011-04-21T00:56:48Z</updated><content type="html">&lt;p&gt;The math behind digital sampling and filtering is fascinating, complex, and full of arcane terms like &lt;a href="http://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem" target="_blank"&gt;Nyquist frequency&lt;/a&gt;. But I'm barely a good enough mathematician to understand it, let alone try to explain it here! This post is my attempt to describe &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/20/antialiasing.aspx" target="_blank"&gt;aliasing &lt;/a&gt;as it applies to computer graphics via overgeneralized hand waving.&lt;/p&gt;  &lt;p&gt;Most of the important operations involved in rendering graphics can be boiled down to digitally sampling a signal. If this phrase is new to you, don't panic!&amp;#160; A signal just means a value that changes as you move around some coordinate space (which can be 1D, 2D, or occasionally 3D or more). Common types of signal used in graphics are:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;A texture image, the color of which changes as you move to different 2D locations within that image&lt;/li&gt;    &lt;li&gt;A shader lighting function, the brightness of which changes as you alter the angle of the light&lt;/li&gt;    &lt;li&gt;The edge of a triangle, the position of which changes as you move along the edge&lt;/li&gt;    &lt;li&gt;The position of a moving object, which changes as you move through time&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Signals can sometimes be described by a mathematical equation, but they are more commonly represented as a series of digital samples, ie. an array which stores the value of the signal for many different coordinate locations.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;&amp;lt;digression&amp;gt;&lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;People often claim that the real world uses continuously varying analog signals, but when you get down to the quantum level it is actually all digital samples! Subatomic particles are entirely discrete. Photons are either there or not there, so the brightness of a light can never involve a fractional number of photons. Things only appear continuous because these particles are so small. Reality is pixelated, just at a ridiculously high resolution :-)&lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;&amp;lt;/digression&amp;gt;&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Sampling occurs whenever we wish to transform one signal into another, for instance:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;To rasterize a triangle, we turn the mathematical description of its edge into an array of framebuffer pixels&lt;/li&gt;    &lt;li&gt;To map a texture onto this triangle, we turn the array of samples which makes up our texture map into a different array of framebuffer pixel colors&lt;/li&gt;    &lt;li&gt;To light that triangle, we turn a mathematical lighting equation into a different brightness value for each pixel that the triangle covers&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Although the implementation tends to be heavily optimized, all forms of sampling work basically the same way:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The output signal is defined as an array of digital sample values&lt;/li&gt;    &lt;li&gt;For each element in the output array, find the corresponding location in the coordinate space of the input signal&lt;/li&gt;    &lt;li&gt;If the input signal is a mathematical equation, evaluate it at that location&lt;/li&gt;    &lt;li&gt;Or if the input is a series of digital samples, look up the stored value at that location&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Easy, right? But this basic operation is where pretty much every kind of aliasing comes from.&lt;/p&gt;  &lt;p&gt;Example time. Consider this 1D signal, stored as an array of 512 digital values:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-70-20-metablogapi/7635.image_5F00_1CAB6943.png" width="504" height="215" /&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Let's convert this signal to an array of just 64 values, by taking evenly spaced samples every 8 entries through the original. Note that there is no requirement for our samples to be evenly spaced. That makes it easy to visualize, but if we were for instance mapping a texture onto the side of an object rendered with a 3D perspective view, the relationship between input and output samples could be a more complex curve function.&lt;/p&gt;  &lt;p&gt;This resampling produces a new signal with the same basic shape as the original, but less detail:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;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="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-70-20-metablogapi/7658.image_5F00_2CD7313C.png" width="504" height="215" /&gt;&lt;/p&gt; &lt;/blockquote&gt;    &lt;p&gt;It looks ugly and blocky, but that is actually a made-up problem caused by the fact that after shrinking my 512 sample signal to just 64 samples, I scaled back up to 512 before displaying the above image. If I displayed the downsampled signal at its native 64 pixel width, there would be no such blockiness.&lt;/p&gt;  &lt;p&gt;If I did for some reason need to shrink the signal to 64 samples and then scale back up to 512, I could do that scaling by interpolating between values rather than just repeating them. This is called linear filtering (the previous example used point sampling) and it produces an image that looks pleasingly similar to our original, albeit with less fine detail:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-70-20-metablogapi/0876.image_5F00_25B7F4C4.png" width="504" height="215" /&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Here's where it gets interesting. Look what happens if we reduce the output signal to just 16 samples:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;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="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-70-20-metablogapi/3513.image_5F00_338A3ABF.png" width="240" height="102" /&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Then 8:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;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="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-70-20-metablogapi/1460.image_5F00_2C6AFE47.png" width="240" height="102" /&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;7:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;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="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-70-20-metablogapi/5078.image_5F00_3A3D4442.png" width="240" height="102" /&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;And finally 6:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;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="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-70-20-metablogapi/3835.image_5F00_0530B512.png" width="240" height="102" /&gt;&lt;/p&gt; &lt;/blockquote&gt;          &lt;p&gt;Whoah!&amp;#160; How come 8 samples has a dip followed by peak toward the right of the signal, but the 7 sample version is almost flat, while the 6 sample version has a peak followed by dip, almost the exact opposite of the 8 sample version?&lt;/p&gt;  &lt;p&gt;The problem is that when we are taking so few samples, there just aren't enough values to accurately represent the shape of the original signal. It ends up being basically random where in the signal these samples happen to be taken, so our output signal can change dramatically when we make even small adjustments to how we are sampling it. When reducing a signal to dramatically fewer samples than were present in the original, the result tends to be meaningless noise.&lt;/p&gt;  &lt;p&gt;Aliasing can be a problem even when you are not dramatically reducing the number of samples. Consider our original 512 sample signal, which includes a lot of small, high frequency jitter. Then consider the 64 sample version, which has the same basic shape but without that fine detail. This looks fine as a still image, but what if were to animate it, perhaps sliding the curve gradually sideways? Now each frame of the animation will be sampling from slightly different locations in the original signal. One frame our sample location may randomly happen to be at the top of one of those little jitters, then the next frame it could be at the bottom. The result is that our output signal randomly jitters up and down, in addition to sliding sideways!&lt;/p&gt;  &lt;p&gt;This is a common characteristic of aliasing problems. In extreme cases they can make even static images look bad, but more often, subtle aliasing may look fine when stationary yet will flicker or shimmer whenever the object or camera moves.&lt;/p&gt;  &lt;p&gt;Fun way to see an extreme example of this in action:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Download &lt;a href="http://commons.wikimedia.org/wiki/File:Moire_pattern_of_bricks.jpg" target="_blank"&gt;this image&lt;/a&gt; and load it into Paint.NET&lt;/li&gt;    &lt;li&gt;Select Image / Resize&lt;/li&gt;    &lt;li&gt;Choose Nearest Neighbor resampling mode&lt;/li&gt;    &lt;li&gt;Scale to 80%&lt;/li&gt;    &lt;li&gt;See that crazy ripple pattern?&lt;/li&gt;    &lt;li&gt;Undo&lt;/li&gt;    &lt;li&gt;Now resize to 75%&lt;/li&gt;    &lt;li&gt;Another, totally different ripple pattern!&lt;/li&gt;    &lt;li&gt;Imagine how horrible this would look if we were rendering an animation of this texture shrinking in size as it receded into the distance...&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;em&gt;Up next: ways to avoid aliasing when resampling a signal.&lt;/em&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10156484" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Antialiasing</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/shawnhar/archive/2011/04/20/antialiasing.aspx" /><id>http://blogs.msdn.com/b/shawnhar/archive/2011/04/20/antialiasing.aspx</id><published>2011-04-20T20:04:09Z</published><updated>2011-04-20T20:04:09Z</updated><content type="html">&lt;p&gt;I've been meaning to write about antialiasing for a while, but now I sit down to do that I realize I have too much to say for a single article. So this post is the introduction to a series.&lt;/p&gt;  &lt;p&gt;Antialiasing is one of the most important yet least widely understood areas of computer graphics. If I had a penny for every time I heard the developer of a 2D game say &amp;quot;&lt;em&gt;I turned on antialiasing but my sprites still look jaggy&lt;/em&gt;&amp;quot;, well, I'd be up to six or even seven pennies by now!&lt;/p&gt;  &lt;p&gt;The thing is, &amp;quot;antialiasing&amp;quot; is really too vague a term to mean anything at all! The important word is &amp;quot;aliasing&amp;quot;, which is surprisingly hard to pin down. &lt;a href="http://dictionary.reference.com/browse/aliasing" target="_blank"&gt;Dictionary.com&lt;/a&gt; gives two definitions:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;em&gt;Jagged distortions in curves and diagonal lines in computer graphics caused by limited or diminished screen resolution. &lt;/em&gt;&lt;/li&gt;    &lt;li&gt;&lt;em&gt;Distortion in a reproduced sound wave caused by a low sampling rate during the recording of the sound signal as digital information. &lt;/em&gt;&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;These are both examples of aliasing, but really just special cases of a more generic underlying meaning:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;Artifacts created when a source value (which can be either analog or digital) is replaced by a digital approximation.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;We perform such approximations in many places when rendering computer graphics:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;We approximate the shape of arbitrary objects as a list of triangles&lt;/li&gt;    &lt;li&gt;We approximate the shape of a triangle as a grid of dots (screen pixels)&lt;/li&gt;    &lt;li&gt;We approximate arbitrary images as grids of dots (textures)&lt;/li&gt;    &lt;li&gt;We frequently approximate one grid of dots as another different grid of dots (scaling images, rotating, or mapping them onto 3D geometry)&lt;/li&gt;    &lt;li&gt;Our shader programs use many digital approximations, as varied as the things for which we use shaders (ie. basically infinite)&lt;/li&gt;    &lt;li&gt;We approximate moving objects as a series of static images (animation)&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Any or all of these approximations can cause ugly aliasing artifacts. Antialiasing really just means &amp;quot;&lt;em&gt;a technique used to avoid or cover up an aliasing problem&lt;/em&gt;&amp;quot;. Since there are many different kinds of aliasing, and many techniques to overcome each of them, it should be no surprise that there are many, many different forms of antialiasing. And of course, they only work if you choose an antialiasing technique that matches the specific kind of aliasing you were suffering from in the first place!&lt;/p&gt;  &lt;p&gt;Ok, that was kinda dry. Next up, more theory. Then after that, some practical examples.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10156388" width="1" height="1"&gt;</content><author><name>Shawn Hargreaves - MSFT</name><uri>http://blogs.msdn.com/ShawnHargreaves/ProfileUrlRedirect.ashx</uri></author></entry></feed>
