From 0412aa872632c8ba72e23ddf292c6a5ad8e94ea5 Mon Sep 17 00:00:00 2001 From: Noah Lyons Date: Mon, 25 Apr 2022 20:14:39 -0700 Subject: [PATCH 1/2] added recievesShadows, weird bug with clipping and angle --- examples/jsm/postprocessing/SSShadowPass.js | 116 +++++++++++++++++++- examples/jsm/shaders/SSShadowShader.js | 6 + examples/webgl_postprocessing_ssshadow.html | 7 ++ 3 files changed, 127 insertions(+), 2 deletions(-) diff --git a/examples/jsm/postprocessing/SSShadowPass.js b/examples/jsm/postprocessing/SSShadowPass.js index 0168e0d4f731c0..278ac75503de65 100644 --- a/examples/jsm/postprocessing/SSShadowPass.js +++ b/examples/jsm/postprocessing/SSShadowPass.js @@ -15,7 +15,8 @@ import { UnsignedShortType, WebGLRenderTarget, HalfFloatType, - MeshStandardMaterial + MeshStandardMaterial, + DoubleSide } from '../../../build/three.module.js'; import { Pass, FullScreenQuad } from './Pass.js'; import { SSShadowShader } from '../shaders/SSShadowShader.js'; @@ -24,7 +25,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 +50,28 @@ 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,16 @@ class SSShadowPass extends Pass { this.normalMaterial = new MeshNormalMaterial( { morphTargets } ); this.normalMaterial.blending = NoBlending; + this.recievesShadowsOnMaterial = new MeshBasicMaterial( { + color: 'white', + side: DoubleSide + } ); + + this.recievesShadowsOffMaterial = new MeshBasicMaterial( { + color: 'black', + side: DoubleSide + } ); + // refractiveOn material this.refractiveOnMaterial = new MeshBasicMaterial( { @@ -196,12 +238,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 +271,11 @@ class SSShadowPass extends Pass { this.renderOverride( renderer, this.normalMaterial, this.normalRenderTarget, 0, 0 ); + 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,58 @@ 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 => { + + child._SSShadowPassBackupMaterial = child.material; + if ( this._selects.includes( child ) ) { + + child.material = this.recievesShadowsOnMaterial; + + } else { + + child.material = this.recievesShadowsOffMaterial; + + } + + } ); + // this.backupCameraNear = this.camera.near; + // this.backupCameraFar = this.camera.far; + // this.camera.far = this.backupCameraFar * 100; + renderer.render( this.scene, this.camera ); + this.scene.traverseVisible( child => { + + child.material = child._SSShadowPassBackupMaterial; + + } ); + + // restore original state + // this.camera.far = this.backupCameraFar; + renderer.autoClear = originalAutoClear; + renderer.setClearColor( this.originalClearColor ); + renderer.setClearAlpha( originalClearAlpha ); + + } + setSize( width, height ) { this.width = width; @@ -359,6 +469,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 +487,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..597844f97ea179 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==0.) 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..2d0f9204cf9b71 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(); @@ -116,6 +117,7 @@ mesh.name = 'bunny'; scene.add( mesh ); objects.push( mesh ); + selects.push( mesh ); // Release decoder resources. dracoLoader.dispose(); @@ -132,6 +134,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 +144,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 +154,7 @@ mesh.name = 'cone'; scene.add( mesh ); objects.push( mesh ); + selects.push( mesh ); // renderer renderer = new THREE.WebGLRenderer( { antialias: false } ); @@ -176,6 +181,7 @@ width: innerWidth, height: innerHeight, encoding: THREE.sRGBEncoding, + selects: selects } ); composer.addPass( ssshadowPass ); @@ -231,6 +237,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 ); From 0d5489c6fd9e525fc6993133e45ecdcf8d441a61 Mon Sep 17 00:00:00 2001 From: Noah Lyons Date: Mon, 25 Apr 2022 20:00:57 -0700 Subject: [PATCH 2/2] Selective working but no example yet --- examples/jsm/postprocessing/SSShadowPass.js | 25 ++++++++++++++------- examples/jsm/shaders/SSShadowShader.js | 2 +- examples/webgl_postprocessing_ssshadow.html | 3 ++- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/examples/jsm/postprocessing/SSShadowPass.js b/examples/jsm/postprocessing/SSShadowPass.js index 278ac75503de65..42fe9d0c158622 100644 --- a/examples/jsm/postprocessing/SSShadowPass.js +++ b/examples/jsm/postprocessing/SSShadowPass.js @@ -15,8 +15,7 @@ import { UnsignedShortType, WebGLRenderTarget, HalfFloatType, - MeshStandardMaterial, - DoubleSide + MeshStandardMaterial } from '../../../build/three.module.js'; import { Pass, FullScreenQuad } from './Pass.js'; import { SSShadowShader } from '../shaders/SSShadowShader.js'; @@ -51,6 +50,7 @@ class SSShadowPass extends Pass { this.tempColor = new Color(); this._selects = selects; + this.selective = Array.isArray( this._selects ); Object.defineProperty( this, 'selects', { get() { @@ -175,12 +175,10 @@ class SSShadowPass extends Pass { this.recievesShadowsOnMaterial = new MeshBasicMaterial( { color: 'white', - side: DoubleSide } ); this.recievesShadowsOffMaterial = new MeshBasicMaterial( { color: 'black', - side: DoubleSide } ); // refractiveOn material @@ -271,6 +269,8 @@ 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); @@ -430,6 +430,11 @@ class SSShadowPass extends Pass { this.scene.traverseVisible( child => { + if ( !child?.material?.visible ) { + + return; + + } child._SSShadowPassBackupMaterial = child.material; if ( this._selects.includes( child ) ) { @@ -442,18 +447,22 @@ class SSShadowPass extends Pass { } } ); - // this.backupCameraNear = this.camera.near; - // this.backupCameraFar = this.camera.far; - // this.camera.far = this.backupCameraFar * 100; + renderer.render( this.scene, this.camera ); + this.scene.traverseVisible( child => { + if ( !child?.material?.visible ) { + + return; + + } + child.material = child._SSShadowPassBackupMaterial; } ); // restore original state - // this.camera.far = this.backupCameraFar; renderer.autoClear = originalAutoClear; renderer.setClearColor( this.originalClearColor ); renderer.setClearAlpha( originalClearAlpha ); diff --git a/examples/jsm/shaders/SSShadowShader.js b/examples/jsm/shaders/SSShadowShader.js index 597844f97ea179..40f5500b7b2699 100644 --- a/examples/jsm/shaders/SSShadowShader.js +++ b/examples/jsm/shaders/SSShadowShader.js @@ -119,7 +119,7 @@ const SSShadowShader = { void main(){ #ifdef SELECTIVE float recievesShadows=texture2D(tRecievesShadows,vUv).r; - if(recievesShadows==0.) return; + 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 2d0f9204cf9b71..acf08eba25a56d 100644 --- a/examples/webgl_postprocessing_ssshadow.html +++ b/examples/webgl_postprocessing_ssshadow.html @@ -86,6 +86,7 @@ plane.position.y = - 0.0001; // plane.receiveShadow = true; scene.add( plane ); + selects.push(plane); plane.name = 'plane'; // Lights @@ -181,7 +182,7 @@ width: innerWidth, height: innerHeight, encoding: THREE.sRGBEncoding, - selects: selects + selects: selects, } ); composer.addPass( ssshadowPass );