From 926f1be28ff5de097029d177dec8867411e439ec Mon Sep 17 00:00:00 2001 From: Mikael Emtinger Date: Thu, 24 Mar 2011 17:51:28 +0100 Subject: [PATCH] Initial add of lens flare --- src/lights/LensFlare.js | 53 +++++++ src/renderers/WebGLRenderer.js | 269 ++++++++++++++++++--------------- 2 files changed, 204 insertions(+), 118 deletions(-) create mode 100644 src/lights/LensFlare.js diff --git a/src/lights/LensFlare.js b/src/lights/LensFlare.js new file mode 100644 index 0000000000..274706d995 --- /dev/null +++ b/src/lights/LensFlare.js @@ -0,0 +1,53 @@ +/** + * @author Mikael Emtinger + */ + +THREE.LensFlare = function ( material, size ) { + + THREE.Object3D.call( this ); + + this.positionScreen = new THREE.Vector3(); + this.lensFlares = []; + this.customUpdateCallback = undefined; + + this.addLensFlare( material, size, 0 ); +}; + +THREE.LensFlare.prototype = new THREE.Object3D(); +THREE.LensFlare.prototype.constructor = THREE.LensFlare; +THREE.LensFlare.prototype.supr = THREE.Object3D.prototype; + + +/* + * Add: adds another flare + */ + +THREE.LensFlare.prototype.add = function( material, size, distance ) { + + distance = Math.min( distance, Math.max( 0, distance )); + + lensFlares.push( { material: material, size: size, distance: distance, position: new THREE.Vector3() } ); +} + + +/* + * Update lens flares update positions on all flares based on the screen position + * Set myLensFlare.customUpdateCallback to alter the flares in your project specific way. + */ + +THREE.LensFlare.updateLensFlares = function() { + + // todo: update lens halo positions here +} + + + + + + + + + + + + diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index e188757380..714c18f5c3 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -2524,159 +2524,186 @@ THREE.WebGLRenderer = function ( parameters ) { } + // render flares + + if( scene.__webglLensFlares.length ) { + + renderLensFlares( scene, renderTarget ); + + } - //////////////////////// stencil shadows begin ////////////////////// - // method: we're rendering the world in light, then the shadow - // volumes into the stencil and last a big darkening - // quad over the whole thing. This is NOT how you're - // supposed to do stencil shadows but is much faster - // + // render stencil shadows if( scene.__webglShadowVolumes.length && scene.lights.length ) { + + renderStencilShadows( scene ); + + } + + + // Generate mipmap if we're using any kind of mipmap filtering + + if ( renderTarget && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) { + + updateRenderTargetMipmap( renderTarget ); + + } + + }; + + + /* + * Render lens flares + * Method: renders 9 0xff00ff-colored points scattered over the light source area, + * reads these back and calculates occlusion. + * Then LensFlare.updateLensFlares() is called to re-position and + * update transparency of flares. Then they are rendered. + * + */ + + function renderLensFlares() { + + + } + + + /* + * Stencil Shadows + * method: we're rendering the world in light, then the shadow + * volumes into the stencil and last a big darkening + * quad over the whole thing. This is not how "you're + * supposed to" do stencil shadows but is much faster + * + */ + + function renderStencilShadows( scene ) { - // setup stencil - - _gl.enable( _gl.POLYGON_OFFSET_FILL ); - _gl.polygonOffset( 0.1, 1.0 ); - _gl.enable( _gl.STENCIL_TEST ); - _gl.depthMask( false ); - _gl.colorMask( false, false, false, false ); - - _gl.stencilFunc( _gl.ALWAYS, 1, 0xFF ); - _gl.stencilOpSeparate( _gl.BACK, _gl.KEEP, _gl.INCR, _gl.KEEP ); - _gl.stencilOpSeparate( _gl.FRONT, _gl.KEEP, _gl.DECR, _gl.KEEP ); - + // setup stencil + + _gl.enable( _gl.POLYGON_OFFSET_FILL ); + _gl.polygonOffset( 0.1, 1.0 ); + _gl.enable( _gl.STENCIL_TEST ); + _gl.depthMask( false ); + _gl.colorMask( false, false, false, false ); + _gl.stencilFunc( _gl.ALWAYS, 1, 0xFF ); + _gl.stencilOpSeparate( _gl.BACK, _gl.KEEP, _gl.INCR, _gl.KEEP ); + _gl.stencilOpSeparate( _gl.FRONT, _gl.KEEP, _gl.DECR, _gl.KEEP ); + + + // loop through all directional lights + + var l, ll = scene.lights.length; + var p; + var light, lights = scene.lights, geometryGroup; + var dirLight = []; + var program; + var p_uniforms; + var m_uniforms; + var attributes; + var o, ol = scene.__webglShadowVolumes.length; + + for( l = 0; l < ll; l++ ) { - // loop through all directional lights - - var l, ll = scene.lights.length; - var p; - var light, geometryGroup; - var dirLight = []; - var program; - var p_uniforms; - var m_uniforms; - var attributes; - - ol = scene.__webglShadowVolumes.length; + light = scene.lights[ l ]; - for( l = 0; l < ll; l++ ) { + if( light instanceof THREE.DirectionalLight ) { + + dirLight[ 0 ] = -light.position.x; + dirLight[ 1 ] = -light.position.y; + dirLight[ 2 ] = -light.position.z; + - light = scene.lights[ l ]; + // render all volumes - if( light instanceof THREE.DirectionalLight ) { + for( o = 0; o < ol; o++ ) { + + object = scene.__webglShadowVolumes[ o ].object; + geometryGroup = scene.__webglShadowVolumes[ o ].buffer; + material = object.materials[ 0 ]; - dirLight[ 0 ] = -light.position.x; - dirLight[ 1 ] = -light.position.y; - dirLight[ 2 ] = -light.position.z; - - // render all volumes - - for ( o = 0; o < ol; o++ ) { - - object = scene.__webglShadowVolumes[ o ].object; - geometryGroup = scene.__webglShadowVolumes[ o ].buffer; - material = object.materials[ 0 ]; + if ( !material.program ) _this.initMaterial( material, lights, undefined, object ); + program = material.program, + p_uniforms = program.uniforms, + m_uniforms = material.uniforms, + attributes = program.attributes; - if ( !material.program ) _this.initMaterial( material, lights, fog, object ); - - program = material.program, - p_uniforms = program.uniforms, - m_uniforms = material.uniforms, - attributes = program.attributes; + if( _oldProgram !== program ) { + + _gl.useProgram( program ); + _oldProgram = program; - if( _oldProgram !== program ) { - - _gl.useProgram( program ); - _oldProgram = program; + _gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, _projectionMatrixArray ); + _gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, _viewMatrixArray ); + _gl.uniform3fv( p_uniforms.directionalLightDirection, dirLight ); + } - _gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, _projectionMatrixArray ); - _gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, _viewMatrixArray ); - _gl.uniform3fv( p_uniforms.directionalLightDirection, dirLight ); - } + object.matrixWorld.flattenToArray( object._objectMatrixArray ); + _gl.uniformMatrix4fv( p_uniforms.objectMatrix, false, object._objectMatrixArray ); - object.matrixWorld.flattenToArray( object._objectMatrixArray ); - //object._modelViewMatrix.multiplyToArray( camera.matrixWorldInverse, object.matrixWorld, object._modelViewMatrixArray ); - _gl.uniformMatrix4fv( p_uniforms.objectMatrix, false, object._objectMatrixArray ); - //_gl.uniformMatrix4fv( p_uniforms.modelViewMatrix, false, object._modelViewMatrixArray ); + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLVertexBuffer ); + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLVertexBuffer ); - _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLNormalBuffer ); + _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webGLNormalBuffer ); - _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webGLFaceBuffer ); - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webGLFaceBuffer ); + _gl.cullFace( _gl.FRONT ); + _gl.drawElements( _gl.TRIANGLES, geometryGroup.__webGLFaceCount, _gl.UNSIGNED_SHORT, 0 ); - _gl.cullFace( _gl.FRONT ); - _gl.drawElements( _gl.TRIANGLES, geometryGroup.__webGLFaceCount, _gl.UNSIGNED_SHORT, 0 ); - - _gl.cullFace( _gl.BACK ); - _gl.drawElements( _gl.TRIANGLES, geometryGroup.__webGLFaceCount, _gl.UNSIGNED_SHORT, 0 ); - - } - + _gl.cullFace( _gl.BACK ); + _gl.drawElements( _gl.TRIANGLES, geometryGroup.__webGLFaceCount, _gl.UNSIGNED_SHORT, 0 ); + } - + } - - - // draw darkening polygon - - _gl.disable( _gl.POLYGON_OFFSET_FILL ); - _gl.colorMask( true, true, true, true ); - _gl.stencilFunc( _gl.NOTEQUAL, 0, 0xFF ); - _gl.stencilOp( _gl.KEEP, _gl.KEEP, _gl.KEEP ); - _gl.disable( _gl.DEPTH_TEST ); - - _gl.enable( _gl.BLEND ); - _gl.blendFunc( _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA ); - _gl.blendEquation( _gl.FUNC_ADD ); - - - _oldBlending = ""; - _oldProgram = _shadow.program; - - _gl.useProgram( _shadow.program ); - _gl.uniformMatrix4fv( _shadow.projectionLocation, false, _projectionMatrixArray ); - - _gl.bindBuffer( _gl.ARRAY_BUFFER, _shadow.vertexBuffer ); - _gl.vertexAttribPointer( _shadow.vertexLocation, 3, _gl.FLOAT, false, 0, 0 ); - _gl.enableVertexAttribArray( _shadow.vertexLocation ); - - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _shadow.elementBuffer ); - _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); - - - // disable stencil - - _gl.disable ( _gl.STENCIL_TEST ); - _gl.enable ( _gl.DEPTH_TEST ); - _gl.disable ( _gl.BLEND ); - _gl.depthMask( true ); + } + // setup color+stencil - //////////////////////// stencil shadows end ////////////////////// + _gl.disable( _gl.POLYGON_OFFSET_FILL ); + _gl.colorMask( true, true, true, true ); + _gl.stencilFunc( _gl.NOTEQUAL, 0, 0xFF ); + _gl.stencilOp( _gl.KEEP, _gl.KEEP, _gl.KEEP ); + _gl.disable( _gl.DEPTH_TEST ); - // Generate mipmap if we're using any kind of mipmap filtering + // draw darkening polygon - if ( renderTarget && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) { + _oldBlending = ""; + _oldProgram = _shadow.program; - updateRenderTargetMipmap( renderTarget ); + _gl.useProgram( _shadow.program ); + _gl.uniformMatrix4fv( _shadow.projectionLocation, false, _projectionMatrixArray ); + + _gl.bindBuffer( _gl.ARRAY_BUFFER, _shadow.vertexBuffer ); + _gl.vertexAttribPointer( _shadow.vertexLocation, 3, _gl.FLOAT, false, 0, 0 ); + _gl.enableVertexAttribArray( _shadow.vertexLocation ); - } + _gl.enable( _gl.BLEND ); + _gl.blendFunc( _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA ); + _gl.blendEquation( _gl.FUNC_ADD ); + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _shadow.elementBuffer ); + _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); + + + // disable stencil + + _gl.disable ( _gl.STENCIL_TEST ); + _gl.enable ( _gl.DEPTH_TEST ); + _gl.disable ( _gl.BLEND ); + _gl.depthMask( true ); + } - }; function setupMatrices ( object, camera ) { @@ -2692,6 +2719,7 @@ THREE.WebGLRenderer = function ( parameters ) { scene.__webglObjects = []; scene.__webglObjectsImmediate = []; scene.__webglShadowVolumes = []; + scene.__webglLensFlares = []; } while ( scene.__objectsAdded.length ) { @@ -2722,6 +2750,11 @@ THREE.WebGLRenderer = function ( parameters ) { } + for ( var o = 0, ol = scene.__webglLensFlares.length; o < ol; o ++ ) { + + updateObject( scene.__webglLensFlares[ o ].object, scene ); + + } }; -- GitLab