// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors. // All rights reserved. // Code licensed under the BSD License. // http://www.anki3d.org/LICENSE // Calculates the disocclusion length. The longer the length the better the pixel is for temporal accumulation #pragma anki technique comp vert pixel #include #include #include constexpr F32 kZDistanceLimit = 0.05; // In meters Texture2D g_depthTex : register(t0); Texture2D g_historyDepthTex : register(t1); Texture2D g_motionVectorsTex : register(t2); Texture2D g_prevHistoryLengthTex : register(t3); RWTexture2D g_historyLengthTex : register(u0); ConstantBuffer g_globalRendererConsts : register(b0); SamplerState g_linearAnyClampSampler : register(s0); Vec3 unproject(Vec2 ndc, F32 d) { return cheapPerspectiveUnprojection(g_globalRendererConsts.m_matrices.m_unprojectionParameters, ndc, d); } F32 computeLength(Vec2 coord) { Vec2 viewport; g_depthTex.GetDimensions(viewport.x, viewport.y); const Vec2 uv = (coord + 0.5) / viewport; const Vec2 ndc = uvToNdc(uv); const Vec2 historyUv = uv + TEX(g_motionVectorsTex, coord) + (g_globalRendererConsts.m_previousMatrices.m_jitterOffsetNdc - g_globalRendererConsts.m_matrices.m_jitterOffsetNdc) / Vec2(2.0, -2.0); // Compute length F32 good = 0.0; // Zero means "new" pixel this frame if(any(historyUv < 0.0) || any(historyUv > 1.0)) { good = 0.0; } else { const F32 crntDepth = g_depthTex[coord]; if(crntDepth == 1.0) { return 0.0; } const F32 crntViewZ = cheapPerspectiveUnprojection(g_globalRendererConsts.m_matrices.m_unprojectionParameters, ndc, crntDepth).z; // Read history const F32 historyDepth = g_historyDepthTex.SampleLevel(g_linearAnyClampSampler, historyUv, 0.0f); const Vec4 v = mul(g_globalRendererConsts.m_previousMatrices.m_invertedViewProjection, Vec4(uvToNdc(historyUv), historyDepth, 1.0)); const F32 historyViewZ = mul(g_globalRendererConsts.m_matrices.m_view, Vec4(v.xyz / v.w, 1.0)).z; const F32 dist = abs(crntViewZ - historyViewZ); const F32 factor = dist / kZDistanceLimit; good = 1.0 - min(factor, 1.0); } F32 len = good; if(good > 0.1) { const F32 prevLen = g_prevHistoryLengthTex.SampleLevel(g_linearAnyClampSampler, historyUv, 0.0f) * kMaxHistoryLength; len += prevLen; len = min(len, kMaxHistoryLength); } return len / kMaxHistoryLength; } #if ANKI_COMPUTE_SHADER [numthreads(64, 1, 1)] void main(COMPUTE_ARGS) { const Vec2 coord = getOptimalDispatchThreadId8x8Amd(svGroupIndex, svGroupId.xy); Vec2 viewport; g_historyLengthTex.GetDimensions(viewport.x, viewport.y); if(any(coord >= viewport)) { return; } const F32 len = computeLength(coord); TEX(g_historyLengthTex, coord) = len; } #endif #if ANKI_PIXEL_SHADER F32 main(VertOut input) : SV_TARGET0 { const Vec2 coord = floor(input.m_svPosition.xy); return computeLength(coord); } #endif