TSL PostProcessing: Use texture uniform for the colorNode of an output pass

I’m trying to create a PostProcessing setup that can handle switching input scenes easily.

With EffectComposer, we could create a RenderPass for each scene, add it to the array of passes, and just toggle renderPass.enabled whenever we wanted to switch scene.

With TSL, it seems we need to create a single NodeMaterial for the quad that gets rendered to the screen as the last step and I don’t want to create a new material, or recompile the same material each time I want to change the input scene pass.

So I’d like to create a uniform for the scene pass texture that I can update whenever I want to switch scenes.

I’ve tried a bunch of approaches, but none seem to work.

Here is the gist of what I’m trying to do:

const postProcessing = new PostProcessing(renderer)

const scene1pass = pass(scene1, scene1.camera)
const scene2pass = pass(scene2, scene2.camera)

const activeSceneTexture = texture(scene1pass.getTextureNode())

// other passes in the chain would be here
const outputPass = renderOutput(activeSceneTexture)

postProcessing.outputNode = outputPass

// then later:
activeSceneTexture.value = scene2pass.getTexture('output')

This will update the uniform but show an empty screen (no data), but if I switch back to the first scene pass like activeSceneTexture.value = scene1pass.getTexture('output'), the previous scene appears again, so I must be close, I’m just missing something.

Does anyone know how to do this? Or if there’s a better way to achieve what I want, I’m all ears!

Any chances to share an editable live example that shows what you are doing?

In the meanwhile, you can configure different pass chains that change over time like in webgpu_postprocessing_ssr. In the demo, the effect chain changes if you click on the enabled checkbox.

BTW: You only need renderOutput() if you set postProcessing.outputColorTransform to `false`. I don’t see you are doing this in your code.

Here you go @Mugen87 three.js dev template - module - JSFiddle - Code Playground

That SSR demo does change the postprocessing chain yes, but it seems to rebuild the material each time, which causes lag, which of course you wouldn’t want when switching scenes. I don’t need to rebuild the material, just switch out which scene is being used as the input for the postprocessing chain, which I thought I’d be able to do via a uniform.

I was using renderOutput() because I’ll be making use of the FXAA pass, I was just omitting it from my example code.

Unfortunately, this code does not work. A pass is a node itself and when it is not used in a material, its internals don’t get updated. So you have to assign the pass node that you want to render into the post processing stack.

When switching nodes of the same type, the shader should not be recompiled.

There’s a TSL_PostProcessing.txt file in my githib link that might help you.

I’ve tried a few different ways of doing what you suggested but it still causes recompilation. And the SSR example recompiles too. Perhaps it’s a bug?

See the updated fiddle: three.js dev template - module - JSFiddle - Code Playground

The recompilation happens in WebGPU and WebGL mode:

WebGL:

WebGPU:

This is no recompilation but just the rebuild of the material. It’s important that there are no calls of gl.compileShader() in WebGL or no new render pipelines in WebGPU.

I understand there is still an overhead of the node rebuild but that is inevitable when working with a node based system. How often are you planning to switch between different render passes in your app?

It really depends. If you can freely navigate between scenes in an app, the user can switch scenes as much as they want.

I suppose it might work if you create a separate NodeMaterial for each scene that contains all the post effects you’d like, even if they are the same for every scene, then you could just switch out the material.

However, if at some point you’d like to do an animated transition to another scene, you’d have to build another material once you’ve chosen the two scenes to navigate between.

Could you organize the transitions like in below demo?

It works since TransitionNode uses both passes in its TSL setup.

I could, but I would have to create and precompile materials for every possible transition route within the app, which is far from ideal.

I managed to hack together a working version by using a switch statement for the scene textures and manipulating the updateBeforeType prop of the PassNode: three.js dev template - module - JSFiddle - Code Playground