WebGPURenderer - PostProcessing: Can't swap beteween results from 2 differnet MRT passes

I have a project that requires a set of buffers for various postprocessing effects. However, a single MRT pass can only accomodate so many buffers by default, after which, adding another one throws an error.

ERROR: Total color attachment bytes per sample (40) exceeds maximum (32) with formats

To get around this, I decided to use 2 different MRT passes.

I am having an issue where I cant seem to swap the postprocessing.outputNode between texture nodes from the 2 different MRT passes. I have made a simple example to illustrate.

As you can see, the output should swap from diffuse to normal textures within the setInterval. However, this does not happen.

If I make it so that both diffuse and normal outputs are from the same MRT pass, it works as expected.


const diffuseNode = scenePass.getTextureNode(“diffuse”)
const normalNode = scenePass2.getTextureNode(“normal”) // Does not work: using scenePass2
// const normalNode = scenePass.getTextureNode(“normal”) // Works: using scenePass

let f = true
setInterval(() => {
  console.log(f)
  post.outputNode = f ? diffuseNode  : normalNode
  post.needsUpdate = true
  f = !f
}, 1000)

Am i using MRT pass correctly in this situation?

Um, this is the first time we encounter such a use case with mrt(). It’s good possible that the second scene pass is not properly executed if you are not doing something with the “default” output.

I would like to understand first why you hit the attachment size restriction. Do you think you can reproduce your setup in an updated fiddle so the error pops up?

We are working at packing strategies with MRT so it’s possible to decrease the overall attachment size which means you won’t need a second render pass.

E.g. when you use directionToColor() to pack your half float normals into a color, you can do the following to switch the normal attachment texture type from RGBA16 to RGBA8:

const normalTexture = scenePass.getTexture( ‘normal’ );
normalTexture.type = THREE.UnsignedByteType;

You won’t see a quality difference but save 50% memory and bandwidth just for this attachment.

2 Likes

Here is a reproduction of the error. I am already using the UnsignedByteType for all the texture attachments. As soon as i use the velocity pass, the error is thrown

I have also tried packing the roughness and metalness into the alpha channels of the other passes but this leads to unwanted alpha blending in the other passes for transparent: true obejcts as demonstrated by this minimal example:

For context, the app uses GTAO, SSR and SSGI all at once. I am trying to integrate TRAA, thus requiring the velocity pass.

I understand that using all the passes at once is a performance killer. However, that is simply what the project calls for.

I can work around this issue by setting requiredLimits.maxColorAttachmentBytesPerSample higher in the renderer params but this is not scalable to all hardware.

Side-note: Using GTAO and SSGI does not make sense since you get AO via SSGI. SSGI can be considered in general as an enhancement of AO.

The double pass approach is definitely something you want to avoid. It would probably be best to open an issue at Github and request more API for packing data in MRT configurations. E.g the diffuse color is a good candidate for more aggressive packing, metal/rough/velocity can maybe also be combined.

Got it. I will make an issue on GH for more API for packing data.

Should I also open the main question in this thread as a bug? Swaping passes from different MRT instnaces doesnt update?