playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
3 lines (2 loc) • 3.61 kB
TypeScript
declare const _default: "\n #include \"sampleCatmullRomPS\"\n #include \"screenDepthPS\"\n\n uniform sampler2D sourceTexture;\n uniform sampler2D historyTexture;\n uniform mat4 matrix_viewProjectionPrevious;\n uniform mat4 matrix_viewProjectionInverse;\n uniform vec4 jitters; // xy: current frame, zw: previous frame\n uniform vec2 textureSize;\n\n varying vec2 uv0;\n\n vec2 reproject(vec2 uv, float depth) {\n\n // fragment NDC\n depth = depth * 2.0 - 1.0;\n vec4 ndc = vec4(uv * 2.0 - 1.0, depth, 1.0);\n\n // remove jitter from the current frame\n ndc.xy -= jitters.xy;\n\n // Transform NDC to world space of the current frame\n vec4 worldPosition = matrix_viewProjectionInverse * ndc;\n worldPosition /= worldPosition.w;\n\n // world position to screen space of the previous frame\n vec4 screenPrevious = matrix_viewProjectionPrevious * worldPosition;\n\n return (screenPrevious.xy / screenPrevious.w) * 0.5 + 0.5;\n }\n\n vec3 colorClampPremul(vec2 uv, vec3 historyPremul) {\n\n vec3 minPremul = vec3(9999.0);\n vec3 maxPremul = vec3(-9999.0);\n\n // 3x3 neighborhood in premultiplied space \u2014 same domain as the temporal mix (see main()).\n for(float x = -1.0; x <= 1.0; ++x) {\n for(float y = -1.0; y <= 1.0; ++y) {\n vec4 s = texture2D(sourceTexture, uv + vec2(x, y) / textureSize);\n vec3 premul = s.rgb * s.a;\n minPremul = min(minPremul, premul);\n maxPremul = max(maxPremul, premul);\n }\n }\n\n return clamp(historyPremul, minPremul, maxPremul);\n }\n\n void main()\n {\n // current frame\n vec4 srcColor = texture2D(sourceTexture, uv0);\n\n // current depth is in linear space, convert it to non-linear space\n float linearDepth = getLinearScreenDepth(uv0);\n float depth = delinearizeDepth(linearDepth);\n\n // previous frame\n vec2 historyUv = reproject(uv0, depth);\n\n #ifdef QUALITY_HIGH\n\n vec4 historySample = SampleTextureCatmullRom(TEXTURE_PASS(historyTexture), historyUv, textureSize);\n\n #else\n\n vec4 historySample = texture2D(historyTexture, historyUv);\n\n #endif\n\n // Premultiplied (rgb * a) is the coverage-correct space for TAA: straight RGB interpolates\n // uncorrelated color and opacity at edges, which causes colored fringes and alpha-related\n // ghosting when history is blended or clamped against a 3x3 neighborhood. We clamp and mix\n // in premultiplied space, then un-premultiply once using the current frame's alpha only\n // (alpha is not temporally filtered \u2014 output stays tied to this frame's coverage).\n vec3 historyPremul = historySample.rgb * historySample.a;\n vec3 srcPremul = srcColor.rgb * srcColor.a;\n\n vec3 historyPremulClamped = colorClampPremul(uv0, historyPremul);\n\n float mixFactor = (historyUv.x < 0.0 || historyUv.x > 1.0 || historyUv.y < 0.0 || historyUv.y > 1.0) ?\n 1.0 : 0.05;\n\n vec3 mixedPremul = mix(historyPremulClamped, srcPremul, mixFactor);\n float a = srcColor.a;\n // Match UNORM8 alpha quantum: below one step, un-premul is ill-defined / noisy; use current RGB.\n const float UNPREMUL_EPS = 1.0 / 255.0;\n vec3 rgbStraight = (a > UNPREMUL_EPS) ? (mixedPremul / a) : srcColor.rgb;\n gl_FragColor = vec4(rgbStraight, a);\n }\n";
export default _default;