I am trying to create a bilinear interpolation filter using HLSL and the GatherRed / GatherGreen / GatherBlue functions but I am getting really poor results compared to a proper hardware bilinear filter as you can see in the image attached to this post.
Here is the pixel shader code I am using:
Texture2D g_texture : register(t0);
struct pixel_in
{
float2 tex_coord : TEXCOORD;
};
float3 bilinear(float2 texcoord, float tex_dimension)
{
float3 result;
// red channel
float4 reds = g_texture.GatherRed(g_sampler, texcoord);
float r1 = reds.x;
float r2 = reds.y;
float r3 = reds.z;
float r4 = reds.w;
float2 fract = frac(texcoord.xy * tex_dimension);
float top_row_red = lerp(r1, r2, fract.x);
float bottom_row_red = lerp(r3, r4, fract.x);
float final_red = lerp(bottom_row_red, top_row_red, fract.y);
result.x = final_red;
// green channel
float4 greens = g_texture.GatherGreen(g_sampler, texcoord);
float g1 = greens.x;
float g2 = greens.y;
float g3 = greens.z;
float g4 = greens.w;
float top_row_green = lerp(g1, g2, fract.x);
float bottom_row_green = lerp(g3, g4, fract.x);
float final_green = lerp(bottom_row_green, top_row_green, fract.y);
result.y = final_green;
// blue channel
float4 blues = g_texture.GatherBlue(g_sampler, texcoord);
float b1 = blues.x;
float b2 = blues.y;
float b3 = blues.z;
float b4 = blues.w;
float top_row_blue = lerp(b1, b2, fract.x);
float bottom_row_blue = lerp(b3, b4, fract.x);
float final_blue = lerp(bottom_row_blue, top_row_blue, fract.y);
result.z = final_blue;
return result;
}
float4 PS(pixel_input pin) : SV_Target
{
uint width_texels;
uint height_texels;
g_texture.GetDimensions(width_texels, height_texels);
float4 result = float4(0.0f, 0.0f, 0.0f, 1.0f);
result.xyz = bilinear(pin.tex_coord, width_texels);
return result;
}
I'm really not sure what I'm doing wrong here, there doesn't seem to be much linear interpolation hapening in my version but I'm not sure why.