#define MAX_RADIUS 128u uniform float4x4 ViewProj; uniform texture2d image; uniform float2 texel_step; uniform float radius; uniform float focus_center; uniform float focus_width; // Half the focus zone thickness uniform float focus_angle; uniform float2 uv_size; sampler_state textureSampler{ Filter = Linear; AddressU = Clamp; AddressV = Clamp; MinLOD = 0; MaxLOD = 0; }; struct VertData { float4 pos : POSITION; float2 uv : TEXCOORD0; }; VertData mainTransform(VertData v_in) { v_in.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); return v_in; } float4 mainImage(VertData v_in) : TARGET { // Rotate about angle: // a matrix multiplication is more readable, but does not work on OpenGL // for some reason. //float2x2 rot = float2x2(cos(focus_angle), sin(focus_angle), -sin(focus_angle), cos(focus_angle)); //float2 uv_prime = mul(rot, v_in.uv*uv_size - 0.5*uv_size) / uv_size.y + 0.5f - focus_center; float2 coord_norm = v_in.uv*uv_size - 0.5*uv_size; float2 uv_prime = float2( coord_norm.x * cos(focus_angle) + coord_norm.y * sin(focus_angle), -coord_norm.x * sin(focus_angle) + coord_norm.y * cos(focus_angle) )/uv_size.y + 0.5f - focus_center; float dist = abs(uv_prime.y); // DO THE BLUR // 1. Sample incoming pixel float4 col = image.Sample(textureSampler, v_in.uv); // if in the focused zone, return original pixel. if(dist < focus_width) { return col; } float scaled_radius = (dist-focus_width) * radius; // 2. March out from incoming pixel, add surrounding pixels to color for(uint i=1u; i<=MAX_RADIUS; i+=2u) { if(i+1u > scaled_radius) { break; } float offset = float(i) + 0.5f; col += 2.0f*image.Sample(textureSampler, v_in.uv + (offset * texel_step)); col += 2.0f*image.Sample(textureSampler, v_in.uv - (offset * texel_step)); } float fradius = floor(scaled_radius); float residual = scaled_radius-(fradius-float(int(fradius)%2)); if(residual > 0.0f) { float offset = (scaled_radius - residual/2.0f); col += image.Sample(textureSampler, v_in.uv + (offset * texel_step)) * residual; col += image.Sample(textureSampler, v_in.uv - (offset * texel_step)) * residual; } // 3. Normalize the color with the total number of samples col /= (2.0f * scaled_radius + 1.0f); return col; } technique Draw { pass { vertex_shader = mainTransform(v_in); pixel_shader = mainImage(v_in); } }