RasterGrid’s Gaussian Blur in HLSL#

Gaussian blurs sample many pixels. RasterGrid optimized Gaussian blur by sampling in-between pixels. RasterGrid’s article did not include shader code for varied Gaussian blur radii. This post solves that.

Source Code#

float GetGaussianWeight(float SampleIndex, float Sigma)
{
   const float Pi = 3.1415926535897932384626433832795f;
   float Output = rsqrt(2.0 * Pi * (Sigma * Sigma));
   return Output * exp(-(SampleIndex * SampleIndex) / (2.0 * Sigma * Sigma));
}

float GetGaussianOffset(float SampleIndex, float Sigma, out float LinearWeight)
{
   float Offset1 = SampleIndex;
   float Offset2 = SampleIndex + 1.0;
   float Weight1 = GetGaussianWeight(Offset1, Sigma);
   float Weight2 = GetGaussianWeight(Offset2, Sigma);
   LinearWeight = Weight1 + Weight2;
   return ((Offset1 * Weight1) + (Offset2 * Weight2)) / LinearWeight;
}

float4 GetGaussianBlur(float2 Tex, float LOD, float2 PixelSize, float Sigma)
{
   // Sample and weight center first to get even number sides
   float TotalWeight = GetGaussianWeight(0.0, Sigma);
   float4 OutputColor = tex2Dlod(SampleColorTex, float4(Tex, 0.0, LOD)) * TotalWeight;

   for(float i = 1.0; i < Sigma * 3.0; i += 2.0)
   {
      float LinearWeight = 0.0;
      float LinearOffset = GetGaussianOffset(i, Sigma, LinearWeight);
      OutputColor += tex2Dlod(SampleColorTex, float4(Tex - (LinearOffset * PixelSize), 0.0, LOD)) * LinearWeight;
      OutputColor += tex2Dlod(SampleColorTex, float4(Tex + (LinearOffset * PixelSize), 0.0, LOD)) * LinearWeight;
      TotalWeight += LinearWeight * 2.0;
   }

   // Normalize intensity to prevent altered output
   return OutputColor / TotalWeight;
}