export declare const speckleStaticAoGenerateFrag = "\n\t\t#include \n\t\t#define AO_ESTIMATOR 1\n\t\t#define NORMAL_TEXTURE 0\n\t\t#define IMPROVED_NORMAL_RECONSTRUCTION 0\n\t\t#define ACCURATE_NORMAL_RECONSTRUCTION 1\n\n\t\tvarying vec2 vUv;\n\t\tuniform sampler2D tDepth;\n\t\tuniform sampler2D tNormal;\n uniform vec2 size;\n\n\t\tuniform float cameraNear;\n\t\tuniform float cameraFar;\n\t\tuniform mat4 cameraProjectionMatrix;\n\t\tuniform mat4 cameraInverseProjectionMatrix;\n\t\t\n\t\tuniform float intensity;\n\t\tuniform float bias;\n\t\tuniform float kernelRadius;\n\t\t\n\t\t\n\t\t#if AO_ESTIMATOR == 0\n\t\t\t#define NUM_SAMPLES 16\n \t#define SPIRAL_TURNS 2\n\t\t\t#define INV_NUM_SAMPLES 1.0 / float( NUM_SAMPLES )\n \t#define offset PI2 / float(NUM_FRAMES)\n\n\t\t\tuniform float minResolution;\n\t\t\tuniform float frameIndex;\n\t\t\tuniform float scale;\n\t\t#endif\n\n\t\t#if AO_ESTIMATOR == 1\n\t\t\tuniform float tanFov;\n\t\t\tuniform sampler2D tNoise;\n\t\t\tuniform vec3 kernel[ KERNEL_SIZE ];\n\t\t#endif\n\n\t\t// RGBA depth\n\t\t#include \n\t\tvec4 getDefaultColor( const in vec2 screenPosition ) {\n\t\t\treturn vec4( 1.0 );\n\t\t}\n\n\n\t\tfloat getLinearDepth( const in vec2 screenPosition ) {\n\t\t\treturn unpackRGBAToDepth( texture2D( tDepth, screenPosition ) );\n\t\t}\n\n\t\tfloat getPerspectiveDepth(const in vec2 coords) {\n\t\t\tfloat linearDepth = unpackRGBAToDepth( texture2D( tDepth, coords ) );\n\t\t\t#if PERSPECTIVE_CAMERA == 1\n\t\t\t\tfloat viewZ = orthographicDepthToViewZ(linearDepth, cameraNear, cameraFar);\n\t\t\t\tfloat centerDepth = viewZToPerspectiveDepth(viewZ, cameraNear, cameraFar);\n\t\t\t\treturn centerDepth;\n\t\t\t#else\n\t\t\t\treturn linearDepth;\n\t\t\t#endif\n\t\t}\n\n\t\tfloat getViewDepth(const in float linearDepth) {\n\t\t\treturn orthographicDepthToViewZ(linearDepth, cameraNear, cameraFar);\n\t\t}\n\n\t\tfloat getViewZ( const in float depth ) {\n\t\t\t#if PERSPECTIVE_CAMERA == 1\n\t\t\treturn perspectiveDepthToViewZ( depth, cameraNear, cameraFar );\n\t\t\t#else\n\t\t\treturn orthographicDepthToViewZ( depth, cameraNear, cameraFar );\n\t\t\t#endif\n\t\t}\n\n\t\tvec3 getViewPosition( const in vec2 screenPosition, const in float depth, const in float viewZ ) {\n\t\t\tfloat clipW = cameraProjectionMatrix[2][3] * viewZ + cameraProjectionMatrix[3][3];\n\t\t\tvec4 clipPosition = vec4( ( vec3( screenPosition, depth ) - 0.5 ) * 2.0, 1.0 );\n\t\t\tclipPosition *= clipW; // unprojection.\n\t\t\treturn ( cameraInverseProjectionMatrix * clipPosition ).xyz;\n\t\t}\n\n\t\t//https://wickedengine.net/2019/09/22/improved-normal-reconstruction-from-depth/\n\t\tvec3 viewNormalImproved(in vec2 uv, in vec3 origin)\n\t\t{\t\n\t\t\thighp vec2 dd = abs(vec2(1./size.x, 1./size.y));\n\t\t\thighp vec2 ddx = vec2(dd.x, 0.);\n\t\t\thighp vec2 ddy = vec2(0., dd.y);\n\n\t\t\tfloat sampleDepth = getPerspectiveDepth( uv - ddy );\n\t\t\tfloat sampleViewZ = getViewZ( sampleDepth );\n\t\t\thighp vec3 top = getViewPosition( uv - ddy, sampleDepth, sampleViewZ );\n\n\t\t\tsampleDepth = getPerspectiveDepth( uv + ddy );\n\t\t\tsampleViewZ = getViewZ( sampleDepth );\n\t\t\thighp vec3 bottom = getViewPosition( uv + ddy, sampleDepth, sampleViewZ );\n\n\t\t\thighp vec3 center = origin;\n\t\t\t\n\t\t\tsampleDepth = getPerspectiveDepth( uv - ddx );\n\t\t\tsampleViewZ = getViewZ( sampleDepth );\n\t\t\thighp vec3 left = getViewPosition( uv - ddx, sampleDepth, sampleViewZ );\n\n\t\t\tsampleDepth = getPerspectiveDepth( uv + ddx );\n\t\t\tsampleViewZ = getViewZ( sampleDepth );\n\t\t\thighp vec3 right = getViewPosition( uv + ddx, sampleDepth, sampleViewZ );\n\n\t\t\t // get the difference between the current and each offset position\n\t\t\tvec3 l = center - left;\n\t\t\tvec3 r = right - center;\n\t\t\tvec3 d = center - top;\n\t\t\tvec3 u = bottom - center;\n\n\t\t\t// pick horizontal and vertical diff with the smallest z difference\n\t\t\tvec3 hDeriv = abs(l.z) < abs(r.z) ? l : r;\n\t\t\tvec3 vDeriv = abs(d.z) < abs(u.z) ? d : u;\n\n\t\t\t// get view space normal from the cross product of the two smallest offsets\n\t\t\tvec3 viewNormal = normalize(cross(hDeriv, vDeriv));\n\n\t\t\treturn viewNormal;\n\t\t}\n\n\t\tvec3 viewNormalAccurate(in vec2 uv, in vec3 origin, in float centerDepth) {\n\t\t\thighp vec2 dd = abs(vec2(1./size.x, 1./size.y));\n\t\t\thighp vec2 ddx = vec2(dd.x, 0.);\n\t\t\thighp vec2 ddy = vec2(0., dd.y);\n\n\t\t\tfloat sampleDepth = getPerspectiveDepth( uv - ddy );\n\t\t\tfloat sampleViewZ = getViewZ( sampleDepth );\n\t\t\thighp vec3 top = getViewPosition( uv - ddy, sampleDepth, sampleViewZ );\n\n\t\t\tsampleDepth = getPerspectiveDepth( uv + ddy );\n\t\t\tsampleViewZ = getViewZ( sampleDepth );\n\t\t\thighp vec3 bottom = getViewPosition( uv + ddy, sampleDepth, sampleViewZ );\n\n\t\t\thighp vec3 center = origin;\n\t\t\t\n\t\t\tsampleDepth = getPerspectiveDepth( uv - ddx );\n\t\t\tsampleViewZ = getViewZ( sampleDepth );\n\t\t\thighp vec3 left = getViewPosition( uv - ddx, sampleDepth, sampleViewZ );\n\n\t\t\tsampleDepth = getPerspectiveDepth( uv + ddx );\n\t\t\tsampleViewZ = getViewZ( sampleDepth );\n\t\t\thighp vec3 right = getViewPosition( uv + ddx, sampleDepth, sampleViewZ );\n\n\t\t\t // get the difference between the current and each offset position\n\t\t\tvec3 l = center - left;\n\t\t\tvec3 r = right - center;\n\t\t\tvec3 d = center - top;\n\t\t\tvec3 u = bottom - center;\n\n\t\t\t// get depth values at 1 & 2 pixels offsets from current along the horizontal axis\n\t\t\tvec4 H = vec4(\n\t\t\t\tgetLinearDepth(uv - ddx),\n\t\t\t\tgetLinearDepth(uv + ddx),\n\t\t\t\tgetLinearDepth(uv - 2. * ddx),\n\t\t\t\tgetLinearDepth(uv + 2. * ddx)\n\t\t\t);\n\n\t\t\t// get depth values at 1 & 2 pixels offsets from current along the vertical axis\n\t\t\tvec4 V = vec4(\n\t\t\t\tgetLinearDepth(uv - ddy),\n\t\t\t\tgetLinearDepth(uv + ddy),\n\t\t\t\tgetLinearDepth(uv - 2. * ddy),\n\t\t\t\tgetLinearDepth(uv + 2. * ddy)\n\t\t\t);\n\n\t\t\t// current pixel's depth difference from slope of offset depth samples\n\t\t\t// differs from original article because we're using non-linear depth values\n\t\t\t// see article's comments\n\t\t\tvec2 he = abs((2. * H.xy - H.zw) - centerDepth);\n\t\t\tvec2 ve = abs((2. * V.xy - V.zw) - centerDepth);\n\n\t\t\t// pick horizontal and vertical diff with the smallest depth difference from slopes\n\t\t\tvec3 hDeriv = he.x < he.y ? l : r;\n\t\t\tvec3 vDeriv = ve.x < ve.y ? d : u;\n\n\t\t\t// get view space normal from the cross product of the best derivatives\n\t\t\tvec3 viewNormal = normalize(cross(hDeriv, vDeriv));\n\n\t\t\treturn viewNormal;\n\n\t\t}\n\n\t\tvec3 getViewNormal( const in vec3 viewPosition, const in vec2 screenPosition, in float centerDepth ) {\n\t\t\t#if NORMAL_TEXTURE == 1\n\t\t\t\treturn unpackRGBToNormal( texture2D( tNormal, screenPosition ).xyz );\n\t\t\t#elif IMPROVED_NORMAL_RECONSTRUCTION == 1\n\t\t\t\treturn viewNormalImproved(screenPosition, viewPosition);\n\t\t\t#elif ACCURATE_NORMAL_RECONSTRUCTION == 1\n\t\t\t\treturn viewNormalAccurate(screenPosition, viewPosition, centerDepth);\n\t\t\t#else\n\t\t\t\treturn normalize( cross( dFdx( viewPosition ), dFdy( viewPosition ) ) );\n\t\t\t#endif\n\t\t}\n\n\n\t\tfloat scaleDividedByCameraFar;\n\t\tfloat minResolutionMultipliedByCameraFar;\n // moving costly divides into consts\n\t\t\n\n\t\tfloat computeKernelSize(float d, float r) {\n\t\t\t#if PERSPECTIVE_CAMERA == 1\n\t\t\t\t// Apparently this is wrong\n\t\t\t\t// return (r * tan(fov) * d) / (size.y * 0.5);\n\t\t\t\t// And this is correct\n\t\t\t\tfloat rp = r / (size.y * 0.5);\n\t\t\t\treturn sqrt((rp*rp*tanFov*tanFov*d*d)/(1. + rp*rp*tanFov*tanFov));\n\t\t\t#else\n\t\t\t\tfloat twoOrthoSize = size.y / (2./ cameraProjectionMatrix[1][1]);\n\t\t\t\treturn r / twoOrthoSize;\n\t\t\t#endif\n\t\t}\n\n\t\tfloat getAmbientOcclusion( const in vec3 centerViewPosition, in float centerDepth ) {\n #if AO_ESTIMATOR == 0\n // precompute some variables require in getOcclusion.\n scaleDividedByCameraFar = scale / cameraFar;\n minResolutionMultipliedByCameraFar = minResolution * cameraFar;\n vec3 centerViewNormal = getViewNormal( centerViewPosition, vUv, centerDepth );\n // jsfiddle that shows sample pattern: https://jsfiddle.net/TenHands/jun67k9y/7/\n float occlusionSum = 0.0;\n float weightSum = 0.0;\n for( int i = 0; i < NUM_SAMPLES; i ++ ) {\n float alpha = ( float(i) + 1. ) / float(NUM_SAMPLES);\n float angle = float(SPIRAL_TURNS) * alpha;\n vec2 radius = (kernelRadius / size) * pow( alpha, 1.1 );\n vec2 sampleUv = vUv + vec2( cos( angle + frameIndex * offset ), sin( angle + frameIndex * offset ) ) * radius;\n\n float sampleDepth = getPerspectiveDepth( sampleUv );\n if( sampleDepth >= ( 1.0 - EPSILON ) ) {\n continue;\n }\n float sampleViewZ = getViewZ( sampleDepth );\n vec3 sampleViewPosition = getViewPosition( sampleUv, sampleDepth, sampleViewZ );\n\n\t\t\t\t\t/** McGuire Estimator*/\n\t\t\t\t\tvec3 v = sampleViewPosition - centerViewPosition;\n\t\t\t\t\tfloat vv = dot(v, v);\n\t\t\t\t\tfloat vn = dot(v, centerViewNormal) - bias;\n\t\t\t\t\t\n\t\t\t\t\t// Note large epsilon to avoid overdarkening within cracks\n\t\t\t\t\tfloat radius2 = 2.;//uSampleRadiusWS * uSampleRadiusWS\n\t\t\t\t\tfloat epsilon = 0.01;\n\t\t\t\t\t\n\t\t\t\t\tfloat f = max(radius2 - vv, 0.0) / radius2;\n\t\t\t\t\tocclusionSum += f * f * f * max(vn / (epsilon + vv), 0.0) / 4.;\n\n\t\t\t\t\t/** Three.js SAO Estimator*/\n // vec3 viewDelta = sampleViewPosition - centerViewPosition;\n // float viewDistance = length( viewDelta );\n // float scaledScreenDistance = scaleDividedByCameraFar * viewDistance;\n // occlusionSum += max(0.0, (dot(centerViewNormal, viewDelta) - minResolutionMultipliedByCameraFar) / scaledScreenDistance - bias) / (1.0 + pow2( scaledScreenDistance ) );\n weightSum += 1.0;\n }\n if( weightSum == 0.0 ) discard;\n return occlusionSum * ( intensity / weightSum );\n\t\t\t#elif AO_ESTIMATOR == 1\n\t\t\t\tvec3 viewPosition = centerViewPosition;\n\t\t\t\tvec3 viewNormal = getViewNormal( centerViewPosition, vUv, centerDepth );\n\t\t\t\tvec2 noiseScale = vec2( size.x / 4.0, size.y / 4.0 );\n\t\t\t\tvec3 random = vec3( texture2D( tNoise, vUv * noiseScale ).r );\n\t\t\t\t// compute matrix used to reorient a kernel vector\n\t\t\t\tvec3 tangent = normalize( random - viewNormal * dot( random, viewNormal ) );\n\t\t\t\tvec3 bitangent = cross( viewNormal, tangent );\n\t\t\t\tmat3 kernelMatrix = mat3( tangent, bitangent, viewNormal );\n\t\t\t\tfloat occlusion = 0.0;\n\t\t\t\tfloat kernelSize_ws = computeKernelSize(-viewPosition.z, kernelRadius);\n\t\t\t\tfloat div = float( KERNEL_SIZE);\n\t\t\t\tfloat maxDist = kernelSize_ws / (cameraFar - cameraNear);\n\t\t\t\tfor ( int i = 0; i < KERNEL_SIZE; i ++ ) {\n\t\t\t\t\tvec3 sampleVector = kernelMatrix * kernel[ i ]; // reorient sample vector in view space\n\t\t\t\t\tvec3 samplePoint = viewPosition + ( sampleVector * kernelSize_ws ); // calculate sample point\n\t\t\t\t\tvec4 samplePointNDC = cameraProjectionMatrix * vec4( samplePoint, 1.0 ); // project point and calculate NDC\n\t\t\t\t\tsamplePointNDC /= samplePointNDC.w;\n\t\t\t\t\tvec2 samplePointUv = samplePointNDC.xy * 0.5 + 0.5; // compute uv coordinates\n\t\t\t\t\tfloat realDepth = getLinearDepth( samplePointUv ); // get linear depth from depth texture\n\t\t\t\t\tfloat sampleDepth = viewZToOrthographicDepth( samplePoint.z + bias, cameraNear, cameraFar ); // compute linear depth of the sample view Z value\n\t\t\t\t\tfloat delta = sampleDepth - realDepth;\n\t\t\t\t\tif ( delta > 0. && delta < maxDist ) { // if fragment is before sample point, increase occlusion\n\t\t\t\t\t\tocclusion += 1.0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn clamp( occlusion * intensity / div, 0.0, 1.0 );\n\t\t\t#endif\n\t\t\t}\n\t\tvoid main() {\n\t\t\tfloat linearDepth = unpackRGBAToDepth( texture2D( tDepth, vUv ) );\n\t\t\tfloat centerDepth = getPerspectiveDepth(vUv);\n\t\t\tif( centerDepth >= ( 1.0 - EPSILON ) ) {\n\t\t\t\tdiscard;\n\t\t\t}\n\t\t\tfloat centerViewZ = getViewDepth(linearDepth);\n\t\t\tvec3 viewPosition = getViewPosition( vUv, centerDepth, centerViewZ );\n\t\t\tvec3 viewNormal = getViewNormal(viewPosition, vUv, linearDepth);\n\t\t\tfloat ambientOcclusion = getAmbientOcclusion( viewPosition, centerDepth );\n\t\t\tgl_FragColor = getDefaultColor( vUv );\n\t\t\tgl_FragColor.xyz *= ambientOcclusion;\n\t\t\tgl_FragColor.a = 1.;\n\t\t}";