three.js icon indicating copy to clipboard operation
three.js copied to clipboard

some optimizations for postprocessing in webxr

Open cabanier opened this issue 1 month ago • 4 comments

@mrdoob the postprocessing step wasn't using anti-aliasing. I fixed this by passing this antialias attribute to the rendertargets. The rendertargets were resolving depth which wasn't used. I turned that off.

I see that the code is rendering to a lot of rendertargets. Is that expected? In order I see:

Surface 0    | 3360x1760 | color 32bit, depth 24bit, stencil 0 bit, MSAA 4 -> clear from browser code
Surface 1    | 4096x4096 | color 32bit, depth 24bit, stencil 0 bit, MSAA 1 -> 4k x 4k shadowmap?
Surface 2    | 3360x1760 | color 64bit, depth 24bit, stencil 0 bit, MSAA 4
Surface 3    | 1680x880  | color 64bit, depth 24bit, stencil 0 bit, MSAA 4
Surface 4    | 1680x880  | color 64bit, depth 24bit, stencil 0 bit, MSAA 4
Surface 5    | 1680x880  | color 64bit, depth 24bit, stencil 0 bit, MSAA 4
Surface 6    | 840 x440  | color 64bit, depth 24bit, stencil 0 bit, MSAA 4
Surface 7    | 840 x440  | color 64bit, depth 24bit, stencil 0 bit, MSAA 4
Surface 8    | 420 x220  | color 64bit, depth 24bit, stencil 0 bit, MSAA 4
Surface 9    | 420 x220  | color 64bit, depth 24bit, stencil 0 bit, MSAA 4
Surface 10   | 210 x110  | color 64bit, depth 24bit, stencil 0 bit, MSAA 4
Surface 11   | 210 x110  | color 64bit, depth 24bit, stencil 0 bit, MSAA 4
Surface 12   | 105 x55   | color 64bit, depth 24bit, stencil 0 bit, MSAA 4
Surface 13   | 105 x55   | color 64bit, depth 24bit, stencil 0 bit, MSAA 4
Surface 14   | 1680x880  | color 64bit, depth 24bit, stencil 0 bit, MSAA 4 
Surface 15   | 3360x1760 | color 64bit, depth 24bit, stencil 0 bit, MSAA 4 -> uses expensive loadcolor
Surface 16   | 3360x1760 | color 32bit, depth 24bit, stencil 0 bit, MSAA 4 -> final blit to destination

Are all these passes needed or can we combine some? Each pass will flush color data to the main memory. Surface 15 also loads it from main memory. Is that needed or is it the same as surface 2? (If you don't know, I can debug it)

This contribution is funded by Meta

cabanier avatar Dec 09 '25 23:12 cabanier

📦 Bundle size

Full ESM build, minified and gzipped.

Before After Diff
WebGL 355.12
84.44
355.16
84.45
+44 B
+9 B
WebGPU 616.35
171.06
616.35
171.06
+0 B
+0 B
WebGPU Nodes 614.96
170.8
614.96
170.8
+0 B
+0 B

🌳 Bundle size after tree-shaking

Minimal build including a renderer, camera, empty scene, and dependencies.

Before After Diff
WebGL 487.46
119.37
487.5
119.38
+44 B
+7 B
WebGPU 687.26
186.66
687.26
186.66
+0 B
+0 B
WebGPU Nodes 637.11
173.88
637.11
173.88
+0 B
+0 B

github-actions[bot] avatar Dec 09 '25 23:12 github-actions[bot]

the postprocessing step wasn't using anti-aliasing. I fixed this by passing this antialias attribute to the rendertargets.

It would be cleaner to do something like this:

render( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {
    
    if ( this._currentSamples !== readBuffer.samples ) {
        this._currentSamples = readBuffer.samples;
        this._updateRenderTargetSamples( readBuffer.samples );
    }
    // ...
}

But I'm not sure antialiasing is really needed for the bloom. Can you revert that change for now?

The resolveDepthBuffer: false change is good 👍

Are all these passes needed or can we combine some?

I think they're needed. That's how the algorithm works.

Surface 15 also loads it from main memory. Is that needed or is it the same as surface 2? (If you don't know, I can debug it)

I don't know actually, would be great if you can take a look 🙏

mrdoob avatar Dec 10 '25 00:12 mrdoob

the postprocessing step wasn't using anti-aliasing. I fixed this by passing this antialias attribute to the rendertargets.

It would be cleaner to do something like this:

render( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {
    
    if ( this._currentSamples !== readBuffer.samples ) {
        this._currentSamples = readBuffer.samples;
        this._updateRenderTargetSamples( readBuffer.samples );
    }
    // ...
}

But I'm not sure antialiasing is really needed for the bloom. Can you revert that change for now?

Sure, but I think it should be added. The graphics looks very jaggy without it.

Surface 15 also loads it from main memory. Is that needed or is it the same as surface 2? (If you don't know, I can debug it)

I don't know actually, would be great if you can take a look 🙏

OK, I'll take a look.

cabanier avatar Dec 10 '25 06:12 cabanier

But I'm not sure antialiasing is really needed for the bloom. Can you revert that change for now?

Sure, but I think it should be added. The graphics looks very jaggy without it.

I updated the code in https://github.com/cabanier/three.js/commit/1d66efc9ccfff396d75f9b77e4d7dfa075e81ff7 so MSAA is applied to the post processing passes. In a follow up commit I'll remove it

Surface 15 also loads it from main memory. Is that needed or is it the same as surface 2? (If you don't know, I can debug it)

I don't know actually, would be great if you can take a look 🙏

OK, I'll take a look.

I inspected the code and the passes are reading from the buffer that is then used to composite the final images. It seems that this is by design.

cabanier avatar Dec 10 '25 08:12 cabanier

Hey Rik, I've tried to clean this up but I'm too confused... You tried to change too many things at once and I don't know what the side effects are. I was going to try to add this to r182 but I'm afraid I'll have to leave this for next release.

mrdoob avatar Dec 10 '25 15:12 mrdoob

Hey Rik, I've tried to clean this up but I'm too confused... You tried to change too many things at once and I don't know what the side effects are. I was going to try to add this to r182 but I'm afraid I'll have to leave this for next release.

No worries. The changes to WebGLOutput.js were needed to avoid jaggies but we can add that later.

cabanier avatar Dec 10 '25 15:12 cabanier

@mrdoob do you want me to add another PR for the MSAA? It seems this one will just discard depth.

cabanier avatar Dec 10 '25 16:12 cabanier