From 09941adae250c3bd22f250d556d0f219d876b6f5 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Wed, 10 Jan 2018 15:03:08 +0100 Subject: [PATCH] LensFlare: Moved to examples --- docs/api/deprecated/DeprecatedList.html | 10 +- docs/api/objects/LensFlare.html | 129 ------- docs/examples/objects/LensFlare.html | 81 ++++ docs/list.js | 5 +- examples/js/objects/LensFlare.js | 428 ++++++++++++++++++++++ examples/webgl_lensflares.html | 66 ++-- src/Three.Legacy.js | 8 + src/Three.js | 1 - src/objects/LensFlare.js | 104 ------ src/renderers/WebGLRenderer.js | 15 +- src/renderers/webgl/WebGLFlareRenderer.js | 387 ------------------- 11 files changed, 567 insertions(+), 667 deletions(-) delete mode 100644 docs/api/objects/LensFlare.html create mode 100644 docs/examples/objects/LensFlare.html create mode 100644 examples/js/objects/LensFlare.js delete mode 100644 src/objects/LensFlare.js delete mode 100644 src/renderers/webgl/WebGLFlareRenderer.js diff --git a/docs/api/deprecated/DeprecatedList.html b/docs/api/deprecated/DeprecatedList.html index 15d3b4506f..3e260b359a 100644 --- a/docs/api/deprecated/DeprecatedList.html +++ b/docs/api/deprecated/DeprecatedList.html @@ -456,6 +456,11 @@ Object3D.useQuaternion has been removed. The library now uses quaternions by default. +

[page:LensFlare]

