// Temporal scene resolve and full-resolution composite. No material/lighting // descriptors are consumed here; the scene was shaded before this pass. // Velocity target: xy = current-minus-prior scene-local UV, z = expected prior // clip depth, w = opaque motion validity (zero for reactive/invalid pixels). #if defined(FASET_TEMPORAL_RESOLVE) struct TemporalResolveParameters { uint4 dimensions; // output width/height, internal width/height float4 outputSceneRect; // output-pixel x/y/width/height float4 internalSceneRect; // internal-pixel x/y/width/height uint4 flags; // x = prior history valid }; [[vk::push_constant]] ConstantBuffer temporalParameters; [[vk::binding(0,0)]] Texture2D currentSceneColor; [[vk::binding(1,0)]] Texture2D currentSceneDepth; [[vk::binding(2,0)]] Texture2D currentSceneVelocity; [[vk::binding(3,0)]] Texture2D previousHistoryColor; [[vk::binding(4,0)]] Texture2D previousHistoryDepth; [[vk::binding(5,0)]] [vk::image_format("rgba16f")] RWTexture2D nextHistoryColor; [[vk::binding(6,0)]] [vk::image_format("r32f")] RWTexture2D nextHistoryDepth; int2 clampScenePixel(int2 pixel) { return clamp(pixel, int2(0), int2(temporalParameters.dimensions.zw) - 1); } float4 sceneColorAt(int2 pixel) { return currentSceneColor.Load(int3(clampScenePixel(pixel), 0)); } float sceneDepthAt(int2 pixel) { return currentSceneDepth.Load(int3(clampScenePixel(pixel), 0)); } float4 sceneVelocityAt(int2 pixel) { return currentSceneVelocity.Load(int3(clampScenePixel(pixel), 0)); } float4 historyBilinear(float2 uv) { float2 position = uv * float2(temporalParameters.dimensions.xy) - .5; int2 base = int2(floor(position)); float2 fraction = position - float2(base); int2 limit = int2(temporalParameters.dimensions.xy) - 1; int2 p00 = clamp(base, int2(0), limit); int2 p10 = clamp(base + int2(1, 0), int2(0), limit); int2 p01 = clamp(base + int2(0, 1), int2(0), limit); int2 p11 = clamp(base + int2(1, 1), int2(0), limit); float4 top = lerp(previousHistoryColor.Load(int3(p00, 0)), previousHistoryColor.Load(int3(p10, 0)), fraction.x); float4 bottom = lerp(previousHistoryColor.Load(int3(p01, 0)), previousHistoryColor.Load(int3(p11, 0)), fraction.x); return lerp(top, bottom, fraction.y); } [shader("compute")] [numthreads(8, 8, 1)] void temporalResolveMain(uint3 dispatchId : SV_DispatchThreadID) { const uint2 outputPixel = dispatchId.xy; const uint2 outputExtent = temporalParameters.dimensions.xy; const uint2 internalExtent = temporalParameters.dimensions.zw; if (outputPixel.x >= outputExtent.x || outputPixel.y >= outputExtent.y) return; const float2 center = float2(outputPixel) + .5; const float4 outputRect = temporalParameters.outputSceneRect; const float4 internalRect = temporalParameters.internalSceneRect; const bool insideScene = all(center >= outputRect.xy) && all(center < outputRect.xy + outputRect.zw) && all(outputRect.zw > 0); const float2 sceneLocalUV = insideScene ? (center - outputRect.xy) / outputRect.zw : float2(0); const float2 internalPosition = insideScene ? internalRect.xy + sceneLocalUV * internalRect.zw : center / float2(outputExtent) * float2(internalExtent); const int2 currentPixel = clampScenePixel(int2(floor(internalPosition))); const float4 currentColor = sceneColorAt(currentPixel); const float currentDepth = sceneDepthAt(currentPixel); float4 resolved = currentColor; if (insideScene && temporalParameters.flags.x != 0) { const float4 centerMotion = sceneVelocityAt(currentPixel); if (all(isfinite(centerMotion)) && centerMotion.w > 0 && centerMotion.z >= 0 && centerMotion.z <= 1) { float4 selectedMotion = centerMotion; float selectedDepth = currentDepth; const float currentTolerance = .002 + .01 * currentDepth; [unroll] for (int dy = -1; dy <= 1; ++dy) [unroll] for (int dx = -1; dx <= 1; ++dx) { const int2 neighbor = clampScenePixel(currentPixel + int2(dx, dy)); const float depth = sceneDepthAt(neighbor); const float4 motion = sceneVelocityAt(neighbor); if (all(isfinite(motion)) && motion.w > 0 && motion.z >= 0 && motion.z <= 1 && abs(depth - currentDepth) <= currentTolerance && depth < selectedDepth) { selectedDepth = depth; selectedMotion = motion; } } const float2 previousLocalUV = sceneLocalUV - selectedMotion.xy; if (all(isfinite(previousLocalUV)) && all(previousLocalUV >= 0) && all(previousLocalUV < 1)) { const float2 previousOutputUV = (outputRect.xy + previousLocalUV * outputRect.zw) / float2(outputExtent); if (all(previousOutputUV >= 0) && all(previousOutputUV < 1)) { const int2 priorPixel = clamp( int2(floor(previousOutputUV * float2(outputExtent))), int2(0), int2(outputExtent) - 1); const float priorDepth = previousHistoryDepth.Load(int3(priorPixel, 0)); const float depthTolerance = .002 + .01 * selectedMotion.z; if (isfinite(priorDepth) && abs(priorDepth - selectedMotion.z) <= depthTolerance) { float3 low = float3(1e30), high = float3(-1e30); [unroll] for (int dy = -1; dy <= 1; ++dy) [unroll] for (int dx = -1; dx <= 1; ++dx) { const float3 color = sceneColorAt(currentPixel + int2(dx, dy)).rgb; low = min(low, color); high = max(high, color); } const float2 motionPixels = selectedMotion.xy * outputRect.zw; const float weight = .9 * saturate(centerMotion.w) / (1 + .5 * length(motionPixels)); const float3 priorColor = clamp(historyBilinear(previousOutputUV).rgb, low, high); resolved.rgb = lerp(currentColor.rgb, priorColor, weight); } } } } } nextHistoryColor[outputPixel] = resolved; nextHistoryDepth[outputPixel] = currentDepth; } #elif defined(FASET_TEMPORAL_COMPOSITE) [[vk::binding(0,0)]] Texture2D resolvedHistoryColor; [shader("vertex")] float4 temporalCompositeVertexMain(uint vertexId : SV_VertexID) : SV_Position { const float2 position = vertexId == 0 ? float2(-1, -1) : vertexId == 1 ? float2(3, -1) : float2(-1, 3); return float4(position, 0, 1); } [shader("fragment")] float4 temporalCompositeFragmentMain(float4 position : SV_Position) : SV_Target { // Scene shading is already display-referred. No second tone or gamma pass. return resolvedHistoryColor.Load(int3(int2(position.xy), 0)); } #else #error Select FASET_TEMPORAL_RESOLVE or FASET_TEMPORAL_COMPOSITE. #endif