提交 09941ada 编写于 作者: M Mugen87

LensFlare: Moved to examples

上级 38162cc2
......@@ -456,6 +456,11 @@
Object3D.useQuaternion has been removed. The library now uses quaternions by default.
</div>
<h3>[page:LensFlare]</h3>
<div>
LensFlare has been moved to [link:https://github.com/mrdoob/three.js/blob/master/examples/js/objects/LensFlare.js /examples/js/objects/LensFlare.js].
</div>
<h3>[page:Particle]</h3>
<div>Particle has been renamed to [page:Sprite].</div>
......@@ -574,11 +579,6 @@
</div>
<h2>Textures</h2>
<h3>[page:ImageUtils]</h3>
......
......@@ -8,7 +8,7 @@
<link type="text/css" rel="stylesheet" href="page.css" />
</head>
<body>
[page:Object3D] &rarr;
[page:Mesh] &rarr;
<h1>[name]</h1>
......@@ -28,15 +28,23 @@ var light = new THREE.PointLight( 0xffffff, 1.5, 2000 );
var textureLoader = new THREE.TextureLoader();
var textureFlare = textureLoader.load( "textures/lensflare/lensflare.png" );
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 flareColor = new THREE.Color( 0xffffff );
flareColor.setHSL( h, s, l + 0.5 );
var lensFlareGroup = new THREE.LensFlareGroup();
var lensFlare = new THREE.LensFlare( textureFlare, 700, 0.0, THREE.AdditiveBlending, flareColor );
lensFlare.position.copy( light.position );
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 );
scene.add( lensFlare );
lensFlareGroup.add( lensFlare0 );
lensFlareGroup.add( lensFlare1 );
lensFlareGroup.add( lensFlare2 );
lensFlareGroup.position.copy( light.position );
scene.add( lensFlareGroup );
</code>
</div>
......@@ -44,20 +52,19 @@ scene.add( lensFlare );
<h2>Constructor</h2>
<h3>[name]( [page:Texture texture], [page:Float size], [page:Float distance], [page:Materials blending], [page:Color color] )</h3>
<h3>[name]( [page:Texture texture], [page:Float size], [page:Float distance], [page:Materials blending], [page:Color color], [page:Float opacity] )</h3>
<div>
[page:Texture texture] - (optional) THREE.Texture to use for the flare. <br />
[page:Float size] - (optional) size in pixels (-1 = use texture.width) <br />
[page:Texture texture] - THREE.Texture to use for the flare. <br />
[page:Float size] - (optional) size in pixels <br />
[page:Float distance] - (optional) (0-1) from light source (0 = at light source) <br />
[page:Materials blending] - (optional) [page:Materials Blending Mode] - Defaults to THREE.NormalBlending <br />
[page:Color color] - (optional) the [page:Color] of the lens flare<br /><br />
[page:Float opacity] - (optional) the opacity of the lens flare<br /><br />
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.
</div>
<h2>Properties</h2>
<div>See the base [page:Object3D] class for common properties.</div>
<div>See the base [page:Mesh] class for common properties.</div>
<h3>[property:Boolean isLensFlare]</h3>
<div>
......@@ -67,63 +74,8 @@ scene.add( lensFlare );
</div>
<h3>[property:array lensFlares]</h3>
<div>
The array of flares as set by [page:LensFlare.add] or passed in the constructor.
Each flare is an object with the following defaults:
<code>
{
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
}
</code>
</div>
<h3>[property:Vector3 positionScreen]</h3>
<div>The position of the lens flare on the screen.</div>
<h3>[property:Function customUpdateCallback]</h3>
<div>
A custom update callback. Default is undefined, set this to override [page:.updateLensFlares updateLensFlares]().
</div>
<h2>Methods</h2>
<div>See the base [page:Object3D] class for common methods.</div>
<h3>[method:null add]( [page:Texture texture], [page:Float size], [page:Float distance], [page:Materials blending], [page:Color color] )</h3>
<div>
Adds a lens flare. Takes the same parameters as the constructor.
</div>
<h3>[method:LensFlare clone]()</h3>
<div>
Return a new LensFlare with the same parameters as this one.
</div>
<h3>[method:LensFlare copy]( [page:LensFlare source] )</h3>
<div>
Copy the parameters from the [page:LensFlare source] LensFlare into this one.
</div>
<h3>[method:null updateLensFlares]()</h3>
<div>
Updates [page:.lensFlares lensFlares] based on the [page:LensFlare.positionScreen positionScreen]
property.<br /><br />
Can be overridden by setting the [page:.customUpdateCallback customUpdateCallback] function.
</div>
<h2>Source</h2>
[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
[link:https://github.com/mrdoob/three.js/blob/master/examples/js/objects/LensFlare.js examples/js/objects/LensFlare.js]
</body>
</html>
......@@ -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"
},
......
/**
* @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;
} )();
......@@ -43,6 +43,7 @@
<script src="../build/three.js"></script>
<script src="js/controls/FlyControls.js"></script>
<script src="js/objects/LensFlare.js"></script>
<script src="js/libs/stats.min.js"></script>
......@@ -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 );
}
......
......@@ -1771,3 +1771,11 @@ export var SceneUtils = {
}
};
//
export function LensFlare() {
console.error( 'THREE.LensFlare has been moved to /examples/js/objects/LensFlare.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';
......
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 };
......@@ -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 );
}
......
/**
* @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 };
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册