+
+ LensFlare has been moved to [link:https://github.com/mrdoob/three.js/blob/master/examples/js/objects/LensFlare.js /examples/js/objects/LensFlare.js]. +
+

[page:Particle]

Particle has been renamed to [page:Sprite].
@@ -574,11 +579,6 @@ - - - - -

Textures

[page:ImageUtils]

diff --git a/docs/api/objects/LensFlare.html b/docs/api/objects/LensFlare.html deleted file mode 100644 index 0098e549e4..0000000000 --- a/docs/api/objects/LensFlare.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - [page:Object3D] → - -

[name]

- -
- Creates a simulated lens flare that tracks a light.

- - Note: [page:WebGLRenderer.alpha] must be set to *true* for LensFlare to work. -
- -

Example

- -
- [example:webgl_lensflares lensflares] - - -var light = new THREE.PointLight( 0xffffff, 1.5, 2000 ); - -var textureLoader = new THREE.TextureLoader(); - -var textureFlare = textureLoader.load( "textures/lensflare/lensflare.png" ); - -var flareColor = new THREE.Color( 0xffffff ); -flareColor.setHSL( h, s, l + 0.5 ); - -var lensFlare = new THREE.LensFlare( textureFlare, 700, 0.0, THREE.AdditiveBlending, flareColor ); -lensFlare.position.copy( light.position ); - -scene.add( lensFlare ); - - -
- -

Constructor

- - -

[name]( [page:Texture texture], [page:Float size], [page:Float distance], [page:Materials blending], [page:Color color] )

-
- [page:Texture texture] - (optional) THREE.Texture to use for the flare.
- [page:Float size] - (optional) size in pixels (-1 = use texture.width)
- [page:Float distance] - (optional) (0-1) from light source (0 = at light source)
- [page:Materials blending] - (optional) [page:Materials Blending Mode] - Defaults to THREE.NormalBlending
- [page:Color color] - (optional) the [page:Color] of the lens flare

- - Automatically adds a lens flare to the lensFlares array if a [page:Texture texture] is set. - If [page:Texture texture] not passed here, [page:.add add] must be called later. -
- -

Properties

-
See the base [page:Object3D] class for common properties.
- -

[property:Boolean isLensFlare]

-
- Used to check whether this or derived classes are lens flares. Default is *true*.

- - You should not change this, as it used internally for optimisation. -
- - -

[property:array lensFlares]

-
- The array of flares as set by [page:LensFlare.add] or passed in the constructor. - Each flare is an object with the following defaults: - -{ - texture: texture, // texture passed in the constructor or [page:.add add] method - size: size, // if not passed in, default is -1 - distance: distance, // if not passed in, default is 0 - x: 0, y: 0, z: 0, // screen position (-1 => 1) z = 0 is in front z = 1 is back - scale: 1, - rotation: 0, - opacity: opacity, // if not passed in, default is 1 - color: color, // if not passed in, default is new Color( 0xffffff ) (white) - blending: blending // if not passed in, default is NormalBlending -} - -
- -

[property:Vector3 positionScreen]

-
The position of the lens flare on the screen.
- -

[property:Function customUpdateCallback]

-
- A custom update callback. Default is undefined, set this to override [page:.updateLensFlares updateLensFlares](). -
- -

Methods

-
See the base [page:Object3D] class for common methods.
- - -

[method:null add]( [page:Texture texture], [page:Float size], [page:Float distance], [page:Materials blending], [page:Color color] )

-
- Adds a lens flare. Takes the same parameters as the constructor. -
- -

[method:LensFlare clone]()

-
- Return a new LensFlare with the same parameters as this one. -
- -

[method:LensFlare copy]( [page:LensFlare source] )

-
- Copy the parameters from the [page:LensFlare source] LensFlare into this one. -
- -

[method:null updateLensFlares]()

-
- Updates [page:.lensFlares lensFlares] based on the [page:LensFlare.positionScreen positionScreen] - property.

- - Can be overridden by setting the [page:.customUpdateCallback customUpdateCallback] function. -
- - -

Source

- - [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] - - diff --git a/docs/examples/objects/LensFlare.html b/docs/examples/objects/LensFlare.html new file mode 100644 index 0000000000..792bc2b947 --- /dev/null +++ b/docs/examples/objects/LensFlare.html @@ -0,0 +1,81 @@ + + + + + + + + + + + [page:Mesh] → + +

[name]

+ +
+ Creates a simulated lens flare that tracks a light.

+ + Note: [page:WebGLRenderer.alpha] must be set to *true* for LensFlare to work. +
+ +

Example

+ +
+ [example:webgl_lensflares lensflares] + + +var light = new THREE.PointLight( 0xffffff, 1.5, 2000 ); + +var textureLoader = new THREE.TextureLoader(); + +var textureFlare0 = textureLoader.load( "textures/lensflare/lensflare0.png" ); +var textureFlare1 = textureLoader.load( "textures/lensflare/lensflare2.png" ); +var textureFlare2 = textureLoader.load( "textures/lensflare/lensflare3.png" ); + +var lensFlareGroup = new THREE.LensFlareGroup(); + +var lensFlare0 = new THREE.LensFlare( textureFlare0, 512, 0, THREE.AdditiveBlending ); +var lensFlare1 = new THREE.LensFlare( textureFlare1, 512, 0, THREE.AdditiveBlending ); +var lensFlare2 = new THREE.LensFlare( textureFlare2, 60, 0.6, THREE.AdditiveBlending ); + +lensFlareGroup.add( lensFlare0 ); +lensFlareGroup.add( lensFlare1 ); +lensFlareGroup.add( lensFlare2 ); + +lensFlareGroup.position.copy( light.position ); + +scene.add( lensFlareGroup ); + + +
+ +

Constructor

+ + +

[name]( [page:Texture texture], [page:Float size], [page:Float distance], [page:Materials blending], [page:Color color], [page:Float opacity] )

+
+ [page:Texture texture] - THREE.Texture to use for the flare.
+ [page:Float size] - (optional) size in pixels
+ [page:Float distance] - (optional) (0-1) from light source (0 = at light source)
+ [page:Materials blending] - (optional) [page:Materials Blending Mode] - Defaults to THREE.NormalBlending
+ [page:Color color] - (optional) the [page:Color] of the lens flare

+ [page:Float opacity] - (optional) the opacity of the lens flare

+ +
+ +

Properties

+
See the base [page:Mesh] class for common properties.
+ +

[property:Boolean isLensFlare]

+
+ Used to check whether this or derived classes are lens flares. Default is *true*.

+ + You should not change this, as it used internally for optimisation. +
+ + +

Source

+ + [link:https://github.com/mrdoob/three.js/blob/master/examples/js/objects/LensFlare.js examples/js/objects/LensFlare.js] + + diff --git a/docs/list.js b/docs/list.js index 5657c5bb59..bb991ac127 100644 --- a/docs/list.js +++ b/docs/list.js @@ -292,7 +292,6 @@ var list = { "Objects": { "Bone": "api/objects/Bone", "Group": "api/objects/Group", - "LensFlare": "api/objects/LensFlare", "Line": "api/objects/Line", "LineLoop": "api/objects/LineLoop", "LineSegments": "api/objects/LineSegments", @@ -361,6 +360,10 @@ var list = { "PRWMLoader": "examples/loaders/PRWMLoader" }, + "Objects": { + "LensFlare": "examples/objects/LensFlare", + }, + "Exporters": { "GLTFExporter": "examples/exporters/GLTFExporter" }, diff --git a/examples/js/objects/LensFlare.js b/examples/js/objects/LensFlare.js new file mode 100644 index 0000000000..a82725782d --- /dev/null +++ b/examples/js/objects/LensFlare.js @@ -0,0 +1,428 @@ +/** + * @author Mugen87 / https://github.com/Mugen87 + * + */ + +THREE.LensFlareGroup = function () { + + THREE.Group.call( this ); + + this.type = 'LensFlareGroup'; + + this.positionScreen = new THREE.Vector3(); + this.customUpdateCallback = undefined; + this.flareVisible = false; + + // textures + + var tempMap = new THREE.CanvasTexture( document.createElement( 'canvas' ) ); + tempMap.image.width = tempMap.image.height = 16; + tempMap.format = THREE.RGBFormat; + tempMap.minFilter = tempMap.magFilter = THREE.NearestFilter; + tempMap.needsUpdate = true; + + var occlusionMap = new THREE.CanvasTexture( document.createElement( 'canvas' ) ); + occlusionMap.image.width = occlusionMap.image.height = 16; + occlusionMap.format = THREE.RGBAFormat; + occlusionMap.minFilter = occlusionMap.magFilter = THREE.NearestFilter; + occlusionMap.needsUpdate = true; + + // material + + var shader = THREE.LensFlareGroup.Shader; + + var material = new THREE.RawShaderMaterial( { + uniforms: shader.uniforms, + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader, + depthWrite: false + } ); + + // the following object is used for occlusionMap generation + + var occluder = new THREE.Mesh( THREE.LensFlare.Geometry, material ); + occluder.frustumCulled = false; + + // + + var scale = new THREE.Vector2(); + var screenPositionPixels = new THREE.Vector2(); + var validArea = new THREE.Box2(); + var currentFrame = 0; + + this.update = function ( renderer, camera, viewport ) { + + var frame = renderer.info.render.frame; + + if ( currentFrame === frame ) return; + + currentFrame = frame; + + var invAspect = viewport.w / viewport.z; + var halfViewportWidth = viewport.z * 0.5; + var halfViewportHeight = viewport.w * 0.5; + + var size = 16 / viewport.w; + scale.set( size * invAspect, size ); + + validArea.min.set( viewport.x, viewport.y ); + validArea.max.set( viewport.x + ( viewport.z - 16 ), viewport.y + ( viewport.w - 16 ) ); + + // calculate position in screen space + + this.positionScreen.setFromMatrixPosition( this.matrixWorld ); + + this.positionScreen.applyMatrix4( camera.matrixWorldInverse ); + this.positionScreen.applyMatrix4( camera.projectionMatrix ); + + // horizontal and vertical coordinate of the lower left corner of the pixels to copy + + screenPositionPixels.x = viewport.x + ( this.positionScreen.x * halfViewportWidth ) + halfViewportWidth - 8; + screenPositionPixels.y = viewport.y + ( this.positionScreen.y * halfViewportHeight ) + halfViewportHeight - 8; + + // screen cull + + if ( validArea.containsPoint( screenPositionPixels ) === true ) { + + this.flareVisible = true; + + // save current RGB to temp texture + + renderer.copyFramebufferToTexture( screenPositionPixels.x, screenPositionPixels.y, tempMap ); + + // render pink quad + + occluder.material.uniforms.renderType.value = 0; + occluder.material.uniforms.scale.value = scale; + occluder.material.uniforms.screenPosition.value = this.positionScreen; + occluder.material.depthTest = true; + + renderer.render( occluder, camera ); + + // copy result to occlusionMap + + renderer.copyFramebufferToTexture( screenPositionPixels.x, screenPositionPixels.y, occlusionMap ); + + // restore graphics + + occluder.material.uniforms.renderType.value = 1; + occluder.material.uniforms.map.value = tempMap; + occluder.material.depthTest = false; + + renderer.render( occluder, camera ); + + // update object positions + + if ( this.customUpdateCallback ) { + + this.customUpdateCallback( this ); + + } else { + + this.updateLensFlares(); + + } + + } else { + + this.flareVisible = false; + + } + + }; + + this.updateLensFlares = function () { + + var vecX = - this.positionScreen.x * 2; + var vecY = - this.positionScreen.y * 2; + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + var flare = this.children[ i ]; + + flare.flarePosition.x = this.positionScreen.x + vecX * flare.flareDistance; + flare.flarePosition.y = this.positionScreen.y + vecY * flare.flareDistance; + + flare.flareRotation += 0.25; + + } + + }; + + this.getOcclusionMap = function () { + + return occlusionMap; + + }; + + this.dispose = function () { + + occluder.material.dispose(); + + tempMap.dispose(); + occlusionMap.dispose(); + + }; + +}; + +THREE.LensFlareGroup.prototype = Object.create( THREE.Group.prototype ); +THREE.LensFlareGroup.prototype.constructor = THREE.LensFlareGroup; +THREE.LensFlareGroup.prototype.isLensFlareGroup = true; + +THREE.LensFlareGroup.Shader = { + + uniforms: { + + 'renderType': { value: 0 }, + 'map': { value: null }, + 'scale': { value: null }, + 'screenPosition': { value: null } + + }, + + vertexShader: [ + + 'precision highp float;', + + 'uniform vec3 screenPosition;', + 'uniform vec2 scale;', + + 'attribute vec3 position;', + 'attribute vec2 uv;', + + 'varying vec2 vUV;', + + 'void main() {', + + ' vUV = uv;', + + ' vec2 pos = position.xy;', + + ' gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );', + + '}' + + ].join( '\n' ), + + fragmentShader: [ + + 'precision highp float;', + + 'uniform lowp int renderType;', + 'uniform sampler2D map;', + + 'varying vec2 vUV;', + + 'void main() {', + + // pink square + + ' if ( renderType == 0 ) {', + + ' gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );', + + // restore + + ' } else {', + + ' gl_FragColor = texture2D( map, vUV );', + + ' }', + + '}' + + ].join( '\n' ) + +}; + +// + +THREE.LensFlare = function ( texture, size, distance, blending, color, opacity ) { + + THREE.Mesh.call( this ); + + this.type = 'LensFlare'; + this.frustumCulled = false; + + this.flareTexture = texture; + this.flareSize = size || 1; + this.flareDistance = distance || 0; + this.flareBlending = blending || THREE.NormalBlending, + this.flareColor = color || new THREE.Color( 0xffffff ); + this.flareOpacity = opacity || 1; + this.flarePosition = new THREE.Vector3(); + this.flareScale = 1; + this.flareRotation = 0; + + this.geometry = THREE.LensFlare.Geometry; + + var shader = THREE.LensFlare.Shader; + + this.material = new THREE.RawShaderMaterial( { + uniforms: shader.uniforms, + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader, + blending: blending, + transparent: true, + depthWrite: false + } ); + + // + + var scale = new THREE.Vector2(); + + this.onBeforeRender = function ( renderer, scene, camera, geometry, material, group, viewport ) { + + var group = this.parent; + + if ( group === null ) { + + console.error( 'THREE.LensFlare: LensFlare not assigned to a LensFlareGroup. Rendering not possible.' ); + return; + + } + + // + + group.update( renderer, camera, viewport ); + + // + + var size = this.flareSize * this.flareScale / viewport.w; + var invAspect = viewport.w / viewport.z; + + scale.set( size * invAspect, size ); + + this.material.uniforms.map.value = this.flareTexture; + this.material.uniforms.occlusionMap.value = group.getOcclusionMap(); + this.material.uniforms.opacity.value = this.flareOpacity; + this.material.uniforms.color.value = this.flareColor; + this.material.uniforms.scale.value = scale; + this.material.uniforms.rotation.value = this.flareRotation; + this.material.uniforms.screenPosition.value = this.flarePosition; + + if ( group.flareVisible === false ) { + + this.material.uniforms.opacity.value = 0; + + } + + }; + + this.dispose = function () { + + this.material.dispose(); + + }; + +}; + +THREE.LensFlare.prototype = Object.create( THREE.Mesh.prototype ); +THREE.LensFlare.prototype.constructor = THREE.LensFlare; +THREE.LensFlare.prototype.isLensFlare = true; + +THREE.LensFlare.Shader = { + + uniforms: { + + 'map': { value: null }, + 'occlusionMap': { value: null }, + 'opacity': { value: 1 }, + 'color': { value: null }, + 'scale': { value: null }, + 'rotation': { value: 1 }, + 'screenPosition': { value: null } + + }, + + vertexShader: [ + + 'precision highp float;', + + 'uniform vec3 screenPosition;', + 'uniform vec2 scale;', + 'uniform float rotation;', + + 'uniform sampler2D occlusionMap;', + + 'attribute vec3 position;', + 'attribute vec2 uv;', + + 'varying vec2 vUV;', + 'varying float vVisibility;', + + 'void main() {', + + ' vUV = uv;', + + ' vec2 pos = position.xy;', + + ' vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );', + ' visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );', + ' visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );', + ' visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );', + ' visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );', + ' visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );', + ' visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );', + ' visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );', + ' visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );', + + ' vVisibility = visibility.r / 9.0;', + ' vVisibility *= 1.0 - visibility.g / 9.0;', + ' vVisibility *= visibility.b / 9.0;', + ' vVisibility *= 1.0 - visibility.a / 9.0;', + + ' pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;', + ' pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;', + + ' gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );', + + '}' + + ].join( '\n' ), + + fragmentShader: [ + + 'precision highp float;', + + 'uniform sampler2D map;', + 'uniform float opacity;', + 'uniform vec3 color;', + + 'varying vec2 vUV;', + 'varying float vVisibility;', + + 'void main() {', + + ' vec4 texture = texture2D( map, vUV );', + ' texture.a *= opacity * vVisibility;', + ' gl_FragColor = texture;', + ' gl_FragColor.rgb *= color;', + + '}' + + ].join( '\n' ) + +}; + +THREE.LensFlare.Geometry = ( function () { + + var geometry = new THREE.BufferGeometry(); + + var float32Array = new Float32Array( [ + - 1, - 1, 0, 0, 0, + 1, - 1, 0, 1, 0, + 1, 1, 0, 1, 1, + - 1, 1, 0, 0, 1 + ] ); + + var interleavedBuffer = new THREE.InterleavedBuffer( float32Array, 5 ); + + geometry.setIndex( [ 0, 1, 2, 0, 2, 3 ] ); + geometry.addAttribute( 'position', new THREE.InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) ); + geometry.addAttribute( 'uv', new THREE.InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) ); + + return geometry; + +} )(); diff --git a/examples/webgl_lensflares.html b/examples/webgl_lensflares.html index fe40d86c6e..380614b9e7 100644 --- a/examples/webgl_lensflares.html +++ b/examples/webgl_lensflares.html @@ -43,6 +43,7 @@ + @@ -86,7 +87,7 @@ var s = 250; - var cube = new THREE.BoxGeometry( s, s, s ); + var cube = new THREE.BoxBufferGeometry( s, s, s ); var material = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0xffffff, shininess: 50 } ); @@ -139,21 +140,30 @@ var flareColor = new THREE.Color( 0xffffff ); flareColor.setHSL( h, s, l + 0.5 ); - var lensFlare = new THREE.LensFlare( textureFlare0, 700, 0.0, THREE.AdditiveBlending, flareColor ); + var lensFlareGroup = new THREE.LensFlareGroup(); - lensFlare.add( textureFlare2, 512, 0.0, THREE.AdditiveBlending ); - lensFlare.add( textureFlare2, 512, 0.0, THREE.AdditiveBlending ); - lensFlare.add( textureFlare2, 512, 0.0, THREE.AdditiveBlending ); + var lensFlare0 = new THREE.LensFlare( textureFlare0, 700, 0.0, THREE.AdditiveBlending, flareColor ); + var lensFlare1 = new THREE.LensFlare( textureFlare2, 512, 0, THREE.AdditiveBlending ); + var lensFlare2 = new THREE.LensFlare( textureFlare2, 512, 0, THREE.AdditiveBlending ); + var lensFlare3 = new THREE.LensFlare( textureFlare2, 512, 0, THREE.AdditiveBlending ); + var lensFlare4 = new THREE.LensFlare( textureFlare3, 60, 0.6, THREE.AdditiveBlending ); + var lensFlare5 = new THREE.LensFlare( textureFlare3, 70, 0.7, THREE.AdditiveBlending ); + var lensFlare6 = new THREE.LensFlare( textureFlare3, 120, 0.9, THREE.AdditiveBlending ); + var lensFlare7 = new THREE.LensFlare( textureFlare3, 70, 1, THREE.AdditiveBlending ); - lensFlare.add( textureFlare3, 60, 0.6, THREE.AdditiveBlending ); - lensFlare.add( textureFlare3, 70, 0.7, THREE.AdditiveBlending ); - lensFlare.add( textureFlare3, 120, 0.9, THREE.AdditiveBlending ); - lensFlare.add( textureFlare3, 70, 1.0, THREE.AdditiveBlending ); + lensFlareGroup.add( lensFlare0 ); + lensFlareGroup.add( lensFlare1 ); + lensFlareGroup.add( lensFlare2 ); + lensFlareGroup.add( lensFlare3 ); + lensFlareGroup.add( lensFlare4 ); + lensFlareGroup.add( lensFlare5 ); + lensFlareGroup.add( lensFlare6 ); + lensFlareGroup.add( lensFlare7 ); - lensFlare.customUpdateCallback = lensFlareUpdateCallback; - lensFlare.position.copy( light.position ); + lensFlareGroup.customUpdateCallback = lensFlareUpdateCallback; + lensFlareGroup.position.copy( light.position ); - scene.add( lensFlare ); + scene.add( lensFlareGroup ); } @@ -162,6 +172,8 @@ renderer = new THREE.WebGLRenderer( { antialias: true, alpha: true } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.autoClear = false; + renderer.info.autoReset = false; container.appendChild( renderer.domElement ); // @@ -182,29 +194,25 @@ // - function lensFlareUpdateCallback( object ) { + function lensFlareUpdateCallback( object ) { - var f, fl = object.lensFlares.length; - var flare; - var vecX = -object.positionScreen.x * 2; - var vecY = -object.positionScreen.y * 2; + var vecX = - object.positionScreen.x * 2; + var vecY = - object.positionScreen.y * 2; + for ( var i = 0, l = this.children.length; i < l; i ++ ) { - for( f = 0; f < fl; f++ ) { + var flare = this.children[ i ]; - flare = object.lensFlares[ f ]; + flare.flarePosition.x = object.positionScreen.x + vecX * flare.flareDistance; + flare.flarePosition.y = object.positionScreen.y + vecY * flare.flareDistance; + flare.flareRotation = 0; - flare.x = object.positionScreen.x + vecX * flare.distance; - flare.y = object.positionScreen.y + vecY * flare.distance; + } - flare.rotation = 0; + object.children[ 2 ].flarePosition.y += 0.025; + object.children[ 3 ].flareRotation = object.positionScreen.x * 0.5 + THREE.Math.degToRad( 45 ); - } - - object.lensFlares[ 2 ].y += 0.025; - object.lensFlares[ 3 ].rotation = object.positionScreen.x * 0.5 + THREE.Math.degToRad( 45 ); - - } + } // @@ -233,6 +241,8 @@ var delta = clock.getDelta(); controls.update( delta ); + renderer.clear(); + renderer.info.reset(); renderer.render( scene, camera ); } diff --git a/src/Three.Legacy.js b/src/Three.Legacy.js index c3acfbdef3..8b8589907b 100644 --- a/src/Three.Legacy.js +++ b/src/Three.Legacy.js @@ -1771,3 +1771,11 @@ export var SceneUtils = { } }; + +// + +export function LensFlare() { + + console.error( 'THREE.LensFlare has been moved to /examples/js/objects/LensFlare.js' ); + +} diff --git a/src/Three.js b/src/Three.js index 72b50d27d8..f4e620c681 100644 --- a/src/Three.js +++ b/src/Three.js @@ -11,7 +11,6 @@ export { ShaderChunk } from './renderers/shaders/ShaderChunk.js'; export { FogExp2 } from './scenes/FogExp2.js'; export { Fog } from './scenes/Fog.js'; export { Scene } from './scenes/Scene.js'; -export { LensFlare } from './objects/LensFlare.js'; export { Sprite } from './objects/Sprite.js'; export { LOD } from './objects/LOD.js'; export { SkinnedMesh } from './objects/SkinnedMesh.js'; diff --git a/src/objects/LensFlare.js b/src/objects/LensFlare.js deleted file mode 100644 index 585dd08abf..0000000000 --- a/src/objects/LensFlare.js +++ /dev/null @@ -1,104 +0,0 @@ -import { Object3D } from '../core/Object3D.js'; -import { NormalBlending } from '../constants.js'; -import { Color } from '../math/Color.js'; -import { Vector3 } from '../math/Vector3.js'; - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ - -function LensFlare( texture, size, distance, blending, color ) { - - Object3D.call( this ); - - this.lensFlares = []; - - this.positionScreen = new Vector3(); - this.customUpdateCallback = undefined; - - if ( texture !== undefined ) { - - this.add( texture, size, distance, blending, color ); - - } - -} - -LensFlare.prototype = Object.assign( Object.create( Object3D.prototype ), { - - constructor: LensFlare, - - isLensFlare: true, - - copy: function ( source ) { - - Object3D.prototype.copy.call( this, source ); - - this.positionScreen.copy( source.positionScreen ); - this.customUpdateCallback = source.customUpdateCallback; - - for ( var i = 0, l = source.lensFlares.length; i < l; i ++ ) { - - this.lensFlares.push( source.lensFlares[ i ] ); - - } - - return this; - - }, - - add: function ( texture, size, distance, blending, color, opacity ) { - - if ( size === undefined ) size = - 1; - if ( distance === undefined ) distance = 0; - if ( opacity === undefined ) opacity = 1; - if ( color === undefined ) color = new Color( 0xffffff ); - if ( blending === undefined ) blending = NormalBlending; - - distance = Math.min( distance, Math.max( 0, distance ) ); - - this.lensFlares.push( { - texture: texture, // THREE.Texture - size: size, // size in pixels (-1 = use texture.width) - distance: distance, // distance (0-1) from light source (0=at light source) - x: 0, y: 0, z: 0, // screen position (-1 => 1) z = 0 is in front z = 1 is back - scale: 1, // scale - rotation: 0, // rotation - opacity: opacity, // opacity - color: color, // color - blending: blending // blending - } ); - - }, - - /* - * 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. - */ - - updateLensFlares: function () { - - var f, fl = this.lensFlares.length; - var flare; - var vecX = - this.positionScreen.x * 2; - var vecY = - this.positionScreen.y * 2; - - for ( f = 0; f < fl; f ++ ) { - - flare = this.lensFlares[ f ]; - - flare.x = this.positionScreen.x + vecX * flare.distance; - flare.y = this.positionScreen.y + vecY * flare.distance; - - flare.wantedRotation = flare.x * Math.PI * 0.25; - flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25; - - } - - } - -} ); - - -export { LensFlare }; diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index 417d42887e..fc16880d07 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -6,7 +6,6 @@ import { WebGLUniforms } from './webgl/WebGLUniforms.js'; import { UniformsLib } from './shaders/UniformsLib.js'; import { UniformsUtils } from './shaders/UniformsUtils.js'; import { ShaderLib } from './shaders/ShaderLib.js'; -import { WebGLFlareRenderer } from './webgl/WebGLFlareRenderer.js'; import { WebGLSpriteRenderer } from './webgl/WebGLSpriteRenderer.js'; import { WebGLShadowMap } from './webgl/WebGLShadowMap.js'; import { WebGLAttributes } from './webgl/WebGLAttributes.js'; @@ -62,7 +61,6 @@ function WebGLRenderer( parameters ) { var currentRenderList = null; var spritesArray = []; - var flaresArray = []; // public properties @@ -260,7 +258,7 @@ function WebGLRenderer( parameters ) { var programCache, renderLists; var background, morphtargets, bufferRenderer, indexedBufferRenderer; - var flareRenderer, spriteRenderer; + var spriteRenderer; var utils; @@ -299,7 +297,6 @@ function WebGLRenderer( parameters ) { bufferRenderer = new WebGLBufferRenderer( _gl, extensions, _infoRender ); indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, _infoRender ); - flareRenderer = new WebGLFlareRenderer( _this, _gl, state, textures, capabilities ); spriteRenderer = new WebGLSpriteRenderer( _this, _gl, state, textures, capabilities ); _this.info.programs = programCache.programs; @@ -1128,7 +1125,6 @@ function WebGLRenderer( parameters ) { shadowsArray.length = 0; spritesArray.length = 0; - flaresArray.length = 0; _localClippingEnabled = this.localClippingEnabled; _clippingEnabled = _clipping.init( this.clippingPlanes, _localClippingEnabled, camera ); @@ -1197,7 +1193,6 @@ function WebGLRenderer( parameters ) { // custom renderers spriteRenderer.render( spritesArray, scene, camera ); - flareRenderer.render( flaresArray, scene, camera, _currentViewport ); // Generate mipmap if we're using any kind of mipmap filtering @@ -1308,10 +1303,6 @@ function WebGLRenderer( parameters ) { } - } else if ( object.isLensFlare ) { - - flaresArray.push( object ); - } else if ( object.isImmediateRenderObject ) { if ( sortObjects ) { @@ -1434,7 +1425,7 @@ function WebGLRenderer( parameters ) { function renderObject( object, scene, camera, geometry, material, group ) { - object.onBeforeRender( _this, scene, camera, geometry, material, group ); + object.onBeforeRender( _this, scene, camera, geometry, material, group, _currentViewport ); object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); @@ -1453,7 +1444,7 @@ function WebGLRenderer( parameters ) { } else { - _this.renderBufferDirect( camera, scene.fog, geometry, material, object, group ); + _this.renderBufferDirect( camera, scene.fog, geometry, material, object, group, _currentViewport ); } diff --git a/src/renderers/webgl/WebGLFlareRenderer.js b/src/renderers/webgl/WebGLFlareRenderer.js deleted file mode 100644 index f94574caf4..0000000000 --- a/src/renderers/webgl/WebGLFlareRenderer.js +++ /dev/null @@ -1,387 +0,0 @@ -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ - -import { Box2 } from '../../math/Box2.js'; -import { Vector2 } from '../../math/Vector2.js'; -import { Vector3 } from '../../math/Vector3.js'; - -function WebGLFlareRenderer( renderer, gl, state, textures, capabilities ) { - - var vertexBuffer, elementBuffer; - var shader, program, attributes, uniforms; - - var tempTexture, occlusionTexture; - - function init() { - - var vertices = new Float32Array( [ - - 1, - 1, 0, 0, - 1, - 1, 1, 0, - 1, 1, 1, 1, - - 1, 1, 0, 1 - ] ); - - var faces = new Uint16Array( [ - 0, 1, 2, - 0, 2, 3 - ] ); - - // buffers - - vertexBuffer = gl.createBuffer(); - elementBuffer = gl.createBuffer(); - - gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); - gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); - - gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); - gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW ); - - // textures - - tempTexture = gl.createTexture(); - occlusionTexture = gl.createTexture(); - - state.bindTexture( gl.TEXTURE_2D, tempTexture ); - gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGB, 16, 16, 0, gl.RGB, gl.UNSIGNED_BYTE, null ); - gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE ); - gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE ); - gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); - gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); - - state.bindTexture( gl.TEXTURE_2D, occlusionTexture ); - gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null ); - gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE ); - gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE ); - gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); - gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); - - shader = { - - vertexShader: [ - - 'uniform lowp int renderType;', - - 'uniform vec3 screenPosition;', - 'uniform vec2 scale;', - 'uniform float rotation;', - - 'uniform sampler2D occlusionMap;', - - 'attribute vec2 position;', - 'attribute vec2 uv;', - - 'varying vec2 vUV;', - 'varying float vVisibility;', - - 'void main() {', - - ' vUV = uv;', - - ' vec2 pos = position;', - - ' if ( renderType == 2 ) {', - - ' vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );', - ' visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );', - ' visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );', - ' visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );', - ' visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );', - ' visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );', - ' visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );', - ' visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );', - ' visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );', - - ' vVisibility = visibility.r / 9.0;', - ' vVisibility *= 1.0 - visibility.g / 9.0;', - ' vVisibility *= visibility.b / 9.0;', - ' vVisibility *= 1.0 - visibility.a / 9.0;', - - ' pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;', - ' pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;', - - ' }', - - ' gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );', - - '}' - - ].join( '\n' ), - - fragmentShader: [ - - 'uniform lowp int renderType;', - - 'uniform sampler2D map;', - 'uniform float opacity;', - 'uniform vec3 color;', - - 'varying vec2 vUV;', - 'varying float vVisibility;', - - 'void main() {', - - // pink square - - ' if ( renderType == 0 ) {', - - ' gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );', - - // restore - - ' } else if ( renderType == 1 ) {', - - ' gl_FragColor = texture2D( map, vUV );', - - // flare - - ' } else {', - - ' vec4 texture = texture2D( map, vUV );', - ' texture.a *= opacity * vVisibility;', - ' gl_FragColor = texture;', - ' gl_FragColor.rgb *= color;', - - ' }', - - '}' - - ].join( '\n' ) - - }; - - program = createProgram( shader ); - - attributes = { - vertex: gl.getAttribLocation( program, 'position' ), - uv: gl.getAttribLocation( program, 'uv' ) - }; - - uniforms = { - renderType: gl.getUniformLocation( program, 'renderType' ), - map: gl.getUniformLocation( program, 'map' ), - occlusionMap: gl.getUniformLocation( program, 'occlusionMap' ), - opacity: gl.getUniformLocation( program, 'opacity' ), - color: gl.getUniformLocation( program, 'color' ), - scale: gl.getUniformLocation( program, 'scale' ), - rotation: gl.getUniformLocation( program, 'rotation' ), - screenPosition: gl.getUniformLocation( program, 'screenPosition' ) - }; - - } - - /* - * Render lens flares - * Method: renders 16x16 0xff00ff-colored points scattered over the light source area, - * reads these back and calculates occlusion. - */ - - this.render = function ( flares, scene, camera, viewport ) { - - if ( flares.length === 0 ) return; - - var tempPosition = new Vector3(); - - var invAspect = viewport.w / viewport.z, - halfViewportWidth = viewport.z * 0.5, - halfViewportHeight = viewport.w * 0.5; - - var size = 16 / viewport.w, - scale = new Vector2( size * invAspect, size ); - - var screenPosition = new Vector3( 1, 1, 0 ), - screenPositionPixels = new Vector2( 1, 1 ); - - var validArea = new Box2(); - - validArea.min.set( viewport.x, viewport.y ); - validArea.max.set( viewport.x + ( viewport.z - 16 ), viewport.y + ( viewport.w - 16 ) ); - - if ( program === undefined ) { - - init(); - - } - - state.useProgram( program ); - - state.initAttributes(); - state.enableAttribute( attributes.vertex ); - state.enableAttribute( attributes.uv ); - state.disableUnusedAttributes(); - - // loop through all lens flares to update their occlusion and positions - // setup gl and common used attribs/uniforms - - gl.uniform1i( uniforms.occlusionMap, 0 ); - gl.uniform1i( uniforms.map, 1 ); - - gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); - gl.vertexAttribPointer( attributes.vertex, 2, gl.FLOAT, false, 2 * 8, 0 ); - gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 ); - - gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); - - state.disable( gl.CULL_FACE ); - state.buffers.depth.setMask( false ); - - for ( var i = 0, l = flares.length; i < l; i ++ ) { - - size = 16 / viewport.w; - scale.set( size * invAspect, size ); - - // calc object screen position - - var flare = flares[ i ]; - - tempPosition.set( flare.matrixWorld.elements[ 12 ], flare.matrixWorld.elements[ 13 ], flare.matrixWorld.elements[ 14 ] ); - - tempPosition.applyMatrix4( camera.matrixWorldInverse ); - tempPosition.applyMatrix4( camera.projectionMatrix ); - - // setup arrays for gl programs - - screenPosition.copy( tempPosition ); - - // horizontal and vertical coordinate of the lower left corner of the pixels to copy - - screenPositionPixels.x = viewport.x + ( screenPosition.x * halfViewportWidth ) + halfViewportWidth - 8; - screenPositionPixels.y = viewport.y + ( screenPosition.y * halfViewportHeight ) + halfViewportHeight - 8; - - // screen cull - - if ( validArea.containsPoint( screenPositionPixels ) === true ) { - - // save current RGB to temp texture - - state.activeTexture( gl.TEXTURE0 ); - state.bindTexture( gl.TEXTURE_2D, null ); - state.activeTexture( gl.TEXTURE1 ); - state.bindTexture( gl.TEXTURE_2D, tempTexture ); - gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGB, screenPositionPixels.x, screenPositionPixels.y, 16, 16, 0 ); - - - // render pink quad - - gl.uniform1i( uniforms.renderType, 0 ); - gl.uniform2f( uniforms.scale, scale.x, scale.y ); - gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); - - state.disable( gl.BLEND ); - state.enable( gl.DEPTH_TEST ); - - gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - - - // copy result to occlusionMap - - state.activeTexture( gl.TEXTURE0 ); - state.bindTexture( gl.TEXTURE_2D, occlusionTexture ); - gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGBA, screenPositionPixels.x, screenPositionPixels.y, 16, 16, 0 ); - - - // restore graphics - - gl.uniform1i( uniforms.renderType, 1 ); - state.disable( gl.DEPTH_TEST ); - - state.activeTexture( gl.TEXTURE1 ); - state.bindTexture( gl.TEXTURE_2D, tempTexture ); - gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - - - // update object positions - - flare.positionScreen.copy( screenPosition ); - - if ( flare.customUpdateCallback ) { - - flare.customUpdateCallback( flare ); - - } else { - - flare.updateLensFlares(); - - } - - // render flares - - gl.uniform1i( uniforms.renderType, 2 ); - state.enable( gl.BLEND ); - - for ( var j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) { - - var sprite = flare.lensFlares[ j ]; - - if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) { - - screenPosition.x = sprite.x; - screenPosition.y = sprite.y; - screenPosition.z = sprite.z; - - size = sprite.size * sprite.scale / viewport.w; - - scale.x = size * invAspect; - scale.y = size; - - gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); - gl.uniform2f( uniforms.scale, scale.x, scale.y ); - gl.uniform1f( uniforms.rotation, sprite.rotation ); - - gl.uniform1f( uniforms.opacity, sprite.opacity ); - gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b ); - - state.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst ); - - textures.setTexture2D( sprite.texture, 1 ); - - gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - - } - - } - - } - - } - - // restore gl - - state.enable( gl.CULL_FACE ); - state.enable( gl.DEPTH_TEST ); - state.buffers.depth.setMask( true ); - - state.reset(); - - }; - - function createProgram( shader ) { - - var program = gl.createProgram(); - - var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER ); - var vertexShader = gl.createShader( gl.VERTEX_SHADER ); - - var prefix = 'precision ' + capabilities.precision + ' float;\n'; - - gl.shaderSource( fragmentShader, prefix + shader.fragmentShader ); - gl.shaderSource( vertexShader, prefix + shader.vertexShader ); - - gl.compileShader( fragmentShader ); - gl.compileShader( vertexShader ); - - gl.attachShader( program, fragmentShader ); - gl.attachShader( program, vertexShader ); - - gl.linkProgram( program ); - - return program; - - } - -} - - -export { WebGLFlareRenderer }; -- GitLab