Skip to content

Commit

Permalink
Examples: Introduce OutputPass. (#26102)
Browse files Browse the repository at this point in the history
* Examples: Introduce `OutputPass`.

* Examples: Simplify selective bloom demo.

* Examples: Improve GUI in bloom demos.
  • Loading branch information
Mugen87 authored May 21, 2023
1 parent 0fb7814 commit 6c7ff7a
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 94 deletions.
72 changes: 72 additions & 0 deletions examples/jsm/postprocessing/OutputPass.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import {
ShaderMaterial,
UniformsUtils,
NoToneMapping,
LinearToneMapping,
ReinhardToneMapping,
CineonToneMapping,
ACESFilmicToneMapping
} from 'three';
import { Pass, FullScreenQuad } from './Pass.js';
import { OutputShader } from '../shaders/OutputShader.js';

class OutputPass extends Pass {

constructor( toneMapping = NoToneMapping, toneMappingExposure = 1 ) {

super();

this.toneMapping = toneMapping;
this.toneMappingExposure = toneMappingExposure;

//

const shader = OutputShader;

this.uniforms = UniformsUtils.clone( shader.uniforms );

this.material = new ShaderMaterial( {
uniforms: this.uniforms,
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader
} );

if ( toneMapping === LinearToneMapping ) this.material.defines.LINEAR_TONE_MAPPING = '';
else if ( toneMapping === ReinhardToneMapping ) this.material.defines.REINHARD_TONE_MAPPING = '';
else if ( toneMapping === CineonToneMapping ) this.material.defines.CINEON_TONE_MAPPING = '';
else if ( toneMapping === ACESFilmicToneMapping ) this.material.defines.ACES_FILMIC_TONE_MAPPING = '';

this.fsQuad = new FullScreenQuad( this.material );

}

render( renderer, writeBuffer, readBuffer/*, deltaTime, maskActive */ ) {

this.uniforms[ 'tDiffuse' ].value = readBuffer.texture;
this.uniforms[ 'toneMappingExposure' ].value = this.toneMappingExposure;

if ( this.renderToScreen === true ) {

renderer.setRenderTarget( null );
this.fsQuad.render( renderer );

} else {

renderer.setRenderTarget( writeBuffer );
if ( this.clear ) renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
this.fsQuad.render( renderer );

}

}

dispose() {

this.material.dispose();
this.fsQuad.dispose();

}

}

export { OutputPass };
61 changes: 61 additions & 0 deletions examples/jsm/shaders/OutputShader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
const OutputShader = {

uniforms: {

'tDiffuse': { value: null },
'toneMappingExposure': { value: 1 }

},

vertexShader: /* glsl */`
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}`,

fragmentShader: /* glsl */`
uniform sampler2D tDiffuse;
#include <tonemapping_pars_fragment>
varying vec2 vUv;
void main() {
gl_FragColor = texture2D( tDiffuse, vUv );
// tone mapping
#ifdef LINEAR_TONE_MAPPING
gl_FragColor.rgb = LinearToneMapping( gl_FragColor.rgb );
#elif defined( REINHARD_TONE_MAPPING )
gl_FragColor.rgb = ReinhardToneMapping( gl_FragColor.rgb );
#elif defined( CINEON_TONE_MAPPING )
gl_FragColor.rgb = OptimizedCineonToneMapping( gl_FragColor.rgb );
#elif defined( ACES_FILMIC_TONE_MAPPING )
gl_FragColor.rgb = ACESFilmicToneMapping( gl_FragColor.rgb );
#endif
// color space
gl_FragColor = LinearTosRGB( gl_FragColor );
}`

};

export { OutputShader };
Binary file modified examples/screenshots/webgl_postprocessing_unreal_bloom.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 21 additions & 19 deletions examples/webgl_postprocessing_unreal_bloom.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,16 @@
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
import { GammaCorrectionShader } from 'three/addons/shaders/GammaCorrectionShader.js';
import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';

let camera, stats;
let composer, renderer, mixer, clock;

const params = {
exposure: 1,
bloomStrength: 1.5,
bloomThreshold: 0,
bloomRadius: 0
threshold: 0,
strength: 1.5,
radius: 0,
exposure: 1
};

init();
Expand All @@ -76,7 +75,6 @@
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.toneMapping = THREE.ReinhardToneMapping;
container.appendChild( renderer.domElement );

const scene = new THREE.Scene();
Expand All @@ -98,11 +96,11 @@
const renderScene = new RenderPass( scene, camera );

const bloomPass = new UnrealBloomPass( new THREE.Vector2( window.innerWidth, window.innerHeight ), 1.5, 0.4, 0.85 );
bloomPass.threshold = params.bloomThreshold;
bloomPass.strength = params.bloomStrength;
bloomPass.radius = params.bloomRadius;
bloomPass.threshold = params.threshold;
bloomPass.strength = params.strength;
bloomPass.radius = params.radius;

const outputPass = new ShaderPass( GammaCorrectionShader );
const outputPass = new OutputPass( THREE.ReinhardToneMapping );

composer = new EffectComposer( renderer );
composer.addPass( renderScene );
Expand All @@ -125,30 +123,34 @@

const gui = new GUI();

gui.add( params, 'exposure', 0.1, 2 ).onChange( function ( value ) {
const bloomFolder = gui.addFolder( 'bloom' );

renderer.toneMappingExposure = Math.pow( value, 4.0 );

} );

gui.add( params, 'bloomThreshold', 0.0, 1.0 ).onChange( function ( value ) {
bloomFolder.add( params, 'threshold', 0.0, 1.0 ).onChange( function ( value ) {

bloomPass.threshold = Number( value );

} );

gui.add( params, 'bloomStrength', 0.0, 3.0 ).onChange( function ( value ) {
bloomFolder.add( params, 'strength', 0.0, 3.0 ).onChange( function ( value ) {

bloomPass.strength = Number( value );

} );

gui.add( params, 'bloomRadius', 0.0, 1.0 ).step( 0.01 ).onChange( function ( value ) {
gui.add( params, 'radius', 0.0, 1.0 ).step( 0.01 ).onChange( function ( value ) {

bloomPass.radius = Number( value );

} );

const toneMappingFolder = gui.addFolder( 'tone mapping' );

toneMappingFolder.add( params, 'exposure', 0.1, 2 ).onChange( function ( value ) {

outputPass.toneMappingExposure = Math.pow( value, 4.0 );

} );

window.addEventListener( 'resize', onWindowResize );

}
Expand Down
100 changes: 25 additions & 75 deletions examples/webgl_postprocessing_unreal_bloom_selective.html
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,18 @@
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
import { GammaCorrectionShader } from 'three/addons/shaders/GammaCorrectionShader.js';
import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';

const ENTIRE_SCENE = 0, BLOOM_SCENE = 1;
const BLOOM_SCENE = 1;

const bloomLayer = new THREE.Layers();
bloomLayer.set( BLOOM_SCENE );

const params = {
exposure: 1,
bloomStrength: 5,
bloomThreshold: 0,
bloomRadius: 0,
scene: 'Scene with Glow'
threshold: 0,
strength: 3,
radius: 0.5,
exposure: 1
};

const darkMaterial = new THREE.MeshBasicMaterial( { color: 'black' } );
Expand All @@ -86,7 +85,6 @@
const renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.toneMapping = THREE.ReinhardToneMapping;
document.body.appendChild( renderer.domElement );

const scene = new THREE.Scene();
Expand All @@ -106,9 +104,9 @@
const renderScene = new RenderPass( scene, camera );

const bloomPass = new UnrealBloomPass( new THREE.Vector2( window.innerWidth, window.innerHeight ), 1.5, 0.4, 0.85 );
bloomPass.threshold = params.bloomThreshold;
bloomPass.strength = params.bloomStrength;
bloomPass.radius = params.bloomRadius;
bloomPass.threshold = params.threshold;
bloomPass.strength = params.strength;
bloomPass.radius = params.radius;

const bloomComposer = new EffectComposer( renderer );
bloomComposer.renderToScreen = false;
Expand All @@ -128,7 +126,7 @@
);
mixPass.needsSwap = true;

const outputPass = new ShaderPass( GammaCorrectionShader );
const outputPass = new OutputPass( THREE.ReinhardToneMapping );

const finalComposer = new EffectComposer( renderer );
finalComposer.addPass( renderScene );
Expand All @@ -143,52 +141,34 @@

const gui = new GUI();

gui.add( params, 'scene', [ 'Scene with Glow', 'Glow only', 'Scene only' ] ).onChange( function ( value ) {
const bloomFolder = gui.addFolder( 'bloom' );

switch ( value ) {

case 'Scene with Glow':
bloomComposer.renderToScreen = false;
break;
case 'Glow only':
bloomComposer.renderToScreen = true;
break;
case 'Scene only':
// nothing to do
break;

}
bloomFolder.add( params, 'threshold', 0.0, 1.0 ).onChange( function ( value ) {

bloomPass.threshold = Number( value );
render();

} );

const folder = gui.addFolder( 'Bloom Parameters' );
bloomFolder.add( params, 'strength', 0.0, 10.0 ).onChange( function ( value ) {

folder.add( params, 'exposure', 0.1, 2 ).onChange( function ( value ) {

renderer.toneMappingExposure = Math.pow( value, 4.0 );
bloomPass.strength = Number( value );
render();

} );

folder.add( params, 'bloomThreshold', 0.0, 1.0 ).onChange( function ( value ) {
bloomFolder.add( params, 'radius', 0.0, 1.0 ).step( 0.01 ).onChange( function ( value ) {

bloomPass.threshold = Number( value );
bloomPass.radius = Number( value );
render();

} );

folder.add( params, 'bloomStrength', 0.0, 10.0 ).onChange( function ( value ) {

bloomPass.strength = Number( value );
render();

} );
const toneMappingFolder = gui.addFolder( 'tone mapping' );

folder.add( params, 'bloomRadius', 0.0, 1.0 ).step( 0.01 ).onChange( function ( value ) {
toneMappingFolder.add( params, 'exposure', 0.1, 2 ).onChange( function ( value ) {

bloomPass.radius = Number( value );
outputPass.toneMappingExposure = Math.pow( value, 4.0 );
render();

} );
Expand Down Expand Up @@ -270,42 +250,12 @@

function render() {

switch ( params.scene ) {

case 'Scene only':
renderer.render( scene, camera );
break;
case 'Glow only':
renderBloom( false );
break;
case 'Scene with Glow':
default:
// render scene with bloom
renderBloom( true );

// render the entire scene, then render bloom scene on top
finalComposer.render();
break;

}

}
scene.traverse( darkenNonBloomed );
bloomComposer.render();
scene.traverse( restoreMaterial );

function renderBloom( mask ) {

if ( mask === true ) {

scene.traverse( darkenNonBloomed );
bloomComposer.render();
scene.traverse( restoreMaterial );

} else {

camera.layers.set( BLOOM_SCENE );
bloomComposer.render();
camera.layers.set( ENTIRE_SCENE );

}
// render the entire scene, then render bloom scene on top
finalComposer.render();

}

Expand Down

0 comments on commit 6c7ff7a

Please sign in to comment.