Advertisement
Guest User

Untitled

a guest
Aug 31st, 2019
1,543
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /**
  2.  * @author spidersharma / http://eduperiment.com/
  3.  *
  4.  * Inspired from Unreal Engine
  5.  * https://docs.unrealengine.com/latest/INT/Engine/Rendering/PostProcessEffects/Bloom/
  6.  */
  7.  
  8. import {
  9.     AdditiveBlending,
  10.     Color,
  11.     LinearFilter,
  12.     MeshBasicMaterial,
  13.     RGBAFormat,
  14.     ShaderMaterial,
  15.     UniformsUtils,
  16.     Vector2,
  17.     Vector3,
  18.     WebGLRenderTarget
  19. } from 'three';
  20. import { Pass } from 'three/examples/jsm/postprocessing/Pass.js';
  21. import { CopyShader } from 'three/examples/jsm/shaders/CopyShader.js';
  22. import { LuminosityHighPassShader } from 'three/examples/jsm/shaders/LuminosityHighPassShader.js';
  23.  
  24. var UnrealBloomPass = function ( resolution, strength, radius, threshold, selectedObjects, scene, camera ) {
  25.  
  26.     Pass.call( this );
  27.  
  28.     this.strength = ( strength !== undefined ) ? strength : 1;
  29.     this.radius = radius;
  30.     this.threshold = threshold;
  31.     this.resolution = ( resolution !== undefined ) ? new Vector2( resolution.x, resolution.y ) : new Vector2( 256, 256 );
  32.  
  33.     this.scene = scene;
  34.     this.camera = camera;
  35.     this.selectedObjects = selectedObjects || [];
  36.  
  37.     // create color only once here, reuse it later inside the render function
  38.     this.clearColor = new Color( 0, 0, 0 );
  39.  
  40.     // render targets
  41.     var pars = { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat };
  42.     this.renderTargetsHorizontal = [];
  43.     this.renderTargetsVertical = [];
  44.     this.nMips = 5;
  45.     var resX = Math.round( this.resolution.x / 2 );
  46.     var resY = Math.round( this.resolution.y / 2 );
  47.  
  48.     this.renderTargetSelectedObjects = new WebGLRenderTarget( resX, resY, pars );
  49.     this.renderTargetSelectedObjects.texture.name = "UnrealBloomPass.selectedObjects";
  50.     this.renderTargetSelectedObjects.texture.generateMipmaps = false;
  51.  
  52.     this.renderTargetBright = new WebGLRenderTarget( resX, resY, pars );
  53.     this.renderTargetBright.texture.name = "UnrealBloomPass.bright";
  54.     this.renderTargetBright.texture.generateMipmaps = false;
  55.  
  56.     for ( var i = 0; i < this.nMips; i ++ ) {
  57.  
  58.         var renderTargetHorizonal = new WebGLRenderTarget( resX, resY, pars );
  59.  
  60.         renderTargetHorizonal.texture.name = "UnrealBloomPass.h" + i;
  61.         renderTargetHorizonal.texture.generateMipmaps = false;
  62.  
  63.         this.renderTargetsHorizontal.push( renderTargetHorizonal );
  64.  
  65.         var renderTargetVertical = new WebGLRenderTarget( resX, resY, pars );
  66.  
  67.         renderTargetVertical.texture.name = "UnrealBloomPass.v" + i;
  68.         renderTargetVertical.texture.generateMipmaps = false;
  69.  
  70.         this.renderTargetsVertical.push( renderTargetVertical );
  71.  
  72.         resX = Math.round( resX / 2 );
  73.  
  74.         resY = Math.round( resY / 2 );
  75.  
  76.     }
  77.  
  78.     // luminosity high pass material
  79.  
  80.     if ( LuminosityHighPassShader === undefined )
  81.         console.error( "UnrealBloomPass relies on LuminosityHighPassShader" );
  82.  
  83.     var highPassShader = LuminosityHighPassShader;
  84.     this.highPassUniforms = UniformsUtils.clone( highPassShader.uniforms );
  85.  
  86.     this.highPassUniforms[ "luminosityThreshold" ].value = threshold;
  87.     this.highPassUniforms[ "smoothWidth" ].value = 0.01;
  88.  
  89.     this.materialHighPassFilter = new ShaderMaterial( {
  90.         uniforms: this.highPassUniforms,
  91.         vertexShader: highPassShader.vertexShader,
  92.         fragmentShader: highPassShader.fragmentShader,
  93.         defines: {}
  94.     } );
  95.  
  96.     // Gaussian Blur Materials
  97.     this.separableBlurMaterials = [];
  98.     var kernelSizeArray = [ 3, 5, 7, 9, 11 ];
  99.     var resX = Math.round( this.resolution.x / 2 );
  100.     var resY = Math.round( this.resolution.y / 2 );
  101.  
  102.     for ( var i = 0; i < this.nMips; i ++ ) {
  103.  
  104.         this.separableBlurMaterials.push( this.createSeperableBlurMaterial( kernelSizeArray[ i ] ) );
  105.  
  106.         this.separableBlurMaterials[ i ].uniforms[ "texSize" ].value = new Vector2( resX, resY );
  107.  
  108.         resX = Math.round( resX / 2 );
  109.  
  110.         resY = Math.round( resY / 2 );
  111.  
  112.     }
  113.  
  114.     // Composite material
  115.     this.bloomFactors = [ 1.0, 0.8, 0.6, 0.4, 0.2 ];
  116.     this.bloomTintColors = [
  117.         new Vector3( 1, 1, 1 ),
  118.         new Vector3( 1, 1, 1 ),
  119.         new Vector3( 1, 1, 1 ),
  120.         new Vector3( 1, 1, 1 ),
  121.         new Vector3( 1, 1, 1 )
  122.     ];
  123.  
  124.     this.compositeMaterial = this.createCompositeMaterial( this.nMips );
  125.  
  126.     this.blendMaterial = this.createBlendMaterial();
  127.  
  128.     // copy material
  129.     if ( CopyShader === undefined ) {
  130.  
  131.         console.error( "UnrealBloomPass relies on CopyShader" );
  132.  
  133.     }
  134.  
  135.     var copyShader = CopyShader;
  136.  
  137.     this.copyUniforms = UniformsUtils.clone( copyShader.uniforms );
  138.     this.copyUniforms[ "opacity" ].value = 1.0;
  139.  
  140.     this.materialCopy = new ShaderMaterial( {
  141.         uniforms: this.copyUniforms,
  142.         vertexShader: copyShader.vertexShader,
  143.         fragmentShader: copyShader.fragmentShader,
  144.         blending: AdditiveBlending,
  145.         depthTest: false,
  146.         depthWrite: false,
  147.         transparent: true
  148.     } );
  149.  
  150.     this.enabled = true;
  151.     this.needsSwap = false;
  152.  
  153.     this.oldClearColor = new Color();
  154.     this.oldClearAlpha = 1;
  155.  
  156.     this.basic = new MeshBasicMaterial();
  157.  
  158.     this.fsQuad = new Pass.FullScreenQuad( null );
  159.  
  160. };
  161.  
  162. UnrealBloomPass.prototype = Object.assign( Object.create( Pass.prototype ), {
  163.  
  164.     constructor: UnrealBloomPass,
  165.  
  166.     dispose: function () {
  167.  
  168.         for ( var i = 0; i < this.renderTargetsHorizontal.length; i ++ ) {
  169.  
  170.             this.renderTargetsHorizontal[ i ].dispose();
  171.  
  172.         }
  173.  
  174.         for ( var i = 0; i < this.renderTargetsVertical.length; i ++ ) {
  175.  
  176.             this.renderTargetsVertical[ i ].dispose();
  177.  
  178.         }
  179.  
  180.         this.renderTargetBright.dispose();
  181.  
  182.     },
  183.  
  184.     setSize: function ( width, height ) {
  185.  
  186.         var resX = Math.round( width / 2 );
  187.         var resY = Math.round( height / 2 );
  188.  
  189.         this.renderTargetBright.setSize( resX, resY );
  190.  
  191.         for ( var i = 0; i < this.nMips; i ++ ) {
  192.  
  193.             this.renderTargetsHorizontal[ i ].setSize( resX, resY );
  194.             this.renderTargetsVertical[ i ].setSize( resX, resY );
  195.  
  196.             this.separableBlurMaterials[ i ].uniforms[ "texSize" ].value = new Vector2( resX, resY );
  197.  
  198.             resX = Math.round( resX / 2 );
  199.             resY = Math.round( resY / 2 );
  200.  
  201.         }
  202.  
  203.     },
  204.  
  205.     render: function ( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {
  206.  
  207.         this.oldClearColor.copy( renderer.getClearColor() );
  208.         this.oldClearAlpha = renderer.getClearAlpha();
  209.         var oldAutoClear = renderer.autoClear;
  210.         renderer.autoClear = false;
  211.  
  212.         renderer.setClearColor( this.clearColor, 0 );
  213.  
  214.         if ( maskActive ) renderer.state.buffers.stencil.setTest( false );
  215.  
  216.         if ( this.renderToScreen ) {
  217.  
  218.             this.fsQuad.material = this.basic;
  219.             if( this.basic.map === null ) this.basic.map = readBuffer.texture;
  220.  
  221.             renderer.setRenderTarget( null );
  222.             renderer.clear();
  223.             this.fsQuad.render( renderer );
  224.  
  225.         }
  226.  
  227.         var applyBuffer = readBuffer;
  228.  
  229.         if ( this.selectedObjects.length > 0 ) {
  230.  
  231.             this.changeVisibilityOfNonSelectedObjects( false );
  232.  
  233.             renderer.setRenderTarget( this.renderTargetSelectedObjects );
  234.             renderer.clear();
  235.             renderer.render( this.scene, this.camera );
  236.  
  237.             applyBuffer = this.renderTargetSelectedObjects;
  238.  
  239.             this.changeVisibilityOfNonSelectedObjects( true );
  240.  
  241.         }
  242.  
  243.         // 1. Extract Bright Areas
  244.         this.highPassUniforms[ "tDiffuse" ].value = applyBuffer.texture;
  245.         this.highPassUniforms[ "luminosityThreshold" ].value = this.threshold;
  246.         this.fsQuad.material = this.materialHighPassFilter;
  247.  
  248.         renderer.setRenderTarget( this.renderTargetBright );
  249.         renderer.clear();
  250.         this.fsQuad.render( renderer );
  251.  
  252.         // 2. Blur All the mips progressively
  253.         var inputRenderTarget = this.renderTargetBright;
  254.  
  255.         for ( var i = 0; i < this.nMips; i ++ ) {
  256.  
  257.             this.fsQuad.material = this.separableBlurMaterials[ i ];
  258.  
  259.             this.separableBlurMaterials[ i ].uniforms[ "colorTexture" ].value = inputRenderTarget.texture;
  260.             this.separableBlurMaterials[ i ].uniforms[ "direction" ].value = UnrealBloomPass.BlurDirectionX;
  261.             renderer.setRenderTarget( this.renderTargetsHorizontal[ i ] );
  262.             renderer.clear();
  263.             this.fsQuad.render( renderer );
  264.  
  265.             this.separableBlurMaterials[ i ].uniforms[ "colorTexture" ].value = this.renderTargetsHorizontal[ i ].texture;
  266.             this.separableBlurMaterials[ i ].uniforms[ "direction" ].value = UnrealBloomPass.BlurDirectionY;
  267.             renderer.setRenderTarget( this.renderTargetsVertical[ i ] );
  268.             renderer.clear();
  269.             this.fsQuad.render( renderer );
  270.  
  271.             inputRenderTarget = this.renderTargetsVertical[ i ];
  272.  
  273.         }
  274.  
  275.         // Composite All the mips
  276.  
  277.         this.fsQuad.material = this.compositeMaterial;
  278.         this.compositeMaterial.uniforms[ "bloomStrength" ].value = this.strength;
  279.         this.compositeMaterial.uniforms[ "bloomRadius" ].value = this.radius;
  280.         this.compositeMaterial.uniforms[ "bloomTintColors" ].value = this.bloomTintColors;
  281.  
  282.         renderer.setRenderTarget( this.renderTargetsHorizontal[ 0 ] );
  283.         renderer.clear();
  284.         this.fsQuad.render( renderer );
  285.  
  286.         if ( this.selectedObjects.length > 0 ) {
  287.  
  288.             this.fsQuad.material = this.blendMaterial;
  289.             this.blendMaterial.uniforms[ 'baseTexture' ].value = readBuffer.texture;
  290.             // this.blendMaterial.uniforms[ "bloomTexture" ].value = this.renderTargetsHorizontal[ 0 ].texture;
  291.  
  292.         } else {
  293.  
  294.             // Blend it additively over the input texture
  295.             this.fsQuad.material = this.materialCopy;
  296.             this.copyUniforms[ "tDiffuse" ].value = this.renderTargetsHorizontal[ 0 ].texture;
  297.  
  298.         }
  299.  
  300.         if ( maskActive ) renderer.state.buffers.stencil.setTest( true );
  301.  
  302.         if ( this.renderToScreen ) {
  303.  
  304.             renderer.setRenderTarget( null );
  305.             this.fsQuad.render( renderer );
  306.  
  307.         } else {
  308.  
  309.             renderer.setRenderTarget( readBuffer );
  310.             this.fsQuad.render( renderer );
  311.  
  312.         }
  313.  
  314.         // Restore renderer settings
  315.         renderer.setClearColor( this.oldClearColor, this.oldClearAlpha );
  316.         renderer.autoClear = oldAutoClear;
  317.  
  318.     },
  319.  
  320.     createBlendMaterial: function() {
  321.  
  322.         return new ShaderMaterial( {
  323.             uniforms: {
  324.                 baseTexture: { value: null },
  325.                 bloomTexture: { value: this.renderTargetsHorizontal[ 0 ].texture },
  326.             },
  327.  
  328.             vertexShader: `
  329.             varying vec2 vUv;
  330.  
  331.             void main() {
  332.  
  333.                 vUv = uv;
  334.  
  335.                 gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
  336.  
  337.             }
  338.             `,
  339.  
  340.             fragmentShader:
  341.             `
  342.             uniform sampler2D baseTexture;
  343.             uniform sampler2D bloomTexture;
  344.  
  345.             varying vec2 vUv;
  346.  
  347.             void main() {
  348.  
  349.                 // vec4 texel1 = texture2D( baseTexture, vUv );
  350.                 // vec4 texel2 = texture2D( bloomTexture, vUv );
  351.                 // gl_FragColor = mix( texel1, texel2, 0.5 );
  352.  
  353.                 gl_FragColor = texture2D( baseTexture , vUv ) + vec4( 1.0 ) * texture2D( bloomTexture , vUv );
  354.  
  355.             }
  356.             `
  357.         } );
  358.  
  359.     },
  360.  
  361.     createSeperableBlurMaterial: function ( kernelRadius ) {
  362.  
  363.         return new ShaderMaterial( {
  364.  
  365.             defines: {
  366.                 "KERNEL_RADIUS": kernelRadius,
  367.                 "SIGMA": kernelRadius
  368.             },
  369.  
  370.             uniforms: {
  371.                 "colorTexture": { value: null },
  372.                 "texSize": { value: new Vector2( 0.5, 0.5 ) },
  373.                 "direction": { value: new Vector2( 0.5, 0.5 ) }
  374.             },
  375.  
  376.             vertexShader:
  377.                 "varying vec2 vUv;\n\
  378.                 void main() {\n\
  379.                     vUv = uv;\n\
  380.                     gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
  381.                 }",
  382.  
  383.             fragmentShader:
  384.                 "#include <common>\
  385.                 varying vec2 vUv;\n\
  386.                 uniform sampler2D colorTexture;\n\
  387.                 uniform vec2 texSize;\
  388.                 uniform vec2 direction;\
  389.                 \
  390.                 float gaussianPdf(in float x, in float sigma) {\
  391.                     return 0.39894 * exp( -0.5 * x * x/( sigma * sigma))/sigma;\
  392.                 }\
  393.                 void main() {\n\
  394.                     vec2 invSize = 1.0 / texSize;\
  395.                     float fSigma = float(SIGMA);\
  396.                     float weightSum = gaussianPdf(0.0, fSigma);\
  397.                     vec3 diffuseSum = texture2D( colorTexture, vUv).rgb * weightSum;\
  398.                     for( int i = 1; i < KERNEL_RADIUS; i ++ ) {\
  399.                         float x = float(i);\
  400.                         float w = gaussianPdf(x, fSigma);\
  401.                         vec2 uvOffset = direction * invSize * x;\
  402.                         vec3 sample1 = texture2D( colorTexture, vUv + uvOffset).rgb;\
  403.                         vec3 sample2 = texture2D( colorTexture, vUv - uvOffset).rgb;\
  404.                         diffuseSum += (sample1 + sample2) * w;\
  405.                         weightSum += 2.0 * w;\
  406.                     }\
  407.                     gl_FragColor = vec4(diffuseSum/weightSum, 1.0);\n\
  408.                 }"
  409.         } );
  410.  
  411.     },
  412.  
  413.     createCompositeMaterial: function ( nMips ) {
  414.  
  415.         return new ShaderMaterial( {
  416.  
  417.             defines: {
  418.                 "NUM_MIPS": nMips
  419.             },
  420.  
  421.             uniforms: {
  422.                 blurTexture0: { value: this.renderTargetsVertical[ 0 ].texture },
  423.                 blurTexture1: { value: this.renderTargetsVertical[ 1 ].texture },
  424.                 blurTexture2: { value: this.renderTargetsVertical[ 2 ].texture },
  425.                 blurTexture3: { value: this.renderTargetsVertical[ 3 ].texture },
  426.                 blurTexture4: { value: this.renderTargetsVertical[ 4 ].texture },
  427.                 bloomStrength: { value: this.strength },
  428.                 bloomFactors: { value: this.bloomFactors },
  429.                 bloomTintColors: { value: this.bloomTintColors },
  430.                 bloomRadius: { value: this.radius }
  431.             },
  432.  
  433.             vertexShader:
  434.                 "varying vec2 vUv;\n\
  435.                 void main() {\n\
  436.                     vUv = uv;\n\
  437.                     gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
  438.                 }",
  439.  
  440.             fragmentShader:
  441.                 "varying vec2 vUv;\
  442.                 uniform sampler2D blurTexture0;\
  443.                 uniform sampler2D blurTexture1;\
  444.                 uniform sampler2D blurTexture2;\
  445.                 uniform sampler2D blurTexture3;\
  446.                 uniform sampler2D blurTexture4;\
  447.                 uniform float bloomStrength;\
  448.                 uniform float bloomRadius;\
  449.                 uniform float bloomFactors[NUM_MIPS];\
  450.                 uniform vec3 bloomTintColors[NUM_MIPS];\
  451.                 \
  452.                 float lerpBloomFactor(const in float factor) { \
  453.                     float mirrorFactor = 1.2 - factor;\
  454.                     return mix(factor, mirrorFactor, bloomRadius);\
  455.                 }\
  456.                 \
  457.                 void main() {\
  458.                     gl_FragColor = bloomStrength * ( lerpBloomFactor(bloomFactors[0]) * vec4(bloomTintColors[0], 1.0) * texture2D(blurTexture0, vUv) + \
  459.                                                     lerpBloomFactor(bloomFactors[1]) * vec4(bloomTintColors[1], 1.0) * texture2D(blurTexture1, vUv) + \
  460.                                                     lerpBloomFactor(bloomFactors[2]) * vec4(bloomTintColors[2], 1.0) * texture2D(blurTexture2, vUv) + \
  461.                                                     lerpBloomFactor(bloomFactors[3]) * vec4(bloomTintColors[3], 1.0) * texture2D(blurTexture3, vUv) + \
  462.                                                     lerpBloomFactor(bloomFactors[4]) * vec4(bloomTintColors[4], 1.0) * texture2D(blurTexture4, vUv) );\
  463.                 }"
  464.         } );
  465.  
  466.     },
  467.  
  468.     changeVisibilityOfNonSelectedObjects: function ( bVisible ) {
  469.  
  470.         var self = this;
  471.  
  472.         this.scene.traverse( function( child ) {
  473.  
  474.             if( child.isMesh && ! self.selectedObjects.includes( child )) {
  475.  
  476.                 child.visible = bVisible;
  477.                 // child.material.colorWrite = bVisible;
  478.  
  479.             }
  480.  
  481.         } );
  482.  
  483.     },
  484.  
  485. } );
  486.  
  487. UnrealBloomPass.BlurDirectionX = new Vector2( 1.0, 0.0 );
  488. UnrealBloomPass.BlurDirectionY = new Vector2( 0.0, 1.0 );
  489.  
  490. export { UnrealBloomPass };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement