float luminance(float3 color) { return dot(color, float3(0.2126, 0.7152, 0.0722)); } float4 buildHistory(ShaderContext context) { float4 previousFeedback = sampleFeedback(context.uv); float4 previousHistory = context.feedbackAvailable > 0 ? previousFeedback : float4(0.0, 0.0, 0.0, 0.0); // Highlight selection is always based on the live source image only. // The stored feedback never feeds back into the threshold test. float currentLuma = luminance(context.sourceColor.rgb); float thresholdWidth = max(softness, 0.0001); float brightMask = smoothstep(highlightThreshold - thresholdWidth, highlightThreshold + thresholdWidth, currentLuma); // Treat RGBA as a 4-slot rolling scalar history: // R = current frame, G = 1 frame ago, B = 2 frames ago, A = 3 frames ago. // Each frame shifts the history forward and drops the oldest sample. float currentContribution = currentLuma * brightMask * max(accumulateAmount, 0.0); float4 nextHistory = float4( currentContribution, previousHistory.r, previousHistory.g, previousHistory.b ); return saturate(nextHistory); } float4 displayHistory(ShaderContext context) { // In the display pass, context.sourceColor is the same-frame historyBuffer // produced by buildHistory(). float4 history = context.sourceColor; float recentEnergy = history.r + history.g + history.b; float3 originalColor = sampleLayerInput(context.uv).rgb; float highlightBoost = recentEnergy * max(displayGain, 0.0); float3 sourceHue = originalColor / max(max(originalColor.r, originalColor.g), max(originalColor.b, 0.0001)); float3 displayColor = originalColor + sourceHue * highlightBoost * 1.5; return float4(saturate(displayColor), 1.0); }