three.js: Temporal Anti Aliasing (TAA) rounding errors over accumulation
Description of the problem
I’ve discovered there is an implementation of MSAA accumulating over several frames, which is a nice thing. The example to this (webgl_postprocessing_taa) shows the beauty of this.
When i applied it to an application i work on, the surpression of the accumulated rounding errors didn’t seem to work, when i use MeshPhongMaterial with it. That is because it is not implemented in the accumulating version of TAARenderPass. So i decided to integrate it myself, but unluckily there is still an issue when the accumulation is going on. The rendered frames go darker inbetween and recover light when the accumulateIndex reaches 32. Please check out my version here.
The inner loop of THREE.TAARenderPass.render in my version is
var baseSampleWeight = 1.0 / jitterOffsets.length;
var roundingRange = 1 / 32;
if( this.accumulateIndex >= 0 && this.accumulateIndex < jitterOffsets.length ) {
this.copyUniforms[ "opacity" ].value = sampleWeight;
this.copyUniforms[ "tDiffuse" ].value = writeBuffer.texture;
// render the scene multiple times, each slightly jitter offset from the last and accumulate the results.
var numSamplesPerFrame = Math.pow( 2, this.sampleLevel );
for ( var i = 0; i < numSamplesPerFrame; i ++ ) {
var j = this.accumulateIndex;
var jitterOffset = jitterOffsets[j];
if ( this.camera.setViewOffset ) {
this.camera.setViewOffset( readBuffer.width, readBuffer.height,
jitterOffset[ 0 ] * 0.0625*1.25, jitterOffset[ 1 ] * 0.0625*1.25, // 0.0625 = 1 / 16
readBuffer.width, readBuffer.height );
}
var sampleWeight = baseSampleWeight;
if( this.unbiased ) {
// also apply unbiased accumulation here
var uniformCenteredDistribution = ( -0.5 + ( this.accumulateIndex + 0.5 ) / jitterOffsets.length );
sampleWeight += roundingRange * uniformCenteredDistribution;
}
this.copyUniforms[ "opacity" ].value = sampleWeight;
renderer.render( this.scene, this.camera, writeBuffer, true );
renderer.render( this.scene2, this.camera2, this.sampleRenderTarget, ( this.accumulateIndex === 0 ) );
this.accumulateIndex ++;
if( this.accumulateIndex >= jitterOffsets.length ) break;
}
if ( this.camera.clearViewOffset ) this.camera.clearViewOffset();
}
By the way, can we further surpress the rounding error artifacts? The sphere looks somewhat quantized in the darker areas. Greetings, Thomas
Three.js version
- Dev
- r77 as of 2016-05-30
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Comments: 19 (15 by maintainers)
I reassembled the TAARenderPass to work around the biasing problem. It now copies a new sample with
1/(this.accumulateIndex+1)
and1-1/(this.accumulateIndex+1)
of the old image to thewriteBuffer
, saving it for the next pass.ClearColor
fully transparent and the alpha for the renderer turned onsetAccumulation( doAccumulation )
to setthis.accumulate
and resetthis.accumulationIndex
resetAccumulationIndex()
webgl_processing_taa.html
to include an OrbitController, instead of a stop-and-go rotation of the cube and also added a Phong shaded SphereHave a look here: Example
Let me know what you think, this can be turned into a pull request then
Rounding errors should not happen anymore because half float render targets are now the default in
EffectComposer
and built-in passes.Setting blending mode to NormalBlending did the deal for me: now the clearColor and clearAlpha given to the renderer is used.
The refreshed example can be visited here.