| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| THREE.WebGLDeferredRenderer = function ( parameters ) { |
|
|
| parameters = parameters || {}; |
|
|
| |
|
|
| var _this = this; |
|
|
| var _context; |
| var _state; |
|
|
| var _width, _height; |
|
|
| |
| var _compColor; |
| var _passColor, _passForward, _passCopy; |
|
|
| |
| var _compReconstruction; |
| var _passReconstruction; |
|
|
| |
| var _compNormalDepth, _compLight, _compFinal; |
| var _passNormalDepth, _passLight, _passLightFullscreen, _passFinal, _passFXAA; |
|
|
| var _depthTexture; |
|
|
| var _currentCamera; |
|
|
| var _lightScene, _lightFullscreenScene; |
|
|
| var _antialias = false; |
| var _hasTransparentObject = false; |
| var _lightPrePass = false; |
| var _cacheKeepAlive = false; |
|
|
| var _tmpMaterial = new THREE.ShaderMaterial( { visible: false } ); |
| var _tmpVector3 = new THREE.Vector3(); |
|
|
| |
| |
| |
| |
|
|
| |
| var _lightScenesCache = {}; |
| var _lightFullscreenScenesCache = {}; |
|
|
| |
| |
| var _normalDepthMaterialsCache = {}; |
| var _normalDepthShininessMaterialsCache = {}; |
| var _colorMaterialsCache = {}; |
| var _reconstructionMaterialsCache = {}; |
|
|
| |
| var _deferredLightsCache = {}; |
|
|
| |
| var _classicDeferredLightMaterialsCache = {}; |
| var _lightPrePassMaterialsCache = {}; |
|
|
| var _removeThresholdCount = 60; |
|
|
| |
| |
| |
| var _originalMaterialsTable = {}; |
|
|
| |
| |
| var _originalOnBeforeRendersTable = {}; |
|
|
| |
| |
| |
| var _originalVisibleTable = {}; |
|
|
| |
|
|
| this.renderer = undefined; |
| this.domElement = undefined; |
|
|
| this.forwardRendering = false; |
|
|
| |
|
|
| function init( parameters ) { |
|
|
| _this.renderer = parameters.renderer !== undefined ? parameters.renderer : new THREE.WebGLRenderer(); |
| _this.domElement = _this.renderer.domElement; |
|
|
| _context = _this.renderer.context; |
| _state = _this.renderer.state; |
|
|
| _width = parameters.width !== undefined ? parameters.width : _this.renderer.getSize( new THREE.Vector2() ).width; |
| _height = parameters.height !== undefined ? parameters.height : _this.renderer.getSize( new THREE.Vector2() ).height; |
|
|
| var antialias = parameters.antialias !== undefined ? parameters.antialias : false; |
|
|
| if ( parameters.cacheKeepAlive !== undefined ) _cacheKeepAlive = parameters.cacheKeepAlive; |
|
|
| initDepthTexture(); |
|
|
| initPassNormalDepth(); |
| initPassColor(); |
| initPassLight(); |
| initPassReconstruction(); |
| initPassFinal(); |
|
|
| _this.setSize( _width, _height ); |
| _this.setAntialias( antialias ); |
| _this.enableLightPrePass( false ); |
|
|
| } |
|
|
| function initDepthTexture() { |
|
|
| _depthTexture = new THREE.DepthTexture( |
| _width, |
| _height, |
| THREE.UnsignedInt248Type, |
| undefined, |
| undefined, |
| undefined, |
| undefined, |
| undefined, |
| undefined, |
| THREE.DepthStencilFormat |
| ); |
|
|
| } |
|
|
| function initPassNormalDepth() { |
|
|
| _passNormalDepth = new THREE.RenderPass(); |
| _passNormalDepth.clear = true; |
|
|
| var rt = new THREE.WebGLRenderTarget( _width, _height, { |
| minFilter: THREE.NearestFilter, |
| magFilter: THREE.NearestFilter, |
| format: THREE.RGBAFormat, |
| type: THREE.FloatType, |
| stencilBuffer: true, |
| depthTexture: _depthTexture |
| } ); |
|
|
| rt.texture.generateMipamps = false; |
|
|
| _compNormalDepth = new THREE.EffectComposer( _this.renderer, rt ); |
| _compNormalDepth.renderToScreen = false; |
| _compNormalDepth.addPass( _passNormalDepth ); |
|
|
| } |
|
|
| function initPassColor() { |
|
|
| _passColor = new THREE.RenderPass(); |
| _passColor.clear = true; |
|
|
| var rt = new THREE.WebGLRenderTarget( _width, _height, { |
| minFilter: THREE.NearestFilter, |
| magFilter: THREE.NearestFilter, |
| format: THREE.RGBAFormat, |
| type: THREE.FloatType, |
| depthTexture: _depthTexture |
| } ); |
|
|
| rt.texture.generateMipamps = false; |
|
|
| _compColor = new THREE.EffectComposer( _this.renderer, rt ); |
| _compColor.renderToScreen = false; |
| _compColor.addPass( _passColor ); |
|
|
| } |
|
|
| function initPassLight() { |
|
|
| _passLightFullscreen = new THREE.RenderPass(); |
| _passLightFullscreen.clear = true; |
| _passLightFullscreen.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); |
|
|
| _passLight = new THREE.RenderPass(); |
| _passLight.clear = false; |
|
|
| var rt = new THREE.WebGLRenderTarget( _width, _height, { |
| minFilter: THREE.NearestFilter, |
| magFilter: THREE.NearestFilter, |
| format: THREE.RGBAFormat, |
| type: THREE.FloatType, |
| depthTexture: _depthTexture |
| } ); |
|
|
| rt.texture.generateMipamps = false; |
|
|
| _compLight = new THREE.EffectComposer( _this.renderer, rt ); |
| _compLight.renderToScreen = false; |
| _compLight.addPass( _passLightFullscreen ); |
| _compLight.addPass( _passLight ); |
|
|
| } |
|
|
| function initPassReconstruction() { |
|
|
| _passReconstruction = new THREE.RenderPass(); |
| _passReconstruction.clear = true; |
|
|
| var rt = new THREE.WebGLRenderTarget( _width, _height, { |
| minFilter: THREE.NearestFilter, |
| magFilter: THREE.NearestFilter, |
| format: THREE.RGBAFormat, |
| type: THREE.FloatType, |
| depthTexture: _depthTexture |
| } ); |
|
|
| rt.texture.generateMipamps = false; |
|
|
| _compReconstruction = new THREE.EffectComposer( _this.renderer, rt ); |
| _compReconstruction.renderToScreen = false; |
| _compReconstruction.addPass( _passReconstruction ); |
|
|
| } |
|
|
| function initPassFinal() { |
|
|
| _passFinal = new THREE.ShaderPass( THREE.ShaderDeferred[ 'final' ] ); |
| _passFinal.clear = true; |
| _passFinal.uniforms.samplerResult.value = _compLight.renderTarget2.texture; |
| _passFinal.material.blending = THREE.NoBlending; |
| _passFinal.material.depthWrite = false; |
| _passFinal.material.depthTest = false; |
|
|
| _passForward = new THREE.RenderPass(); |
| _passForward.clear = false; |
|
|
| _passCopy = new THREE.ShaderPass( THREE.CopyShader ); |
|
|
| _passFXAA = new THREE.ShaderPass( THREE.FXAAShader ); |
|
|
| var rt = new THREE.WebGLRenderTarget( _width, _height, { |
| minFilter: THREE.NearestFilter, |
| magFilter: THREE.LinearFilter, |
| format: THREE.RGBFormat, |
| type: THREE.UnsignedByteType, |
| depthTexture: _depthTexture |
| } ); |
|
|
| rt.texture.generateMipamps = false; |
|
|
| _compFinal = new THREE.EffectComposer( _this.renderer, rt ); |
| _compFinal.addPass( _passFinal ); |
| _compFinal.addPass( _passForward ); |
| _compFinal.addPass( _passCopy ); |
| _compFinal.addPass( _passFXAA ); |
|
|
| } |
|
|
| function initLightScene( scene ) { |
|
|
| var lightSceneData = _lightScenesCache[ scene.uuid ]; |
| var lightFullscreenSceneData = _lightFullscreenScenesCache[ scene.uuid ]; |
|
|
| if ( lightSceneData === undefined ) { |
|
|
| var s = new THREE.Scene(); |
| s.userData.lights = {}; |
|
|
| lightSceneData = createCacheData(); |
| lightSceneData.scene = s; |
|
|
| _lightScenesCache[ scene.uuid ] = lightSceneData; |
|
|
| } |
|
|
| if ( lightFullscreenSceneData === undefined ) { |
|
|
| var s = new THREE.Scene(); |
| s.userData.lights = {}; |
|
|
| var emissiveLight = createDeferredEmissiveLight(); |
|
|
| s.userData.emissiveLight = emissiveLight; |
| s.add( emissiveLight ); |
|
|
| lightFullscreenSceneData = createCacheData(); |
| lightFullscreenSceneData.scene = s; |
|
|
| _lightFullscreenScenesCache[ scene.uuid ] = lightFullscreenSceneData; |
|
|
| } |
|
|
| lightSceneData.used = true; |
| lightFullscreenSceneData.used = true; |
|
|
| var lightScene = lightSceneData.scene; |
| var lightFullscreenScene = lightFullscreenSceneData.scene; |
|
|
| |
| lightFullscreenScene.userData.emissiveLight.visible = ! _lightPrePass; |
|
|
| _lightScene = lightScene; |
| _lightFullscreenScene = lightFullscreenScene; |
|
|
| } |
|
|
| function getMaterialFromCacheOrCreate( originalMaterial, cache, createFunc, updateFunc ) { |
|
|
| var data = cache[ originalMaterial.uuid ]; |
|
|
| if ( data === undefined ) { |
|
|
| data = createCacheData(); |
| data.material = createFunc( originalMaterial ); |
| cache[ originalMaterial.uuid ] = data; |
|
|
| } |
|
|
| data.used = true; |
|
|
| updateFunc( data.material, originalMaterial ); |
|
|
| _originalMaterialsTable[ data.material.uuid ] = originalMaterial; |
|
|
| return data.material; |
|
|
| } |
|
|
| function overrideMaterialAndOnBeforeRender( object, getMaterialFunc, onBeforeRender ) { |
|
|
| if ( object.material === undefined ) return; |
|
|
| if ( Array.isArray( object.material ) ) { |
|
|
| for ( var i = 0, il = object.material.length; i < il; i ++ ) { |
|
|
| object.material[ i ] = getMaterialFunc( object.material[ i ] ); |
|
|
| } |
|
|
| } else { |
|
|
| object.material = getMaterialFunc( object.material ); |
|
|
| } |
|
|
| object.onBeforeRender = onBeforeRender; |
|
|
| } |
|
|
| function restoreOriginalMaterial( object ) { |
|
|
| if ( object.material === undefined ) return; |
|
|
| if ( Array.isArray( object.material ) ) { |
|
|
| for ( var i = 0, il = object.material.length; i < il; i ++ ) { |
|
|
| object.material[ i ] = _originalMaterialsTable[ object.material[ i ].uuid ]; |
|
|
| } |
|
|
| } else { |
|
|
| object.material = _originalMaterialsTable[ object.material.uuid ]; |
|
|
| } |
|
|
| } |
|
|
| function setMaterialNormalDepth( object ) { |
|
|
| overrideMaterialAndOnBeforeRender( object, getNormalDepthMaterial, updateDeferredNormalDepthUniforms ); |
|
|
| } |
|
|
| function getNormalDepthMaterial( originalMaterial ) { |
|
|
| return getMaterialFromCacheOrCreate( |
| originalMaterial, |
| ( _lightPrePass ) ? _normalDepthShininessMaterialsCache : _normalDepthMaterialsCache, |
| createDeferredNormalDepthMaterial, |
| updateDeferredNormalDepthMaterial |
| ); |
|
|
| } |
|
|
| function createDeferredNormalDepthMaterial( originalMaterial ) { |
|
|
| var shader = ( _lightPrePass ) ? THREE.ShaderDeferred[ 'normalDepthShininess' ] : THREE.ShaderDeferred[ 'normalDepth' ]; |
|
|
| return new THREE.ShaderMaterial( { |
| uniforms: Object.assign( {}, shader.uniforms ), |
| fragmentShader: shader.fragmentShader, |
| vertexShader: shader.vertexShader, |
| blending: THREE.NoBlending |
| } ); |
|
|
| } |
|
|
| function updateDeferredNormalDepthMaterial( material, originalMaterial ) { |
|
|
| if ( originalMaterial.skinning !== undefined ) material.skinning = originalMaterial.skinning; |
| if ( originalMaterial.morphTargets !== undefined ) material.morphTargets = originalMaterial.morphTargets; |
|
|
| if ( originalMaterial.visible === true ) { |
|
|
| material.visible = ! originalMaterial.transparent; |
|
|
| } else { |
|
|
| material.visible = false; |
|
|
| } |
|
|
| } |
|
|
| function updateDeferredNormalDepthUniforms( renderer, scene, camera, geometry, material, group ) { |
|
|
| if ( ! _lightPrePass ) return; |
|
|
| var originalMaterial = _originalMaterialsTable[ material.uuid ]; |
|
|
| if ( originalMaterial === undefined || originalMaterial.shininess === undefined ) return; |
|
|
| material.uniforms.shininess.value = originalMaterial.shininess; |
|
|
| } |
|
|
| function setMaterialColor( object ) { |
|
|
| overrideMaterialAndOnBeforeRender( object, getColorMaterial, updateDeferredColorUniforms ); |
|
|
| } |
|
|
| function getColorMaterial( originalMaterial ) { |
|
|
| return getMaterialFromCacheOrCreate( |
| originalMaterial, |
| _colorMaterialsCache, |
| createDeferredColorMaterial, |
| updateDeferredColorMaterial |
| ); |
|
|
| } |
|
|
| function createDeferredColorMaterial( originalMaterial ) { |
|
|
| var shader = THREE.ShaderDeferred[ 'color' ]; |
|
|
| var material = new THREE.ShaderMaterial( { |
| uniforms: Object.assign( {}, shader.uniforms ), |
| fragmentShader: shader.fragmentShader, |
| vertexShader: shader.vertexShader, |
| blending: THREE.NoBlending |
| } ); |
|
|
| if ( originalMaterial.map !== undefined ) material.map = originalMaterial.map; |
|
|
| return material; |
|
|
| } |
|
|
| function updateDeferredColorMaterial( material, originalMaterial ) { |
|
|
| if ( originalMaterial.map !== undefined ) material.map = originalMaterial.map; |
| if ( originalMaterial.skinning !== undefined ) material.skinning = originalMaterial.skinning; |
| if ( originalMaterial.morphTargets !== undefined ) material.morphTargets = originalMaterial.morphTargets; |
|
|
| if ( originalMaterial.visible === true ) { |
|
|
| material.visible = ! originalMaterial.transparent; |
|
|
| } else { |
|
|
| material.visible = false; |
|
|
| } |
|
|
| } |
|
|
| function updateDeferredColorUniforms( renderer, scene, camera, geometry, material, group ) { |
|
|
| var originalMaterial = _originalMaterialsTable[ material.uuid ]; |
| var uniforms = material.uniforms; |
|
|
| var diffuse, emissive; |
|
|
| if ( originalMaterial.isMeshBasicMaterial === true ) { |
|
|
| emissive = originalMaterial.color; |
|
|
| } else { |
|
|
| diffuse = originalMaterial.color; |
| emissive = originalMaterial.emissive; |
|
|
| } |
|
|
| var specular = originalMaterial.specular; |
| var shininess = originalMaterial.shininess; |
| var map = originalMaterial.map; |
|
|
| if ( diffuse !== undefined ) uniforms.diffuse.value.copy( diffuse ); |
| if ( emissive !== undefined ) uniforms.emissive.value.copy( emissive ); |
| if ( specular !== undefined ) uniforms.specular.value.copy( specular ); |
| if ( shininess !== undefined && uniforms.shininess !== undefined ) uniforms.shininess.value = shininess; |
| if ( map !== undefined ) uniforms.map.value = map; |
|
|
| } |
|
|
| function setMaterialReconstruction( object ) { |
|
|
| overrideMaterialAndOnBeforeRender( object, getReconstructionMaterial, updateDeferredReconstructionUniforms ); |
|
|
| } |
|
|
| function getReconstructionMaterial( originalMaterial ) { |
|
|
| if ( originalMaterial.transparent === true ) { |
|
|
| _originalMaterialsTable[ originalMaterial.uuid ] = originalMaterial; |
| return originalMaterial; |
|
|
| } |
|
|
| return getMaterialFromCacheOrCreate( |
| originalMaterial, |
| _reconstructionMaterialsCache, |
| createDeferredReconstructionMaterial, |
| updateDeferredReconstructionMaterial |
| ); |
|
|
| } |
|
|
| function createDeferredReconstructionMaterial( originalMaterial ) { |
|
|
| var shader = THREE.ShaderDeferred[ 'reconstruction' ]; |
|
|
| var material = new THREE.ShaderMaterial( { |
| uniforms: Object.assign( {}, shader.uniforms ), |
| fragmentShader: shader.fragmentShader, |
| vertexShader: shader.vertexShader, |
| blending: THREE.NoBlending |
| } ); |
|
|
| if ( originalMaterial.map !== undefined ) material.map = originalMaterial.map; |
|
|
| return material; |
|
|
| } |
|
|
| function updateDeferredReconstructionMaterial( material, originalMaterial ) { |
|
|
| updateDeferredColorMaterial( material, originalMaterial ); |
|
|
| } |
|
|
| function updateDeferredReconstructionUniforms( renderer, scene, camera, geometry, material, group ) { |
|
|
| if ( material.transparent === true ) { |
|
|
| |
| var onBeforeRender = _originalOnBeforeRendersTable[ this.uuid ]; |
|
|
| if ( onBeforeRender ) { |
|
|
| onBeforeRender.call( this, renderer, scene, camera, geometry, material, group ); |
|
|
| } |
|
|
| return; |
|
|
| } |
|
|
| updateDeferredColorUniforms( renderer, scene, camera, geometry, material, group ); |
|
|
| material.uniforms.samplerLight.value = _compLight.renderTarget2.texture; |
|
|
| } |
|
|
| function setVisibleForForwardRendering( object ) { |
|
|
| if ( object.material === undefined ) return; |
|
|
| if ( Array.isArray( object.material ) ) { |
|
|
| for ( var i = 0, il = object.material.length; i < il; i ++ ) { |
|
|
| if ( _originalVisibleTable[ object.material[ i ].uuid ] === undefined ) { |
|
|
| _originalVisibleTable[ object.material[ i ].uuid ] = object.material[ i ].visible; |
| object.material[ i ].visible = object.material[ i ].transparent && object.material[ i ].visible; |
|
|
| } |
|
|
| } |
|
|
| } else { |
|
|
| if ( _originalVisibleTable[ object.material.uuid ] === undefined ) { |
|
|
| _originalVisibleTable[ object.material.uuid ] = object.material.visible; |
| object.material.visible = object.material.transparent && object.material.visible; |
|
|
| } |
|
|
| } |
|
|
| } |
|
|
| function restoreVisible( object ) { |
|
|
| if ( object.material === undefined ) return; |
|
|
| if ( Array.isArray( object.material ) ) { |
|
|
| for ( var i = 0, il = object.material.length; i < il; i ++ ) { |
|
|
| object.material[ i ].visible = _originalVisibleTable[ object.material[ i ].uuid ]; |
|
|
| } |
|
|
| } else { |
|
|
| object.material.visible = _originalVisibleTable[ object.material.uuid ]; |
|
|
| } |
|
|
| } |
|
|
| function createDeferredEmissiveLight() { |
|
|
| var shader = THREE.ShaderDeferred[ 'emissiveLight' ]; |
|
|
| var material = new THREE.ShaderMaterial( { |
| uniforms: Object.assign( {}, shader.uniforms ), |
| vertexShader: shader.vertexShader, |
| fragmentShader: shader.fragmentShader, |
| blending: THREE.NoBlending, |
| depthWrite: false |
| } ); |
|
|
| var geometry = new THREE.PlaneBufferGeometry( 2, 2 ); |
| var mesh = new THREE.Mesh( geometry, material ); |
|
|
| mesh.onBeforeRender = function ( renderer, scene, camera, geometry, material, group ) { |
|
|
| material.uniforms.samplerColor.value = _compColor.renderTarget2.texture; |
|
|
| }; |
|
|
| return mesh; |
|
|
| } |
|
|
| function createDeferredLight( originalLight ) { |
|
|
| if ( originalLight.isPointLight ) { |
|
|
| return createDeferredPointLight( originalLight ); |
|
|
| } else if ( originalLight.isSpotLight ) { |
|
|
| return createDeferredSpotLight( originalLight ); |
|
|
| } else if ( originalLight.isDirectionalLight ) { |
|
|
| return createDeferredDirectionalLight( originalLight ); |
|
|
| } |
|
|
| return null; |
|
|
| } |
|
|
| function createDeferredLightMaterial( originalLight ) { |
|
|
| if ( originalLight.isPointLight ) { |
|
|
| return createDeferredPointLightMaterial(); |
|
|
| } else if ( originalLight.isSpotLight ) { |
|
|
| return createDeferredSpotLightMaterial(); |
|
|
| } else if ( originalLight.isDirectionalLight ) { |
|
|
| return createDeferredDirectionalLightMaterial(); |
|
|
| } |
|
|
| return null; |
|
|
| } |
|
|
| function getDeferredLightMaterial( light ) { |
|
|
| var cache = ( _lightPrePass ) ? _lightPrePassMaterialsCache : _classicDeferredLightMaterialsCache; |
|
|
| var data = cache[ light.uuid ]; |
|
|
| if ( data === undefined ) { |
|
|
| data = createCacheData(); |
| data.material = createDeferredLightMaterial( light.userData.originalLight ); |
| cache[ light.uuid ] = data; |
|
|
| } |
|
|
| data.used = true; |
|
|
| return data.material; |
|
|
| } |
|
|
| function updateDeferredLight( light ) { |
|
|
| var originalLight = light.userData.originalLight; |
|
|
| if ( originalLight.isPointLight ) { |
|
|
| updateDeferredPointLight( light ); |
|
|
| } |
|
|
| } |
|
|
| function createDeferredLightMesh( light, geometry ) { |
|
|
| var mesh = new THREE.Mesh( geometry, _tmpMaterial ); |
|
|
| mesh.userData.originalLight = light; |
|
|
| return mesh; |
|
|
| } |
|
|
| function createDeferredLightShaderMaterial( shader ) { |
|
|
| var material = new THREE.ShaderMaterial( { |
| uniforms: Object.assign( {}, shader.uniforms ), |
| vertexShader: shader.vertexShader, |
| fragmentShader: shader.fragmentShader, |
| transparent: true, |
| blending: THREE.AdditiveBlending, |
| depthWrite: false |
| } ); |
|
|
| if ( _lightPrePass ) material.premultipliedAlpha = true; |
|
|
| return material; |
|
|
| } |
|
|
| function updateDeferredLightCommonUniforms( uniforms ) { |
|
|
| if ( _lightPrePass ) { |
|
|
| uniforms.samplerNormalDepthShininess.value = _compNormalDepth.renderTarget2.texture; |
|
|
| } else { |
|
|
| uniforms.samplerNormalDepth.value = _compNormalDepth.renderTarget2.texture; |
| uniforms.samplerColor.value = _compColor.renderTarget2.texture; |
|
|
| } |
|
|
| } |
|
|
| function createDeferredPointLight( light ) { |
|
|
| var mesh = createDeferredLightMesh( light, new THREE.SphereBufferGeometry( 1, 16, 8 ) ); |
| mesh.onBeforeRender = updateDeferredPointLightUniforms; |
| return mesh; |
|
|
| } |
|
|
| |
| |
| |
| |
| function createDeferredPointLightMaterial() { |
|
|
| var shader = ( _lightPrePass ) ? THREE.ShaderDeferred[ 'pointLightPre' ] : THREE.ShaderDeferred[ 'pointLight' ]; |
|
|
| var material = createDeferredLightShaderMaterial( shader ); |
|
|
| material.side = THREE.BackSide; |
| material.depthFunc = THREE.GreaterEqualDepth; |
|
|
| return material; |
|
|
| } |
|
|
| function updateDeferredPointLight( light ) { |
|
|
| var originalLight = light.userData.originalLight; |
| var distance = originalLight.distance; |
|
|
| if ( distance > 0 ) { |
|
|
| light.scale.set( 1, 1, 1 ).multiplyScalar( distance ); |
| light.position.setFromMatrixPosition( originalLight.matrixWorld ); |
|
|
| } |
|
|
| } |
|
|
| function updateDeferredPointLightUniforms( renderer, scene, camera, geometry, material, group ) { |
|
|
| var light = this; |
|
|
| var originalLight = light.userData.originalLight; |
| var distance = originalLight.distance; |
| var uniforms = material.uniforms; |
|
|
| uniforms.lightColor.value.copy( originalLight.color ); |
|
|
| if ( distance > 0 ) { |
|
|
| uniforms.lightRadius.value = distance; |
| uniforms.lightIntensity.value = originalLight.intensity; |
| uniforms.lightPositionVS.value.setFromMatrixPosition( originalLight.matrixWorld ).applyMatrix4( _currentCamera.matrixWorldInverse ); |
|
|
| } else { |
|
|
| uniforms.lightRadius.value = Infinity; |
|
|
| } |
|
|
| updateDeferredLightCommonUniforms( uniforms ); |
|
|
| } |
|
|
| function createDeferredSpotLight( light ) { |
|
|
| var mesh = createDeferredLightMesh( light, new THREE.PlaneBufferGeometry( 2, 2 ) ); |
| mesh.onBeforeRender = updateDeferredSpotLightUniforms; |
| return mesh; |
|
|
| } |
|
|
| function createDeferredSpotLightMaterial() { |
|
|
| var shader = ( _lightPrePass ) ? THREE.ShaderDeferred[ 'spotLightPre' ] : THREE.ShaderDeferred[ 'spotLight' ]; |
|
|
| var material = createDeferredLightShaderMaterial( shader ); |
|
|
| material.depthTest = false; |
|
|
| return material; |
|
|
| } |
|
|
| function updateDeferredSpotLightUniforms( renderer, scene, camera, geometry, material, group ) { |
|
|
| var light = this; |
|
|
| var originalLight = light.userData.originalLight; |
| var uniforms = light.material.uniforms; |
|
|
| uniforms.lightAngle.value = originalLight.angle; |
| uniforms.lightColor.value.copy( originalLight.color ); |
| uniforms.lightIntensity.value = originalLight.intensity; |
| uniforms.lightPositionVS.value.setFromMatrixPosition( originalLight.matrixWorld ).applyMatrix4( _currentCamera.matrixWorldInverse ); |
|
|
| var vec = uniforms.lightDirectionVS.value; |
| var vec2 = _tmpVector3; |
|
|
| vec.setFromMatrixPosition( originalLight.matrixWorld ); |
| vec2.setFromMatrixPosition( originalLight.target.matrixWorld ); |
| vec.sub( vec2 ).normalize().transformDirection( _currentCamera.matrixWorldInverse ); |
|
|
| updateDeferredLightCommonUniforms( uniforms ); |
|
|
| } |
|
|
| function createDeferredDirectionalLight( light ) { |
|
|
| var mesh = createDeferredLightMesh( light, new THREE.PlaneBufferGeometry( 2, 2 ) ); |
| mesh.onBeforeRender = updateDeferredDirectionalLightUniforms; |
| return mesh; |
|
|
| } |
|
|
| function createDeferredDirectionalLightMaterial() { |
|
|
| var shader = ( _lightPrePass ) ? THREE.ShaderDeferred[ 'directionalLightPre' ] : THREE.ShaderDeferred[ 'directionalLight' ]; |
|
|
| var material = createDeferredLightShaderMaterial( shader ); |
|
|
| material.depthTest = false; |
|
|
| return material; |
|
|
| } |
|
|
| function updateDeferredDirectionalLightUniforms( renderer, scene, camera, geometry, material, group ) { |
|
|
| var light = this; |
|
|
| var originalLight = light.userData.originalLight; |
| var uniforms = light.material.uniforms; |
|
|
| uniforms.lightColor.value.copy( originalLight.color ); |
| uniforms.lightIntensity.value = originalLight.intensity; |
|
|
| var vec = uniforms.lightDirectionVS.value; |
| var vec2 = _tmpVector3; |
|
|
| vec.setFromMatrixPosition( originalLight.matrixWorld ); |
| vec2.setFromMatrixPosition( originalLight.target.matrixWorld ); |
| vec.sub( vec2 ).normalize().transformDirection( _currentCamera.matrixWorldInverse ); |
|
|
| updateDeferredLightCommonUniforms( uniforms ); |
|
|
| } |
|
|
| function saveOriginalOnBeforeRenderAndCheckTransparency( object ) { |
|
|
| if ( object.material === undefined ) return; |
|
|
| _originalOnBeforeRendersTable[ object.uuid ] = object.onBeforeRender; |
|
|
| |
| if ( _hasTransparentObject || _lightPrePass ) return; |
|
|
| if ( ! object.visible ) return; |
|
|
| if ( Array.isArray( object.material ) ) { |
|
|
| for ( var i = 0, il = object.material.length; i < il; i ++ ) { |
|
|
| if ( object.material[ i ].visible === true && object.material[ i ].transparent === true ) { |
|
|
| _hasTransparentObject = true; |
| break; |
|
|
| } |
|
|
| } |
|
|
| } else { |
|
|
| if ( object.material.visible === true && object.material.transparent === true ) _hasTransparentObject = true; |
|
|
| } |
|
|
| } |
|
|
| function restoreOriginalOnBeforeRender( object ) { |
|
|
| if ( object.material === undefined ) return; |
|
|
| object.onBeforeRender = _originalOnBeforeRendersTable[ object.uuid ]; |
|
|
| } |
|
|
| function addDeferredLightsToLightScene( object ) { |
|
|
| if ( object.isLight !== true ) return; |
|
|
| var data = _deferredLightsCache[ object.uuid ]; |
|
|
| if ( data === undefined ) { |
|
|
| data = createCacheData(); |
| data.light = createDeferredLight( object ); |
| _deferredLightsCache[ object.uuid ] = data; |
|
|
| } |
|
|
| data.used = true; |
|
|
| var light = data.light; |
|
|
| if ( light === null ) return; |
|
|
| var scene = ( object.isPointLight === true ) ? _lightScene : _lightFullscreenScene; |
|
|
| var lights = scene.userData.lights; |
|
|
| if ( lights[ light.uuid ] === undefined ) { |
|
|
| scene.add( light ); |
|
|
| lights[ light.uuid ] = { |
| light: light, |
| found: true |
| }; |
|
|
| } |
|
|
| lights[ light.uuid ].found = true; |
|
|
| } |
|
|
| function updateDeferredLightsInLightScene( scene ) { |
|
|
| var lights = scene.userData.lights; |
| var keys = Object.keys( lights ); |
|
|
| for ( var i = 0, il = keys.length; i < il; i ++ ) { |
|
|
| var key = keys[ i ]; |
|
|
| if ( lights[ key ].found === false ) { |
|
|
| scene.remove( lights[ key ].light ); |
| delete lights[ key ]; |
|
|
| } else { |
|
|
| var light = lights[ key ].light; |
| light.material = getDeferredLightMaterial( light ); |
|
|
| updateDeferredLight( light ); |
| lights[ key ].found = false; |
|
|
| } |
|
|
| } |
|
|
| } |
|
|
| function updateDeferredCommonUniforms( camera ) { |
|
|
| var uniforms = THREE.ShaderDeferredCommon[ 'commonUniforms' ]; |
|
|
| uniforms.viewWidth.value = _width; |
| uniforms.viewHeight.value = _height; |
|
|
| uniforms.matProjInverse.value.getInverse( camera.projectionMatrix ); |
|
|
| } |
|
|
| function enableFinalPasses() { |
|
|
| if ( _lightPrePass ) { |
|
|
| _passForward.enabled = false; |
| _passCopy.enabled = false; |
|
|
| if ( _antialias ) { |
|
|
| _passFXAA.enabled = true; |
|
|
| } else { |
|
|
| _passFXAA.enabled = false; |
|
|
| } |
|
|
| } else { |
|
|
| if ( _hasTransparentObject ) { |
|
|
| if ( _antialias ) { |
|
|
| _passForward.enabled = true; |
| _passCopy.enabled = false; |
| _passFXAA.enabled = true; |
|
|
| } else { |
|
|
| _passForward.enabled = true; |
| _passCopy.enabled = true; |
| _passFXAA.enabled = false; |
|
|
| } |
|
|
| } else { |
|
|
| if ( _antialias ) { |
|
|
| _passForward.enabled = false; |
| _passCopy.enabled = false; |
| _passFXAA.enabled = true; |
|
|
| } else { |
|
|
| _passForward.enabled = false; |
| _passCopy.enabled = false; |
| _passFXAA.enabled = false; |
|
|
| } |
|
|
| } |
|
|
| } |
|
|
| } |
|
|
| function createCacheData() { |
|
|
| return { |
| used: true, |
| keepAlive: _cacheKeepAlive, |
| count: 0 |
| }; |
|
|
| } |
|
|
| function cleanupCache( cache ) { |
|
|
| var keys = Object.keys( cache ); |
|
|
| for ( var i = 0, il = keys.length; i < il; i ++ ) { |
|
|
| var key = keys[ i ]; |
|
|
| if ( cache[ key ].used === false ) { |
|
|
| cache[ key ].count ++; |
|
|
| if ( cache[ key ].keepAlive === false && cache[ key ].count > _removeThresholdCount ) { |
|
|
| delete cache[ key ]; |
|
|
| } |
|
|
| } else { |
|
|
| cache[ key ].used = false; |
| cache[ key ].count = 0; |
|
|
| } |
|
|
| } |
|
|
| } |
|
|
| function cleanupTable( table ) { |
|
|
| var keys = Object.keys( table ); |
|
|
| for ( var i = 0, il = keys.length; i < il; i ++ ) { |
|
|
| var key = keys[ i ]; |
|
|
| table[ key ] = undefined; |
|
|
| } |
|
|
| } |
|
|
| function cleanupCaches() { |
|
|
| cleanupCache( _lightScenesCache ); |
| cleanupCache( _lightFullscreenScenesCache ); |
| cleanupCache( _normalDepthMaterialsCache ); |
| cleanupCache( _normalDepthShininessMaterialsCache ); |
| cleanupCache( _colorMaterialsCache ); |
| cleanupCache( _reconstructionMaterialsCache ); |
| cleanupCache( _classicDeferredLightMaterialsCache ); |
| cleanupCache( _lightPrePassMaterialsCache ); |
| cleanupCache( _deferredLightsCache ); |
|
|
| cleanupTable( _originalMaterialsTable ); |
| cleanupTable( _originalOnBeforeRendersTable ); |
| cleanupTable( _originalVisibleTable ); |
|
|
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| function renderNormalDepth( scene, camera ) { |
|
|
| scene.traverse( setMaterialNormalDepth ); |
|
|
| _passNormalDepth.scene = scene; |
| _passNormalDepth.camera = camera; |
|
|
| _this.renderer.autoClearDepth = true; |
| _this.renderer.autoClearStencil = true; |
|
|
| _state.buffers.stencil.setTest( true ); |
| _state.buffers.stencil.setFunc( _context.ALWAYS, 1, 0xffffffff ); |
| _state.buffers.stencil.setOp( _context.REPLACE, _context.REPLACE, _context.REPLACE ); |
|
|
| _compNormalDepth.render(); |
|
|
| scene.traverse( restoreOriginalMaterial ); |
|
|
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| function renderColor( scene, camera ) { |
|
|
| scene.traverse( setMaterialColor ); |
|
|
| _passColor.scene = scene; |
| _passColor.camera = camera; |
|
|
| _this.renderer.autoClearDepth = false; |
| _this.renderer.autoClearStencil = false; |
|
|
| _state.buffers.stencil.setFunc( _context.EQUAL, 1, 0xffffffff ); |
| _state.buffers.stencil.setOp( _context.KEEP, _context.KEEP, _context.KEEP ); |
|
|
| _compColor.render(); |
|
|
| scene.traverse( restoreOriginalMaterial ); |
|
|
| } |
|
|
| |
| |
| |
| |
| |
|
|
| function renderLight( scene, camera ) { |
|
|
| scene.traverse( addDeferredLightsToLightScene ); |
|
|
| updateDeferredLightsInLightScene( _lightScene ); |
| updateDeferredLightsInLightScene( _lightFullscreenScene ); |
|
|
| _passLight.scene = _lightScene; |
| _passLight.camera = camera; |
|
|
| _passLightFullscreen.scene = _lightFullscreenScene; |
|
|
| _this.renderer.autoClearDepth = false; |
| _this.renderer.autoClearStencil = false; |
|
|
| _compLight.render(); |
|
|
| _state.buffers.stencil.setTest( false ); |
|
|
| } |
|
|
| |
| |
| |
| |
| |
|
|
| function renderLightPre( scene, camera ) { |
|
|
| scene.traverse( addDeferredLightsToLightScene ); |
|
|
| updateDeferredLightsInLightScene( _lightScene ); |
| updateDeferredLightsInLightScene( _lightFullscreenScene ); |
|
|
| _passLight.scene = _lightScene; |
| _passLight.camera = camera; |
|
|
| _passLightFullscreen.scene = _lightFullscreenScene; |
|
|
| _this.renderer.autoClearDepth = false; |
| _this.renderer.autoClearStencil = false; |
|
|
| _state.buffers.stencil.setFunc( _context.EQUAL, 1, 0xffffffff ); |
| _state.buffers.stencil.setOp( _context.KEEP, _context.KEEP, _context.KEEP ); |
|
|
| _compLight.render(); |
|
|
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| function renderReconstruction( scene, camera ) { |
|
|
| scene.traverse( setMaterialReconstruction ); |
|
|
| _passReconstruction.scene = scene; |
| _passReconstruction.camera = camera; |
|
|
| _this.renderer.autoClearDepth = false; |
| _this.renderer.autoClearStencil = false; |
|
|
| _compReconstruction.render(); |
|
|
| _state.buffers.stencil.setTest( false ); |
|
|
| scene.traverse( restoreOriginalMaterial ); |
|
|
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| function renderFinal( scene, camera ) { |
|
|
| if ( ! _lightPrePass && _hasTransparentObject ) { |
|
|
| scene.traverse( setVisibleForForwardRendering ); |
| scene.traverse( restoreOriginalOnBeforeRender ); |
|
|
| _passForward.scene = scene; |
| _passForward.camera = camera; |
|
|
| } |
|
|
| enableFinalPasses(); |
|
|
| _this.renderer.autoClearDepth = false; |
| _this.renderer.autoClearStencil = false; |
|
|
| _compFinal.render(); |
|
|
| if ( ! _lightPrePass && _hasTransparentObject ) { |
|
|
| scene.traverse( restoreVisible ); |
|
|
| } |
|
|
| } |
|
|
| |
|
|
| this.setSize = function ( width, height ) { |
|
|
| _width = width; |
| _height = height; |
|
|
| this.renderer.setSize( _width, _height ); |
|
|
| _compNormalDepth.setSize( _width, _height ); |
| _compColor.setSize( _width, _height ); |
| _compLight.setSize( _width, _height ); |
| _compReconstruction.setSize( _width, _height ); |
| _compFinal.setSize( _width, _height ); |
|
|
| _depthTexture.image.width = _width; |
| _depthTexture.image.height = _height; |
| _depthTexture.needsUpdate = true; |
|
|
| _passFXAA.uniforms.resolution.value.set( 1 / _width, 1 / _height ); |
|
|
| }; |
|
|
| this.setAntialias = function ( enabled ) { |
|
|
| _antialias = enabled; |
|
|
| }; |
|
|
| this.enableLightPrePass = function ( enabled ) { |
|
|
| _lightPrePass = enabled; |
|
|
| _passFinal.uniforms.samplerResult.value = ( _lightPrePass ) ? _compReconstruction.renderTarget2.texture : _compLight.renderTarget2.texture; |
|
|
| }; |
|
|
| this.render = function ( scene, camera ) { |
|
|
| |
|
|
| if ( this.forwardRendering ) { |
|
|
| this.renderer.render( scene, camera ); |
| return; |
|
|
| } |
|
|
| var currentSceneAutoUpdate = scene.autoUpdate; |
| var currentAutoClearColor = this.renderer.autoClearColor; |
| var currentAutoClearDepth = this.renderer.autoClearDepth; |
| var currentAutoClearStencil = this.renderer.autoClearStencil; |
|
|
| _currentCamera = camera; |
|
|
| initLightScene( scene ); |
|
|
| scene.autoUpdate = false; |
| scene.updateMatrixWorld(); |
|
|
| _hasTransparentObject = false; |
|
|
| scene.traverse( saveOriginalOnBeforeRenderAndCheckTransparency ); |
|
|
| updateDeferredCommonUniforms( camera ); |
|
|
| renderNormalDepth( scene, camera ); |
|
|
| if ( _lightPrePass ) { |
|
|
| renderLightPre( scene, camera ); |
| renderReconstruction( scene, camera ); |
|
|
| } else { |
|
|
| renderColor( scene, camera ); |
| renderLight( scene, camera ); |
|
|
| } |
|
|
| renderFinal( scene, camera ); |
|
|
| scene.traverse( restoreOriginalOnBeforeRender ); |
|
|
| cleanupCaches(); |
|
|
| scene.autoUpdate = currentSceneAutoUpdate; |
| this.renderer.autoClearColor = currentAutoClearColor; |
| this.renderer.autoClearDepth = currentAutoClearDepth; |
| this.renderer.autoClearStencil = currentAutoClearStencil; |
|
|
| }; |
|
|
| |
|
|
| init( parameters ); |
|
|
| }; |
|
|
| THREE.DeferredShaderChunk = { |
|
|
| packVector3: [ |
|
|
| "float vec3_to_float( vec3 data ) {", |
|
|
| " const float unit = 255.0/256.0;", |
| " highp float compressed = fract( data.x * unit ) + floor( data.y * unit * 255.0 ) + floor( data.z * unit * 255.0 ) * 255.0;", |
| " return compressed;", |
|
|
| "}" |
|
|
| ].join( "\n" ), |
|
|
| unpackFloat: [ |
|
|
| "vec3 float_to_vec3( float data ) {", |
|
|
| " const float unit = 255.0;", |
| " vec3 uncompressed;", |
| " uncompressed.x = fract( data );", |
| " float zInt = floor( data / unit );", |
| " uncompressed.z = fract( zInt / unit );", |
| " uncompressed.y = fract( floor( data - ( zInt * unit ) ) / unit );", |
| " return uncompressed;", |
|
|
| "}" |
|
|
| ].join( "\n" ), |
|
|
| |
| packNormal: [ |
|
|
| "vec2 normal_to_vec2( vec3 normal ) {", |
|
|
| " return normal.xy / sqrt( normal.z * 8.0 + 8.0 ) + 0.5;", |
|
|
| "}" |
|
|
| ].join( "\n" ), |
|
|
| unpackVector2: [ |
|
|
| "vec3 vec2_to_normal( vec2 data ) {", |
|
|
| " vec2 fenc = data * 4.0 - 2.0;", |
| " float f = dot( fenc, fenc );", |
| " float g = sqrt( 1.0 - f / 4.0 );", |
| " vec3 normal;", |
| " normal.xy = fenc * g;", |
| " normal.z = 1.0 - f / 2.0;", |
| " return normal;", |
|
|
| "}" |
|
|
| ].join( "\n" ), |
|
|
| computeTextureCoord: [ |
|
|
| "vec2 texCoord = gl_FragCoord.xy / vec2( viewWidth, viewHeight );" |
|
|
| ].join( "\n" ), |
|
|
| packNormalDepth: [ |
|
|
| "vec4 packedNormalDepth;", |
| "packedNormalDepth.xyz = normal * 0.5 + 0.5;", |
| "packedNormalDepth.w = position.z / position.w;" |
|
|
| ].join( "\n" ), |
|
|
| unpackNormalDepth: [ |
|
|
| "vec4 normalDepthMap = texture2D( samplerNormalDepth, texCoord );", |
| "float depth = normalDepthMap.w;", |
|
|
| "if ( depth == 0.0 ) discard;", |
|
|
| "vec3 normal = normalDepthMap.xyz * 2.0 - 1.0;" |
|
|
| ].join( "\n" ), |
|
|
| packNormalDepthShininess: [ |
|
|
| "vec4 packedNormalDepthShininess;", |
| "packedNormalDepthShininess.xy = normal_to_vec2( normal );", |
| "packedNormalDepthShininess.z = shininess;", |
| "packedNormalDepthShininess.w = position.z / position.w;" |
|
|
| ].join( "\n" ), |
|
|
| unpackNormalDepthShininess: [ |
|
|
| "vec4 normalDepthMap = texture2D( samplerNormalDepthShininess, texCoord );", |
| "float depth = normalDepthMap.w;", |
|
|
| "if ( depth == 0.0 ) discard;", |
|
|
| "vec3 normal = vec2_to_normal( normalDepthMap.xy );", |
| "float shininess = normalDepthMap.z;" |
|
|
| ].join( "\n" ), |
|
|
| packColor: [ |
|
|
| "vec4 packedColor;", |
| "packedColor.x = vec3_to_float( diffuseColor.rgb );", |
| "packedColor.y = vec3_to_float( emissiveColor );", |
| "packedColor.z = vec3_to_float( specularColor );", |
| "packedColor.w = shininess;" |
|
|
| ].join( "\n" ), |
|
|
| unpackColor: [ |
|
|
| "vec4 colorMap = texture2D( samplerColor, texCoord );", |
| "vec3 diffuseColor = float_to_vec3( colorMap.x );", |
| "vec3 emissiveColor = float_to_vec3( colorMap.y );", |
| "vec3 specularColor = float_to_vec3( colorMap.z );", |
| "float shininess = colorMap.w;" |
|
|
| ].join( "\n" ), |
|
|
| packLight: [ |
|
|
| "vec4 packedLight;", |
| "packedLight.xyz = lightIntensity * lightColor * max( dot( lightVector, normal ), 0.0 ) * attenuation;", |
| "packedLight.w = lightIntensity * specular * max( dot( lightVector, normal ), 0.0 ) * attenuation;" |
|
|
| ].join( "\n" ), |
|
|
| computeVertexPositionVS: [ |
|
|
| "vec2 xy = texCoord * 2.0 - 1.0;", |
| "vec4 vertexPositionProjected = vec4( xy, depth, 1.0 );", |
| "vec4 vertexPositionVS = matProjInverse * vertexPositionProjected;", |
| "vertexPositionVS.xyz /= vertexPositionVS.w;", |
| "vertexPositionVS.w = 1.0;" |
|
|
| ].join( "\n" ), |
|
|
| |
| computeSpecular: [ |
|
|
| "vec3 halfVector = normalize( lightVector - normalize( vertexPositionVS.xyz ) );", |
| "float dotNormalHalf = max( dot( normal, halfVector ), 0.0 );", |
| "float specular = 0.31830988618 * ( shininess * 0.5 + 1.0 ) * pow( dotNormalHalf, shininess );" |
|
|
| ].join( "\n" ), |
|
|
| combine: [ |
|
|
| "gl_FragColor = vec4( lightIntensity * lightColor * max( dot( lightVector, normal ), 0.0 ) * ( diffuseColor + specular * specularColor ) * attenuation, 1.0 );" |
|
|
| ].join( "\n" ) |
|
|
| }; |
|
|
| THREE.ShaderDeferredCommon = { |
|
|
| commonUniforms: { |
|
|
| matProjInverse: new THREE.Uniform( new THREE.Matrix4() ), |
|
|
| viewWidth: new THREE.Uniform( 800 ), |
| viewHeight: new THREE.Uniform( 600 ) |
|
|
| } |
|
|
| }; |
|
|
| THREE.ShaderDeferred = { |
|
|
| normalDepth: { |
|
|
| uniforms: {}, |
|
|
| vertexShader: [ |
|
|
| "varying vec3 vNormal;", |
| "varying vec4 vPosition;", |
|
|
| "#include <morphtarget_pars_vertex>", |
| "#include <skinning_pars_vertex>", |
|
|
| "void main() {", |
|
|
| "#include <begin_vertex>", |
| "#include <beginnormal_vertex>", |
| "#include <skinbase_vertex>", |
| "#include <skinnormal_vertex>", |
| "#include <defaultnormal_vertex>", |
| "#include <morphtarget_vertex>", |
| "#include <skinning_vertex>", |
| "#include <project_vertex>", |
|
|
| " vNormal = normalize( transformedNormal );", |
| " vPosition = gl_Position;", |
|
|
| "}" |
|
|
| ].join( "\n" ), |
|
|
| fragmentShader: [ |
|
|
| "varying vec3 vNormal;", |
| "varying vec4 vPosition;", |
|
|
| "void main() {", |
|
|
| " vec3 normal = vNormal;", |
| " vec4 position = vPosition;", |
|
|
| THREE.DeferredShaderChunk[ "packNormalDepth" ], |
|
|
| " gl_FragColor = packedNormalDepth;", |
|
|
| "}" |
|
|
| ].join( "\n" ) |
|
|
| }, |
|
|
| color: { |
|
|
| uniforms: { |
|
|
| map: new THREE.Uniform( null ), |
| offsetRepeat: new THREE.Uniform( new THREE.Vector4( 0, 0, 1, 1 ) ), |
|
|
| diffuse: new THREE.Uniform( new THREE.Color( 0x000000 ) ), |
| emissive: new THREE.Uniform( new THREE.Color( 0x000000 ) ), |
| specular: new THREE.Uniform( new THREE.Color( 0x000000 ) ), |
| shininess: new THREE.Uniform( 30.0 ) |
|
|
| }, |
|
|
| vertexShader: [ |
|
|
| "#include <uv_pars_vertex>", |
| "#include <morphtarget_pars_vertex>", |
| "#include <skinning_pars_vertex>", |
|
|
| "void main() {", |
|
|
| "#include <uv_vertex>", |
| "#include <begin_vertex>", |
| "#include <beginnormal_vertex>", |
| "#include <skinbase_vertex>", |
| "#include <skinnormal_vertex>", |
| "#include <defaultnormal_vertex>", |
| "#include <morphtarget_vertex>", |
| "#include <skinning_vertex>", |
| "#include <project_vertex>", |
|
|
| "}" |
|
|
| ].join( "\n" ), |
|
|
| fragmentShader: [ |
|
|
| "uniform vec3 diffuse;", |
| "uniform vec3 emissive;", |
| "uniform vec3 specular;", |
| "uniform float shininess;", |
|
|
| "#include <uv_pars_fragment>", |
| "#include <map_pars_fragment>", |
| THREE.DeferredShaderChunk[ "packVector3" ], |
|
|
| "void main() {", |
|
|
| " vec4 diffuseColor = vec4( diffuse, 1.0 );", |
| " vec3 emissiveColor = emissive;", |
| " vec3 specularColor = specular;", |
|
|
| "#include <map_fragment>", |
| THREE.DeferredShaderChunk[ "packColor" ], |
|
|
| " gl_FragColor = packedColor;", |
|
|
| "}" |
|
|
| ].join( "\n" ) |
|
|
| }, |
|
|
| emissiveLight: { |
|
|
| uniforms: Object.assign( |
|
|
| { |
|
|
| samplerColor: new THREE.Uniform( null ) |
|
|
| }, |
|
|
| THREE.ShaderDeferredCommon[ 'commonUniforms' ] |
|
|
| ), |
|
|
| vertexShader: [ |
|
|
| "void main() { ", |
|
|
| " gl_Position = vec4( sign( position.xy ), 0.0, 1.0 );", |
|
|
| "}" |
|
|
| ].join( '\n' ), |
|
|
| fragmentShader: [ |
|
|
| "uniform sampler2D samplerColor;", |
|
|
| "uniform float viewHeight;", |
| "uniform float viewWidth;", |
|
|
| THREE.DeferredShaderChunk[ "unpackFloat" ], |
|
|
| "void main() {", |
|
|
| THREE.DeferredShaderChunk[ "computeTextureCoord" ], |
| THREE.DeferredShaderChunk[ "unpackColor" ], |
|
|
| " gl_FragColor = vec4( emissiveColor, 1.0 );", |
|
|
| "}" |
|
|
| ].join( '\n' ) |
|
|
| }, |
|
|
| pointLight: { |
|
|
| uniforms: Object.assign( |
|
|
| { |
|
|
| samplerNormalDepth: new THREE.Uniform( null ), |
| samplerColor: new THREE.Uniform( null ), |
|
|
| lightColor: new THREE.Uniform( new THREE.Color( 0x000000 ) ), |
| lightPositionVS: new THREE.Uniform( new THREE.Vector3( 0, 1, 0 ) ), |
| lightIntensity: new THREE.Uniform( 1.0 ), |
| lightRadius: new THREE.Uniform( 1.0 ) |
|
|
| }, |
|
|
| THREE.ShaderDeferredCommon[ 'commonUniforms' ] |
|
|
| ), |
|
|
| vertexShader: [ |
|
|
| "void main() {", |
|
|
| " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", |
|
|
| "}" |
|
|
| ].join( "\n" ), |
|
|
| fragmentShader: [ |
|
|
| "uniform sampler2D samplerNormalDepth;", |
| "uniform sampler2D samplerColor;", |
|
|
| "uniform float viewHeight;", |
| "uniform float viewWidth;", |
|
|
| "uniform vec3 lightColor;", |
| "uniform vec3 lightPositionVS;", |
| "uniform float lightIntensity;", |
| "uniform float lightRadius;", |
|
|
| "uniform mat4 matProjInverse;", |
|
|
| THREE.DeferredShaderChunk[ "unpackFloat" ], |
|
|
| "void main() {", |
|
|
| THREE.DeferredShaderChunk[ "computeTextureCoord" ], |
| THREE.DeferredShaderChunk[ "unpackNormalDepth" ], |
| THREE.DeferredShaderChunk[ "computeVertexPositionVS" ], |
|
|
| " vec3 lightVector = lightPositionVS - vertexPositionVS.xyz;", |
| " float distance = length( lightVector );", |
|
|
| " if ( distance > lightRadius ) discard;", |
|
|
| " lightVector = normalize( lightVector );", |
|
|
| THREE.DeferredShaderChunk[ "unpackColor" ], |
| THREE.DeferredShaderChunk[ "computeSpecular" ], |
|
|
| " //float cutoff = 0.3;", |
| " //float denom = distance / lightRadius + 1.0;", |
| " //float attenuation = 1.0 / ( denom * denom );", |
| " //attenuation = ( attenuation - cutoff ) / ( 1.0 - cutoff );", |
| " //attenuation = max( attenuation, 0.0 );", |
| " //attenuation *= attenuation;", |
|
|
| " //diffuseColor *= saturate( -distance / lightRadius + 1.0 );", |
| " //float attenuation = 1.0;", |
|
|
| " float attenuation = saturate( -distance / lightRadius + 1.0 );", |
|
|
| THREE.DeferredShaderChunk[ "combine" ], |
|
|
| "}" |
|
|
| ].join( "\n" ) |
|
|
| }, |
|
|
| spotLight: { |
|
|
| uniforms: Object.assign( |
|
|
| { |
|
|
| samplerNormalDepth: new THREE.Uniform( null ), |
| samplerColor: new THREE.Uniform( null ), |
|
|
| lightColor: new THREE.Uniform( new THREE.Color( 0x000000 ) ), |
| lightDirectionVS: new THREE.Uniform( new THREE.Vector3( 0, 1, 0 ) ), |
| lightPositionVS: new THREE.Uniform( new THREE.Vector3( 0, 1, 0 ) ), |
| lightAngle: new THREE.Uniform( 1.0 ), |
| lightIntensity: new THREE.Uniform( 1.0 ) |
|
|
| }, |
|
|
| THREE.ShaderDeferredCommon[ 'commonUniforms' ] |
|
|
| ), |
|
|
| vertexShader: [ |
|
|
| "void main() { ", |
|
|
| " gl_Position = vec4( sign( position.xy ), 0.0, 1.0 );", |
|
|
| "}" |
|
|
| ].join( "\n" ), |
|
|
| fragmentShader: [ |
|
|
| "uniform sampler2D samplerNormalDepth;", |
| "uniform sampler2D samplerColor;", |
|
|
| "uniform float viewHeight;", |
| "uniform float viewWidth;", |
|
|
| "uniform vec3 lightColor;", |
| "uniform vec3 lightPositionVS;", |
| "uniform vec3 lightDirectionVS;", |
| "uniform float lightAngle;", |
| "uniform float lightIntensity;", |
|
|
| "uniform mat4 matProjInverse;", |
|
|
| THREE.DeferredShaderChunk[ "unpackFloat" ], |
|
|
| "void main() {", |
|
|
| THREE.DeferredShaderChunk[ "computeTextureCoord" ], |
| THREE.DeferredShaderChunk[ "unpackNormalDepth" ], |
| THREE.DeferredShaderChunk[ "computeVertexPositionVS" ], |
| THREE.DeferredShaderChunk[ "unpackColor" ], |
|
|
| " vec3 lightVector = normalize( lightPositionVS.xyz - vertexPositionVS.xyz );", |
|
|
| " float rho = dot( lightDirectionVS, lightVector );", |
| " float rhoMax = cos( lightAngle );", |
|
|
| " if ( rho <= rhoMax ) discard;", |
|
|
| " float theta = rhoMax + 0.0001;", |
| " float phi = rhoMax + 0.05;", |
| " float falloff = 4.0;", |
|
|
| " float spot = 0.0;", |
|
|
| " if ( rho >= phi ) {", |
|
|
| " spot = 1.0;", |
|
|
| " } else if ( rho <= theta ) {", |
|
|
| " spot = 0.0;", |
|
|
| " } else { ", |
|
|
| " spot = pow( ( rho - theta ) / ( phi - theta ), falloff );", |
|
|
| " }", |
|
|
| " diffuseColor *= spot;", |
|
|
| THREE.DeferredShaderChunk[ "computeSpecular" ], |
|
|
| " const float attenuation = 1.0;", |
|
|
| THREE.DeferredShaderChunk[ "combine" ], |
|
|
| "}" |
|
|
| ].join( "\n" ) |
|
|
| }, |
|
|
| directionalLight: { |
|
|
| uniforms: Object.assign( |
|
|
| { |
|
|
| samplerNormalDepth: new THREE.Uniform( null ), |
| samplerColor: new THREE.Uniform( null ), |
|
|
| lightColor: new THREE.Uniform( new THREE.Color( 0x000000 ) ), |
| lightDirectionVS: new THREE.Uniform( new THREE.Vector3( 0, 1, 0 ) ), |
| lightIntensity: new THREE.Uniform( 1.0 ) |
| }, |
|
|
| THREE.ShaderDeferredCommon[ 'commonUniforms' ] |
|
|
| ), |
|
|
| vertexShader: [ |
|
|
| "void main() { ", |
|
|
| " gl_Position = vec4( sign( position.xy ), 0.0, 1.0 );", |
|
|
| "}" |
|
|
| ].join( '\n' ), |
|
|
| fragmentShader: [ |
|
|
| "uniform sampler2D samplerNormalDepth;", |
| "uniform sampler2D samplerColor;", |
|
|
| "uniform float viewHeight;", |
| "uniform float viewWidth;", |
|
|
| "uniform vec3 lightColor;", |
| "uniform vec3 lightDirectionVS;", |
| "uniform float lightIntensity;", |
|
|
| "uniform mat4 matProjInverse;", |
|
|
| THREE.DeferredShaderChunk[ "unpackFloat" ], |
|
|
| "void main() {", |
|
|
| THREE.DeferredShaderChunk[ "computeTextureCoord" ], |
| THREE.DeferredShaderChunk[ "unpackNormalDepth" ], |
| THREE.DeferredShaderChunk[ "computeVertexPositionVS" ], |
| THREE.DeferredShaderChunk[ "unpackColor" ], |
|
|
| " vec3 lightVector = normalize( lightDirectionVS );", |
|
|
| THREE.DeferredShaderChunk[ "computeSpecular" ], |
|
|
| " const float attenuation = 1.0;", |
|
|
| THREE.DeferredShaderChunk[ "combine" ], |
|
|
| "}" |
|
|
| ].join( '\n' ) |
|
|
| }, |
|
|
| normalDepthShininess: { |
|
|
| uniforms: { |
|
|
| shininess: new THREE.Uniform( 30.0 ) |
|
|
| }, |
|
|
| vertexShader: [ |
|
|
| "varying vec3 vNormal;", |
| "varying vec4 vPosition;", |
|
|
| "#include <morphtarget_pars_vertex>", |
| "#include <skinning_pars_vertex>", |
|
|
| "void main() {", |
|
|
| "#include <begin_vertex>", |
| "#include <beginnormal_vertex>", |
| "#include <skinbase_vertex>", |
| "#include <skinnormal_vertex>", |
| "#include <defaultnormal_vertex>", |
| "#include <morphtarget_vertex>", |
| "#include <skinning_vertex>", |
| "#include <project_vertex>", |
|
|
| " vNormal = normalize( transformedNormal );", |
| " vPosition = gl_Position;", |
|
|
| "}" |
|
|
| ].join( "\n" ), |
|
|
| fragmentShader: [ |
|
|
| "varying vec3 vNormal;", |
| "varying vec4 vPosition;", |
|
|
| "uniform float shininess;", |
|
|
| THREE.DeferredShaderChunk[ "packNormal" ], |
|
|
| "void main() {", |
|
|
| " vec3 normal = vNormal;", |
| " vec4 position = vPosition;", |
|
|
| THREE.DeferredShaderChunk[ "packNormalDepthShininess" ], |
|
|
| " gl_FragColor = packedNormalDepthShininess;", |
|
|
| "}" |
|
|
| ].join( "\n" ) |
|
|
| }, |
|
|
| pointLightPre: { |
|
|
| uniforms: Object.assign( |
|
|
| { |
|
|
| samplerNormalDepthShininess: new THREE.Uniform( null ), |
|
|
| lightColor: new THREE.Uniform( new THREE.Color( 0x000000 ) ), |
| lightPositionVS: new THREE.Uniform( new THREE.Vector3( 0, 1, 0 ) ), |
| lightIntensity: new THREE.Uniform( 1.0 ), |
| lightRadius: new THREE.Uniform( 1.0 ) |
| }, |
|
|
| THREE.ShaderDeferredCommon[ 'commonUniforms' ] |
|
|
| ), |
|
|
|
|
| vertexShader: [ |
|
|
| "void main() {", |
|
|
| " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", |
|
|
| "}" |
|
|
| ].join( "\n" ), |
|
|
| fragmentShader: [ |
|
|
| "uniform sampler2D samplerNormalDepthShininess;", |
|
|
| "uniform float viewHeight;", |
| "uniform float viewWidth;", |
|
|
| "uniform vec3 lightColor;", |
| "uniform vec3 lightPositionVS;", |
| "uniform float lightIntensity;", |
| "uniform float lightRadius;", |
|
|
| "uniform mat4 matProjInverse;", |
|
|
| THREE.DeferredShaderChunk[ "unpackFloat" ], |
| THREE.DeferredShaderChunk[ "unpackVector2" ], |
|
|
| "void main() {", |
|
|
| THREE.DeferredShaderChunk[ "computeTextureCoord" ], |
| THREE.DeferredShaderChunk[ "unpackNormalDepthShininess" ], |
| THREE.DeferredShaderChunk[ "computeVertexPositionVS" ], |
|
|
| " vec3 lightVector = lightPositionVS - vertexPositionVS.xyz;", |
| " float distance = length( lightVector );", |
|
|
| " if ( distance > lightRadius ) discard;", |
|
|
| " lightVector = normalize( lightVector );", |
|
|
| THREE.DeferredShaderChunk[ "computeSpecular" ], |
|
|
| " float attenuation = saturate( -distance / lightRadius + 1.0 );", |
|
|
| THREE.DeferredShaderChunk[ "packLight" ], |
|
|
| " gl_FragColor = packedLight;", |
|
|
| "}" |
|
|
| ].join( "\n" ) |
|
|
| }, |
|
|
| spotLightPre: { |
|
|
| uniforms: Object.assign( |
|
|
| { |
|
|
| samplerNormalDepthShininess: new THREE.Uniform( null ), |
|
|
| lightColor: new THREE.Uniform( new THREE.Color( 0x000000 ) ), |
| lightDirectionVS: new THREE.Uniform( new THREE.Vector3( 0, 1, 0 ) ), |
| lightPositionVS: new THREE.Uniform( new THREE.Vector3( 0, 1, 0 ) ), |
| lightAngle: new THREE.Uniform( 1.0 ), |
| lightIntensity: new THREE.Uniform( 1.0 ) |
|
|
| }, |
|
|
| THREE.ShaderDeferredCommon[ 'commonUniforms' ] |
|
|
| ), |
|
|
| vertexShader: [ |
|
|
| "void main() { ", |
|
|
| " gl_Position = vec4( sign( position.xy ), 0.0, 1.0 );", |
|
|
| "}" |
|
|
| ].join( "\n" ), |
|
|
| fragmentShader: [ |
|
|
| "uniform sampler2D samplerNormalDepthShininess;", |
|
|
| "uniform float viewHeight;", |
| "uniform float viewWidth;", |
|
|
| "uniform vec3 lightColor;", |
| "uniform vec3 lightPositionVS;", |
| "uniform vec3 lightDirectionVS;", |
| "uniform float lightAngle;", |
| "uniform float lightIntensity;", |
|
|
| "uniform mat4 matProjInverse;", |
|
|
| THREE.DeferredShaderChunk[ "unpackFloat" ], |
| THREE.DeferredShaderChunk[ "unpackVector2" ], |
|
|
| "void main() {", |
|
|
| THREE.DeferredShaderChunk[ "computeTextureCoord" ], |
| THREE.DeferredShaderChunk[ "unpackNormalDepthShininess" ], |
| THREE.DeferredShaderChunk[ "computeVertexPositionVS" ], |
|
|
| " vec3 lightVector = normalize( lightPositionVS.xyz - vertexPositionVS.xyz );", |
|
|
| " float rho = dot( lightDirectionVS, lightVector );", |
| " float rhoMax = cos( lightAngle );", |
|
|
| " if ( rho <= rhoMax ) discard;", |
|
|
| " float theta = rhoMax + 0.0001;", |
| " float phi = rhoMax + 0.05;", |
| " float falloff = 4.0;", |
|
|
| " float spot = 0.0;", |
|
|
| " if ( rho >= phi ) {", |
|
|
| " spot = 1.0;", |
|
|
| " } else if ( rho <= theta ) {", |
|
|
| " spot = 0.0;", |
|
|
| " } else { ", |
|
|
| " spot = pow( ( rho - theta ) / ( phi - theta ), falloff );", |
|
|
| " }", |
|
|
| THREE.DeferredShaderChunk[ "computeSpecular" ], |
|
|
| " const float attenuation = 1.0;", |
|
|
| THREE.DeferredShaderChunk[ "packLight" ], |
|
|
| " gl_FragColor = spot * packedLight;", |
|
|
| "}" |
|
|
| ].join( "\n" ) |
|
|
| }, |
|
|
| directionalLightPre: { |
|
|
| uniforms: Object.assign( |
|
|
| { |
|
|
| samplerNormalDepthShininess: new THREE.Uniform( null ), |
|
|
| lightColor: new THREE.Uniform( new THREE.Color( 0x000000 ) ), |
| lightDirectionVS: new THREE.Uniform( new THREE.Vector3( 0, 1, 0 ) ), |
| lightIntensity: new THREE.Uniform( 1.0 ) |
|
|
| }, |
|
|
| THREE.ShaderDeferredCommon[ 'commonUniforms' ] |
|
|
| ), |
|
|
| vertexShader: [ |
|
|
| "void main() { ", |
|
|
| " gl_Position = vec4( sign( position.xy ), 0.0, 1.0 );", |
|
|
| "}" |
|
|
| ].join( '\n' ), |
|
|
| fragmentShader: [ |
|
|
| "uniform sampler2D samplerNormalDepthShininess;", |
|
|
| "uniform float viewHeight;", |
| "uniform float viewWidth;", |
|
|
| "uniform vec3 lightColor;", |
| "uniform vec3 lightDirectionVS;", |
| "uniform float lightIntensity;", |
|
|
| "uniform mat4 matProjInverse;", |
|
|
| THREE.DeferredShaderChunk[ "unpackFloat" ], |
| THREE.DeferredShaderChunk[ "unpackVector2" ], |
|
|
| "void main() {", |
|
|
| THREE.DeferredShaderChunk[ "computeTextureCoord" ], |
| THREE.DeferredShaderChunk[ "unpackNormalDepthShininess" ], |
| THREE.DeferredShaderChunk[ "computeVertexPositionVS" ], |
|
|
| " vec3 lightVector = normalize( lightDirectionVS );", |
|
|
| THREE.DeferredShaderChunk[ "computeSpecular" ], |
|
|
| " const float attenuation = 1.0;", |
|
|
| THREE.DeferredShaderChunk[ "packLight" ], |
|
|
| " gl_FragColor = packedLight;", |
|
|
| "}" |
|
|
| ].join( '\n' ) |
|
|
| }, |
|
|
| reconstruction: { |
|
|
| uniforms: Object.assign( |
|
|
| { |
|
|
| samplerLight: new THREE.Uniform( null ), |
|
|
| map: new THREE.Uniform( null ), |
| offsetRepeat: new THREE.Uniform( new THREE.Vector4( 0, 0, 1, 1 ) ), |
|
|
| diffuse: new THREE.Uniform( new THREE.Color( 0x000000 ) ), |
| emissive: new THREE.Uniform( new THREE.Color( 0x000000 ) ), |
| specular: new THREE.Uniform( new THREE.Color( 0x000000 ) ), |
| shininess: new THREE.Uniform( 30.0 ) |
|
|
| }, |
|
|
| THREE.ShaderDeferredCommon[ 'commonUniforms' ] |
|
|
| ), |
|
|
| vertexShader: [ |
|
|
| "#include <uv_pars_vertex>", |
| "#include <morphtarget_pars_vertex>", |
| "#include <skinning_pars_vertex>", |
|
|
| "void main() {", |
|
|
| "#include <uv_vertex>", |
| "#include <begin_vertex>", |
| "#include <beginnormal_vertex>", |
| "#include <skinbase_vertex>", |
| "#include <skinnormal_vertex>", |
| "#include <defaultnormal_vertex>", |
| "#include <morphtarget_vertex>", |
| "#include <skinning_vertex>", |
| "#include <project_vertex>", |
|
|
| "}" |
|
|
| ].join( "\n" ), |
|
|
| fragmentShader: [ |
|
|
| "uniform sampler2D samplerLight;", |
|
|
| "uniform vec3 diffuse;", |
| "uniform vec3 emissive;", |
| "uniform vec3 specular;", |
| "uniform float shininess;", |
|
|
| "uniform float viewHeight;", |
| "uniform float viewWidth;", |
|
|
| "#include <uv_pars_fragment>", |
| "#include <map_pars_fragment>", |
|
|
| THREE.DeferredShaderChunk[ "unpackFloat" ], |
|
|
| "void main() {", |
|
|
| " vec4 diffuseColor = vec4( diffuse, 1.0 );", |
| " vec3 emissiveColor = emissive;", |
| " vec3 specularColor = specular;", |
|
|
| THREE.DeferredShaderChunk[ "computeTextureCoord" ], |
|
|
| " vec4 light = texture2D( samplerLight, texCoord );", |
|
|
| "#include <map_fragment>", |
|
|
| " vec3 diffuseFinal = diffuseColor.rgb * light.rgb;", |
| " vec3 emissiveFinal = emissiveColor;", |
| " vec3 specularFinal = specularColor * light.rgb * light.a;", |
|
|
| " gl_FragColor = vec4( diffuseFinal + emissiveFinal + specularFinal, 1.0 );", |
|
|
| "}" |
|
|
| ].join( "\n" ) |
|
|
| }, |
|
|
| |
| final: { |
|
|
| uniforms: { |
|
|
| samplerResult: new THREE.Uniform( null ) |
|
|
| }, |
|
|
| vertexShader: [ |
|
|
| "varying vec2 texCoord;", |
|
|
| "void main() {", |
|
|
| " vec4 pos = vec4( sign( position.xy ), 0.0, 1.0 );", |
| " texCoord = pos.xy * vec2( 0.5 ) + 0.5;", |
| " gl_Position = pos;", |
|
|
| "}" |
|
|
| ].join( "\n" ), |
|
|
| fragmentShader: [ |
|
|
| "varying vec2 texCoord;", |
| "uniform sampler2D samplerResult;", |
|
|
| "void main() {", |
|
|
| " gl_FragColor = texture2D( samplerResult, texCoord );", |
|
|
| "}" |
|
|
| ].join( "\n" ) |
|
|
| } |
|
|
| }; |
|
|