float3 applyWhiteBalanceOnly(float3 color) { float warmAmount = clamp(warmCool, -1.0, 1.0); float tintAmount = clamp(greenMagenta, -1.0, 1.0); // Warm/cool pivots red against blue while keeping green more stable. float3 warmCoolGain = float3( exp2(warmAmount * 0.35), exp2(-abs(warmAmount) * 0.08), exp2(-warmAmount * 0.35)); // Green/magenta pivots green against the average of red and blue. float3 tintGain = float3( exp2(-tintAmount * 0.22), exp2(tintAmount * 0.35), exp2(-tintAmount * 0.22)); return color * warmCoolGain * tintGain; } float3 applyExposureLikeBlender(float3 color) { // Match the compositor-style exposure model: every +1.0 stop doubles the // image and every -1.0 stop halves it. return color * exp2(exposure); } float4 shadeVideo(ShaderContext context) { float4 source = context.sourceColor; float3 balanced = applyWhiteBalanceOnly(source.rgb); float3 corrected = applyExposureLikeBlender(balanced); source.rgb = lerp(source.rgb, corrected, saturate(strength)); return source; }