diff --git a/examples/jsm/postprocessing/SSShadowPass.js b/examples/jsm/postprocessing/SSShadowPass.js index 0168e0d4f731c0..42fe9d0c158622 100644 --- a/examples/jsm/postprocessing/SSShadowPass.js +++ b/examples/jsm/postprocessing/SSShadowPass.js @@ -24,7 +24,7 @@ import { CopyShader } from '../shaders/CopyShader.js'; class SSShadowPass extends Pass { - constructor( { renderer, scene, camera, width, height, encoding, morphTargets = false } ) { + constructor( { renderer, scene, camera, width, height, selects, encoding, morphTargets = false } ) { super(); @@ -49,6 +49,29 @@ class SSShadowPass extends Pass { this.tempColor = new Color(); + this._selects = selects; + + this.selective = Array.isArray( this._selects ); + Object.defineProperty( this, 'selects', { + get() { + + return this._selects; + + }, + set( val ) { + + if (this._selects === val ) return; + this._selects = val; + if ( Array.isArray( val ) ) { + this.selective = true; + this.ssshadowMaterial.defines.SELECTIVE = true; + this.ssshadowMaterial.needsUpdate = true; + + } + + } + } ); + this._infiniteThick = SSShadowShader.defines.INFINITE_THICK; Object.defineProperty( this, 'infiniteThick', { get() { @@ -98,6 +121,13 @@ class SSShadowPass extends Pass { format: RGBAFormat } ); + this.recievesShadowsRenderTarget = new WebGLRenderTarget( this.width, this.height, { + minFilter: NearestFilter, + magFilter: NearestFilter, + format: RGBAFormat, + type: HalfFloatType, + } ); + // ssshadow render target this.ssshadowRenderTarget = new WebGLRenderTarget( this.width, this.height, { @@ -126,7 +156,9 @@ class SSShadowPass extends Pass { this.ssshadowMaterial.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.texture; this.ssshadowMaterial.uniforms[ 'tNormal' ].value = this.normalRenderTarget.texture; + this.ssshadowMaterial.defines.SELECTIVE = this.selective; this.ssshadowMaterial.needsUpdate = true; + this.ssshadowMaterial.uniforms[ 'tRecievesShadows' ].value = this.recievesShadowsRenderTarget.texture; this.ssshadowMaterial.uniforms[ 'tRefractive' ].value = this.refractiveRenderTarget.texture; this.ssshadowMaterial.uniforms[ 'tDepth' ].value = this.beautyRenderTarget.depthTexture; this.ssshadowMaterial.uniforms[ 'cameraNear' ].value = this.camera.near; @@ -141,6 +173,14 @@ class SSShadowPass extends Pass { this.normalMaterial = new MeshNormalMaterial( { morphTargets } ); this.normalMaterial.blending = NoBlending; + this.recievesShadowsOnMaterial = new MeshBasicMaterial( { + color: 'white', + } ); + + this.recievesShadowsOffMaterial = new MeshBasicMaterial( { + color: 'black', + } ); + // refractiveOn material this.refractiveOnMaterial = new MeshBasicMaterial( { @@ -196,12 +236,15 @@ class SSShadowPass extends Pass { this.beautyRenderTarget.dispose(); this.normalRenderTarget.dispose(); + this.recievesShadowsRenderTarget.dispose(); this.refractiveRenderTarget.dispose(); this.ssshadowRenderTarget.dispose(); // dispose materials this.normalMaterial.dispose(); + this.recievesShadowsOnMaterial.dispose(); + this.recievesShadowsOffMaterial.dispose(); this.refractiveOnMaterial.dispose(); this.refractiveOffMaterial.dispose(); this.copyMaterial.dispose(); @@ -226,6 +269,13 @@ class SSShadowPass extends Pass { this.renderOverride( renderer, this.normalMaterial, this.normalRenderTarget, 0, 0 ); + // render selected objects + + if ( this.selective ) { + + this.renderRecievesShadows( renderer, this.recievesShadowsOnMaterial, this.recievesShadowsRenderTarget, 0, 0); + } + // render SSShadow this.ssshadowMaterial.uniforms[ 'lightPosition' ].value = this.lightPosition; @@ -282,6 +332,14 @@ class SSShadowPass extends Pass { break; + case SSShadowPass.OUTPUT.RecievesShadows: + + this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.recievesShadowsRenderTarget.texture; + this.copyMaterial.blending = NoBlending; + this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer ); + + break; + default: console.warn( 'THREE.SSShadowPass: Unknown output type.' ); @@ -350,6 +408,67 @@ class SSShadowPass extends Pass { } + renderRecievesShadows( renderer, overrideMaterial, renderTarget, clearColor, clearAlpha ) { + + this.originalClearColor.copy( renderer.getClearColor( this.tempColor ) ); + const originalClearAlpha = renderer.getClearAlpha( this.tempColor ); + const originalAutoClear = renderer.autoClear; + + renderer.setRenderTarget( renderTarget ); + renderer.autoClear = false; + + clearColor = overrideMaterial.clearColor || clearColor; + clearAlpha = overrideMaterial.clearAlpha || clearAlpha; + + if ( ( clearColor != undefined ) && ( clearColor != null ) ) { + + renderer.setClearColor( clearColor ); + renderer.setClearAlpha( clearAlpha || 0.0 ); + renderer.clear(); + + } + + this.scene.traverseVisible( child => { + + if ( !child?.material?.visible ) { + + return; + + } + child._SSShadowPassBackupMaterial = child.material; + if ( this._selects.includes( child ) ) { + + child.material = this.recievesShadowsOnMaterial; + + } else { + + child.material = this.recievesShadowsOffMaterial; + + } + + } ); + + renderer.render( this.scene, this.camera ); + + this.scene.traverseVisible( child => { + + if ( !child?.material?.visible ) { + + return; + + } + + child.material = child._SSShadowPassBackupMaterial; + + } ); + + // restore original state + renderer.autoClear = originalAutoClear; + renderer.setClearColor( this.originalClearColor ); + renderer.setClearAlpha( originalClearAlpha ); + + } + setSize( width, height ) { this.width = width; @@ -359,6 +478,7 @@ class SSShadowPass extends Pass { this.ssshadowMaterial.needsUpdate = true; this.beautyRenderTarget.setSize( width, height ); this.normalRenderTarget.setSize( width, height ); + this.recievesShadowsRenderTarget.setSize( width, height ); this.ssshadowRenderTarget.setSize( width, height ); this.refractiveRenderTarget.setSize( width, height ); @@ -376,6 +496,7 @@ SSShadowPass.OUTPUT = { 'Beauty': 3, 'Depth': 4, 'Normal': 5, + 'RecievesShadows': 6, 'Refractive': 7, }; diff --git a/examples/jsm/shaders/SSShadowShader.js b/examples/jsm/shaders/SSShadowShader.js index a71fb803299719..40f5500b7b2699 100644 --- a/examples/jsm/shaders/SSShadowShader.js +++ b/examples/jsm/shaders/SSShadowShader.js @@ -17,6 +17,7 @@ const SSShadowShader = { 'tDiffuse': { value: null }, 'tNormal': { value: null }, 'tRefractive': { value: null }, + 'tRecievesShadows': { value: null }, 'tDepth': { value: null }, 'cameraNear': { value: null }, 'cameraFar': { value: null }, @@ -58,6 +59,7 @@ const SSShadowShader = { uniform sampler2D tNormal; uniform sampler2D tRefractive; uniform sampler2D tDiffuse; + uniform sampler2D tRecievesShadows; uniform float cameraRange; uniform vec2 resolution; uniform float cameraNear; @@ -115,6 +117,10 @@ const SSShadowShader = { return xy; } void main(){ + #ifdef SELECTIVE + float recievesShadows=texture2D(tRecievesShadows,vUv).r; + if(recievesShadows!=1.) return; + #endif // gl_FragColor=vec4(0,0,.5,1);return; diff --git a/examples/webgl_postprocessing_ssshadow.html b/examples/webgl_postprocessing_ssshadow.html index d22526ce666371..acf08eba25a56d 100644 --- a/examples/webgl_postprocessing_ssshadow.html +++ b/examples/webgl_postprocessing_ssshadow.html @@ -43,6 +43,7 @@ let controls; let camera, scene, renderer; const objects = []; + const selects = []; const raycaster = new THREE.Raycaster(); const mouseDown = new THREE.Vector2(); const mouse = new THREE.Vector2(); @@ -85,6 +86,7 @@ plane.position.y = - 0.0001; // plane.receiveShadow = true; scene.add( plane ); + selects.push(plane); plane.name = 'plane'; // Lights @@ -116,6 +118,7 @@ mesh.name = 'bunny'; scene.add( mesh ); objects.push( mesh ); + selects.push( mesh ); // Release decoder resources. dracoLoader.dispose(); @@ -132,6 +135,7 @@ mesh.name = 'box'; scene.add( mesh ); objects.push( mesh ); + selects.push( mesh ); geometry = new THREE.IcosahedronBufferGeometry( .025, 4 ); // material = new THREE.MeshStandardMaterial( { color: 'cyan' } ); @@ -141,6 +145,7 @@ mesh.name = 'sphere'; scene.add( mesh ); objects.push( mesh ); + selects.push( mesh ); geometry = new THREE.ConeBufferGeometry( .025, .05, 64 ); // material = new THREE.MeshStandardMaterial( { color: 'yellow' } ); @@ -150,6 +155,7 @@ mesh.name = 'cone'; scene.add( mesh ); objects.push( mesh ); + selects.push( mesh ); // renderer renderer = new THREE.WebGLRenderer( { antialias: false } ); @@ -176,6 +182,7 @@ width: innerWidth, height: innerHeight, encoding: THREE.sRGBEncoding, + selects: selects, } ); composer.addPass( ssshadowPass ); @@ -231,6 +238,7 @@ 'Beauty': SSShadowPass.OUTPUT.Beauty, 'Depth': SSShadowPass.OUTPUT.Depth, 'Normal': SSShadowPass.OUTPUT.Normal, + 'Recieves Shadows': SSShadowPass.OUTPUT.RecievesShadows, } ).onChange( function ( value ) { ssshadowPass.output = parseInt( value );