How to combine outline effect with tone mapping

Hi there,

I’m trying to combine the tone mapping effects from this example with the outline effects from this example

The outline effect uses an effect composer and then a call to composer.render();in the animate function. Whereas the tone mapping effect seems to be applied directly to the renderer using renderer.toneMapping = someToneMappingOption; and then a call to renderer.render( scene, camera );

So my question is: is there a way to combine these two effects given that they use two different methods of drawing the scene?

Thanks

The outline example renders the scene via RenderPass. This is the so called beauty pass. It internally uses the same renderer.render( scene, camera ); call you normally use in your three.js app. The post-processing effect is then applied with a subsequent pass. Hence, it should be no problem to combine both approaches.

However, there might be post-processing setups where you can use the inline tone mapping and gamma correction features of the renderer. Meaning you have to apply tone mapping and gamma correction as a post-processing pass at the end of your pass chain. That’s because certain passes expect the color values in linear color space, not tone mapped. In this case, you might want to use an approach similar to webgl_shaders_tonemapping and apply tone mapping via post-processing.

Thanks for the reply @Mugen87 ,

The post-processing effect is then applied with a subsequent pass. Hence, it should be no problem to combine both approaches

How would I go about combining?

Here is how I’ve tried to do my post processing setup:

setPostProcessing() {
    //Tone mapping:
    this.renderer.toneMapping = THREE.ACESFilmicToneMapping;
    this.renderer.toneMappingExposure = 0.9;
    this.renderer.toneMappingWhitePoint = 1.0;

    //Render pass:
    this.composer = new EffectComposer(this.renderer);
    let renderPass = new RenderPass(this.scene, this.camera);    
    this.composer.addPass(renderPass);     

    //Outline effect:
    this.outlinePass = new OutlinePass(new THREE.Vector2(this.playerCanvas.clientWidth, this.playerCanvas.clientHeight), this.scene, this.camera);
    let toneMappingPass = new AdaptiveToneMappingPass(true, 256);
    this.composer.addPass(this.outlinePass);
    this.composer.addPass(toneMappingPass);       
}

then in my animate function If I call this.renderer.render( this.scene, this.camera ); here is what I see (tone mapping working fine, but no selection outline):

If I call this.composer.render(); here is what I see: (no tone mapping but outline selection working fine):

I would like to avoid the manual tone mapping approach if possible - looks a bit hard for me!

Ah wait, I made a mistake. If you configure tone mapping like that, it will apply globally to all calls of renderer.render() (at least for all built-in materials). This is not necessarily something you want in this post-processing setup.

I’m afraid you have to use a tone mapping and gamma correction pass for this scenario.

Ah… that’s unfortunate. Any chance you can point me to an example that implements something similar to the ACES Filmic Tone mapping effect?

I’m not aware of an example but you can implement your own custom pass based on the exiting GLSL code:

The basic structure of the code is not that complicated. You only have to apply for all fragments the ACESFilmicToneMapping() function.

Thanks again… I appreciate you steering me in the right direction. But I have to admit I’m a bit useless when it comes to shader stuff… How would I go about turning the code you’ve linked into a ShaderPass that I can then use with my effect composer?

I’ve realized right now that there is already ACESFilmicToneMappingShader. You can use this file to create an instance of ShaderPass and then add it to your post-processing chain.

Thanks for that, I’m still getting issues with this however:

I initialise my post processing like this:

import { ACESFilmicToneMappingShader } from "./ACESFilmicToneMappingShader";

setPostProcessing(){ 

    //Render pass:
    this.composer = new EffectComposer(this.renderer);
    let renderPass = new RenderPass(this.scene, this.camera);    
    this.composer.addPass(renderPass);     

    //Outline effect:
    this.outlinePass = new OutlinePass(new THREE.Vector2(this.playerCanvas.clientWidth, this.playerCanvas.clientHeight), this.scene, this.camera);

    this.composer.addPass(this.outlinePass);

    //Tone mapping
    let tmPass = new ShaderPass(ACESFilmicToneMappingShader);
    this.composer.addPass(tmPass);      
}

where my ACESFilmicToneMappingShader.ts is just a copy from the file you linked

Now I am seeing nothing in the 3d view and an error in the console:

THREE.WebGLProgram: shader error: 0 35715 false gl.getProgramInfoLog invalid shaders THREE.WebGLShader: gl.getShaderInfoLog() fragment
ERROR: 0:116: ‘ACESFilmicToneMapping’ : function already has a body

Can you please edit ACESFilmicToneMappingShader and remove RRTAndODTFit() as well as ACESFilmicToneMapping()? This could be a bug in the GLSL code.