pmndrs / postprocessing

A post processing library for three.js.
zlib License
2.36k stars 213 forks source link

Absolutely incredible work on v5 - examples of chaining shaders, new comparative performance benchmarks? #96

Closed gigablox closed 5 years ago

gigablox commented 6 years ago

I was reviewing your changes for the past couple hours, seeing where all that work went into for the v5 PR and https://github.com/vanruesc/postprocessing/issues/82 milestone. It's incredible how much time and thought you put into this.

Correct me if I'm wrong but this combines passes much more efficiently than the ThreeJS EffectPass class because you are combining shaders and running a single pass rather then multiple passes over each?

I'd love to see some examples of chaining shaders together, I can even submit a PR for that to add to your examples for FPS experimentation.

vanruesc commented 6 years ago

Thank you!

this combines passes much more efficiently than the ThreeJS EffectPass class because you are combining shaders and running a single pass rather then multiple passes over each?

Yes, well, the ThreeJS examples don't contain an EffectPass. That's a new addition in this library. But apart from that you're spot on.

The fundamental concept of passes is still there, too, and it actually hasn't changed at all. Effects, however, offer the possibility to programmatically opt into shader merging via the EffectPass. In my opinion, it's important that the user knows what's happening and why it's happening. The concept of effects supports that quite nicely. Another feasible option would have been to sneakily analyze and merge all kinds of passes behind the back of the user. But I discarded that idea early on.

I'd love to see some examples of chaining shaders together

Do you mean really long effect chains? All the demos already use effect chaining. For example, the color correction demo chains the SMAAEffect, BrightnessContrastEffect, GammaCorrectionEffect and HueSaturationEffect. You could also plug in a BloomEffect, GodRaysEffect, VignetteEffect, and lots of other effects and you'd still have a single fullscreen render operation. Well, to be fair, the BloomEffect and GodRaysEffect render some additional textures off-screen, but that can't be avoided.

The only effects that cannot be merged with each other are BokehEffect, RealisticBokehEffect, ChromaticAberrationEffect, GlitchEffect, PixelationEffect, ShockWaveEffect and SMAAEffect. To use those effects together, you'd have to use multiple EffectPass instances. But the user doesn't have to worry about that too much; if something doesn't work, the EffectPass will complain.

I can even submit a PR for that to add to your examples for FPS experimentation.

That would be nice. If you need assistance, I'm here!

vanruesc commented 6 years ago

For a performance comparison we could do something like this:

const effects = [
    new SomeEffect(),
    ...
    new OtherEffect()
];

// Merge all effects into one pass.
const effectPass = new EffectPass(camera, ...effects);
effectPass.renderToScreen = true;

// Create an individual pass for each effect.
const passes = effects.map((effect) => new EffectPass(camera, effect));
passes[passes.length - 1].renderToScreen = true;

// Add all passes.
for(const pass of passes) {

    pass.enabled = false;
    composer.addPass(pass);

}

composer.addPass(effectPass);

Then we can toggle between the traditional approach and the new one by enabling/disabling the passes. The FPS could be calculated manually and shown in the top-right menu.

vanruesc commented 5 years ago

I've added a performance demo that uses 14 mergeable effects.

Test system:

CPU: AMD Ryzen 1600x GPU: NVIDIA GTX 1060 6Gb RAM: G.Skill 16Gb 3200Mhz Mainboard: Asus Prime B450 Plus Resolution: 1920x1080 Firefox 66.0.3

Results

Effect Merging FPS
enabled ~345
disabled ~260