#include SAMPLER2D(sOcclusion, 0); SAMPLER2D(sMrt1, 1); // normals + depth SAMPLER2D(sAccessibility, 0); SAMPLER2D(sMRT2, 1); // the view space position, xyz // a very simple 4x4 box filter // the kernel has the following form // o o o o // o o o o // o o x o // o o o o // where x marks the fragment position and the o marks a sampling point void boxFilter_fp ( in float4 position : POSITION, in float2 screenTC : TEXCOORD0, out float4 oColor0 : COLOR0, uniform float4 screenSize, uniform float farClipDistance ) { float color = 0; for (int x = -2; x < 2; x++) for (int y = -2; y < 2; y++) { color += tex2D(sOcclusion, float2(screenTC.x + x * screenSize.z, screenTC.y + y * screenSize.w)).x; } color /= 16; oColor0 = float4(color.xxx, 1); } // a very simple and slightly dumb depth aware 4x4 box filter // the kernel has the following form // o o o o // o o o o // o o x o // o o o o // where x marks the fragment position and the o marks a sampling point void smartBoxFilter_fp ( in float4 position : POSITION, in float2 screenTC : TEXCOORD0, out float4 oColor0 : COLOR0, uniform float4 screenSize, uniform float farClipDistance ) { float fragmentDepth = tex2D(sMrt1, screenTC).x; float color = 0; float weight = 0; for (int x = -2; x < 2; x++) for (int y = -2; y < 2; y++) { float sampleDepth = tex2D(sMrt1, float2(screenTC.x + x * screenSize.z, screenTC.y + y * screenSize.w)).x; float dist = abs(fragmentDepth - sampleDepth) * farClipDistance + 0.5; float sampleWeight = 1 / (pow(dist, 1) + 1); color += sampleWeight * tex2D(sOcclusion, float2(screenTC.x + x * screenSize.z, screenTC.y + y * screenSize.w)).x; weight += sampleWeight; } color /= weight; oColor0 = float4(color.xxx, 1); // oColor0 = float4(tex2D(sOcclusion, screenTC).www, 1); } // cross bilateral filter // gaussian blur with photometric weighting // note: encode the viewspace z component in the accessibility texture to reduce // the texture fetch count void crossBilateralFilterX_fp ( in float4 position : POSITION, in float2 uv : TEXCOORD0, out float4 oColor0 : COLOR0, uniform float stepX, // inverse viewport width uniform float cPhotometricExponent ) { const int kernelWidth = 13; float sigma = (kernelWidth - 1) / 6; // make the kernel span 6 sigma float fragmentDepth = tex2D(sMRT2, uv).z; float weights = 0; float blurred = 0; for (float i = -(kernelWidth - 1) / 2; i < (kernelWidth - 1) / 2; i++) { float geometricWeight = exp(-pow(i, 2) / (2 * pow(sigma, 2))); float sampleDepth = tex2D(sMRT2, float2(uv.x - i * stepX, uv.y)).z; float photometricWeight = 1 / pow((1 + abs(fragmentDepth - sampleDepth)), cPhotometricExponent); weights += (geometricWeight * photometricWeight); blurred += tex2D(sAccessibility, float2(uv.x - i * stepX, uv.y)).r * geometricWeight * photometricWeight; } blurred /= weights; oColor0 = float4(blurred.xxx, 1); } void crossBilateralFilterY_fp ( in float4 position : POSITION, in float2 uv : TEXCOORD0, out float4 oColor0 : COLOR0, uniform float stepY, // inverse viewport width uniform float cPhotometricExponent ) { const int kernelWidth = 13; float sigma = (kernelWidth - 1) / 6; // make the kernel span 6 sigma float fragmentDepth = tex2D(sMRT2, uv).z; float weights = 0; float blurred = 0; for (float i = -(kernelWidth - 1) / 2; i < (kernelWidth - 1) / 2; i++) { float geometricWeight = exp(-pow(i, 2) / (2 * pow(sigma, 2))); float sampleDepth = tex2D(sMRT2, float2(uv.x, uv.y - i * stepY)).z; float photometricWeight = 1 / pow((1 + abs(fragmentDepth - sampleDepth)), cPhotometricExponent); weights += (geometricWeight * photometricWeight); blurred += tex2D(sAccessibility, float2(uv.x, uv.y - i * stepY)).r * geometricWeight * photometricWeight; } blurred /= weights; oColor0 = float4(blurred.xxx, 1); }