Color/Hue shift in Temporal Accumulation?

Started by
3 comments, last by JoeJ 2 years ago

I use the Accumulate buffer to interpolate the lighting results from the current and previous frames. As the frames accumulated, I noticed that the tint of the picture changed.

after a few accumulations
after number of accumulations
after many many accumulations
AccRad = clamp(CurrentFrameRad, 0.0f, FP16_MAX);

const float lerpFactor = AccumulateFrames / (AccumulateFrames + 1.0f);
float3 NewRad = AccRad;
float3 PrevRad = HistoryRad[SampleIdx].xyz;
float3 NewRad = lerp(NewRadiance, PrevRadiance, lerpFactor);
HistoryRad[SampleIdx] = float4(NewRad,1.0f);

Above is the relative code, has anyone had a similar problem or has any suggestions?

Advertisement

iGrfx said:
after many many accumulations

How many?
I guess the problem is floating point precision, but there are maybe many potential reasons:

AccRad = clamp(CurrentFrameRad, 0.0f, FP16_MAX); // is your image at 16 bit precision?

const float lerpFactor = AccumulateFrames / (AccumulateFrames + 1.0f);
float3 NewRad = AccRad; // float3 is at 32 bit precision? maybe the conversion does not preserve 16 bit accuracy, and error accumulates
float3 PrevRad = HistoryRad[SampleIdx].xyz;
float3 NewRad = lerp(NewRadiance, PrevRadiance, lerpFactor);
 // not sure how lerp is implemented, but x = a*f + b*(1-f) is more accurate than x = a + (b-a) * f
HistoryRad[SampleIdx] = float4(NewRad,1.0f);

The first thing i'd try is using 32 bit image.
Or ensure all math is done using fp16.
Eventually, after AccumulateFrames becomes large and no more visible improvement is expected, stop or switch to using exponential average.

@JoeJ Yes, my buffer is RGBA16F, I have switched it to RGBA32 and it looks fine. Although I use 32F, I still clamp at [0, FP16Max]. It seems that this problem is not a calculation problem but caused by the storage precision?

iGrfx said:
It seems that this problem is not a calculation problem but caused by the storage precision?

I'd call that precision related numerical drift, but not sure if that's a valid description.
However, even if the math is right, precision is always limited. And accumulation causes small errors summing up to noticeable errors after many iterations.
I guess the loop causes some rounding to smaller numbers behavior causing the darkening, but not sure if that's due to storage, or conversion between fp16 and fp32.

I lack experience with fp16, but i guess it should work with that good enough as well. Let us know what happens in case you port the whole code to fp16, not just the storage.

iGrfx said:
I still clamp at [0, FP16Max]

That's probably unrelated to the issue. I guess radiance rarely gets higher than the max value in practice.
Math itself looks right and the first two images also proof that.

This topic is closed to new replies.

Advertisement