void Crytek_fp ( in float4 position : POSITION, in float2 fragmentTC : TEXCOORD0, out float4 oColor0 : COLOR0, uniform sampler sSceneDepthSampler : register(s0), // depth = w component [0, 1] uniform sampler sRotSampler4x4 : register(s1), // rotation sampler -> pseudo random spherical weighted sampling uniform float4 cViewportSize, // auto param width/height/inv. width/inv. height uniform float cFov, // vertical field of view in radians uniform float farClipDistance, uniform float cSampleInScreenspace, // whether to sample in screen or world space uniform float cSampleLengthScreenSpace, // The sample length in screen space [0, 1] uniform float cSampleLengthWorldSpace, // the sample length in world space in units uniform float cOffsetScale, // [0, 1] The distance of the first sample. samples are the // placed in [cOffsetScale * cSampleLengthScreenSpace, cSampleLengthScreenSpace] uniform float cDefaultAccessibility, // the default value used in the lerp() expression for invalid samples [0, 1] uniform float cEdgeHighlight // multiplier for edge highlighting in [1, 2] 1 is full highlighting 2 is off ) { const int nSampleNum = 32; // number of samples // get the depth of the current pixel and convert into world space unit [0, inf] float fragmentWorldDepth = tex2D(sSceneDepthSampler, fragmentTC).w * farClipDistance; // get rotation vector, rotation is tiled every 4 screen pixels float2 rotationTC = fragmentTC * cViewportSize.xy / 4; float3 rotationVector = 2 * tex2D(sRotSampler4x4, rotationTC).xyz - 1; // [-1, 1]x[-1. 1]x[-1. 1] float rUV = 0; // radius of influence in screen space float r = 0; // radius of influence in world space if (cSampleInScreenspace == 1) { rUV = cSampleLengthScreenSpace; r = tan(rUV * cFov) * fragmentWorldDepth; } else { rUV = atan(cSampleLengthWorldSpace / fragmentWorldDepth) / cFov; // the radius of influence projected into screen space r = cSampleLengthWorldSpace; } float sampleLength = cOffsetScale; // the offset for the first sample const float sampleLengthStep = pow((rUV / sampleLength), 1.0f/nSampleNum); float accessibility = 0; // sample the sphere and accumulate accessibility for (int i = 0; i < (nSampleNum/8); i++) { for (int x = -1; x <= 1; x += 2) for (int y = -1; y <= 1; y += 2) for (int z = -1; z <= 1; z += 2) { //generate offset vector float3 offset = normalize(float3(x, y, z)) * sampleLength; // update sample length sampleLength *= sampleLengthStep; // reflect offset vector by random rotation sample (i.e. rotating it) float3 rotatedOffset = reflect(offset, rotationVector); float2 sampleTC = fragmentTC + rotatedOffset.xy * rUV; // read scene depth at sampling point and convert into world space units (m or whatever) float sampleWorldDepth = tex2D(sSceneDepthSampler, sampleTC).w * farClipDistance; // check if depths of both pixels are close enough and sampling point should affect our center pixel float fRangeIsInvalid = saturate((fragmentWorldDepth - sampleWorldDepth) / r); // accumulate accessibility, use default value of 0.5 if right computations are not possible accessibility += lerp(sampleWorldDepth > (fragmentWorldDepth + rotatedOffset.z * r), cDefaultAccessibility, fRangeIsInvalid); } } // get average value accessibility /= nSampleNum; // normalize, remove edge highlighting accessibility *= cEdgeHighlight; // amplify and saturate if necessary oColor0 = float4(accessibility.xxx, 1); }