title: XNA + HLSL Gaussian blur produces offset artefacts
body: <p>So I've built a downsampling algorithm in XNA (3.1. Yes, I'm aware it's horribly outdated. Yes, I have reasons for using it) and HLSL. Essentially how it works is by applying a Gaussian blur to the original texture, and then resizing it with the default nearest neighbour rescaling, built into XNA. My thinking was that a Gaussian blur would give an approximation to the average of a region of colours, so it would be essentially a cheap way to reduce aliasing. It works well, and very quickly, but produces some interesting artefacts - it seems to very slightly stretch the image. This is not noticeable usually, but some of the things I'm downsampling are sprite sheets, and when animated, it is very clear that the sprites have not been put into the correct position. I'm wondering if a different resampler (also built into HLSL for the speed of the GPU) might be a better option, or if there's an error with this one I can fix. I'll post my code up here, and see if there's anyone who could enlighten me.</p>
  
  <p>First is my HLSL Gaussian effects file:</p>
  
  <pre><code>#define RADIUS  7
  #define KERNEL_SIZE (RADIUS * 2 + 1)
  
  float weightX[KERNEL_SIZE];
  float weightY[KERNEL_SIZE];
  float2 offsetH[KERNEL_SIZE];
  float2 offsetV[KERNEL_SIZE];
  
  texture colorMapTexture;
  
  sampler TextureSampler : register(s0);
  
  void BlurH(inout float4 color : COLOR0, float2 texCoord : TEXCOORD0)
  {
      float4 c = float4(0.0f, 0.0f, 0.0f, 0.0f);
  
      for (int i = 0; i &lt; KERNEL_SIZE; ++i)
          c += tex2D(TextureSampler, texCoord + offsetH[i]) * weightX[i];
  
          color = c;
  }
  
  void BlurV(inout float4 color : COLOR0, float2 texCoord : TEXCOORD0)
  {
      float4 c = float4(0.0f, 0.0f, 0.0f, 0.0f);
  
      for (int i = 0; i &lt; KERNEL_SIZE; ++i)
          c += tex2D(TextureSampler, texCoord + offsetV[i]) * weightY[i];
  
          color = c;
  }
  
  technique GaussianBlur
  {
      pass
      {
          PixelShader = compile ps_2_0 BlurH();
      }
      pass
      {
          PixelShader = compile ps_2_0 BlurV();
      }
  }
  </code></pre>
  
  <p>And my code for initialising the Gaussian effect (note that gaussianBound is set to 8, i.e. 1+ the radius found in the HLSL file):</p>
  
  <pre><code> public static Effect GaussianBlur(float amount, float radx, float rady, Point scale)
          {
              Effect rtrn = gaussianblur.Clone(MainGame.graphicsManager.GraphicsDevice);
  
              if (radx &gt;= gaussianBound)
              {
                  radx = gaussianBound - 0.000001F;
              }
              if (rady &gt;= gaussianBound)
              {
                  rady = gaussianBound - 0.000001F;
              }
              //If blur is too great, image becomes transparent,
              //so cap how much blur can be used.
              //Reduces quality of very small images.
  
              Vector2[] offsetsHoriz, offsetsVert;
              float[] kernelx = new float[(int)(radx * 2 + 1)];
              float sigmax = radx / amount;
              float[] kernely = new float[(int)(rady * 2 + 1)];
              float sigmay = rady / amount;
              //Initialise kernels and sigmas (separately to allow for different scale factors in x and y)
  
              float twoSigmaSquarex = 2.0f * sigmax * sigmax;
              float sigmaRootx = (float)Math.Sqrt(twoSigmaSquarex * Math.PI);
              float twoSigmaSquarey = 2.0f * sigmay * sigmay;
              float sigmaRooty = (float)Math.Sqrt(twoSigmaSquarey * Math.PI);
              float totalx = 0.0f;
              float totaly = 0.0f;
              float distance = 0.0f;
              int index = 0;
              //Initialise gaussian constants, as well as totals for normalisation.
  
              offsetsHoriz = new Vector2[kernelx.Length];
              offsetsVert = new Vector2[kernely.Length];
  
              float xOffset = 1.0f / scale.X;
              float yOffset = 1.0f / scale.Y;
              //Set offsets for use in the HLSL shader.
  
              for (int i = -(int)radx; i &lt;= radx; ++i)
              {
                  distance = i * i;
                  index = i + (int)radx;
                  kernelx[index] = (float)Math.Exp(-distance / twoSigmaSquarex) / sigmaRootx;
                  //Set x kernel values with gaussian function.
                  totalx += kernelx[index];
                  offsetsHoriz[index] = new Vector2(i * xOffset, 0.0f);
                  //Set x offsets.
              }
  
              for (int i = -(int)rady; i &lt;= rady; ++i)
              {
                  distance = i * i;
                  index = i + (int)rady;
                  kernely[index] = (float)Math.Exp(-distance / twoSigmaSquarey) / sigmaRooty;
                  //Set y kernel values with gaussian function.
                  totaly += kernely[index];
                  offsetsVert[index] = new Vector2(0.0f, i * yOffset);
                  //Set y offsets.
              }
  
              for (int i = 0; i &lt; kernelx.Length; ++i)
                  kernelx[i] /= totalx;
  
              for (int i = 0; i &lt; kernely.Length; ++i)
                  kernely[i] /= totaly;
  
              //Normalise kernel values.
  
              rtrn.Parameters["weightX"].SetValue(kernelx);
              rtrn.Parameters["weightY"].SetValue(kernely);
              rtrn.Parameters["offsetH"].SetValue(offsetsHoriz);
              rtrn.Parameters["offsetV"].SetValue(offsetsVert);
              //Set HLSL values.
  
              return rtrn;
          }
  </code></pre>
  
  <p>Beyond this, my function simply draws to a texture each pass of the effect, then draws the result to a new texture at a different scale. This looks really nice, but as I said produces these artefacts of things not quite being in the right place. Some help here would be appreciated.</p>
  
  <p><img src="https://i.stack.imgur.com/KNlNX.png" alt="Artefacts showing"></p>