diff --git a/source/core/objects/misc/LensFlare.js b/source/core/objects/misc/LensFlare.js index ba2f36abf..ec3becf11 100644 --- a/source/core/objects/misc/LensFlare.js +++ b/source/core/objects/misc/LensFlare.js @@ -23,7 +23,11 @@ function LensFlare() this.name = "lensflare"; this.type = "LensFlare"; + this.frustumCulled = false; + this.receiveShadow = false; + this.castShadow = false; + this.elements = []; var positionScreen = new THREE.Vector3(); @@ -171,7 +175,8 @@ function LensFlare() this.dispose = function() { - material1.dispose(); + material1a.dispose(); + material1b.dispose(); material2.dispose(); tempMap.dispose(); occlusionMap.dispose(); diff --git a/source/editor/ui/tab/animation/AnimationTab.js b/source/editor/ui/tab/animation/AnimationTab.js index bb88bab50..87089bfd5 100644 --- a/source/editor/ui/tab/animation/AnimationTab.js +++ b/source/editor/ui/tab/animation/AnimationTab.js @@ -131,16 +131,26 @@ function AnimationTab(parent, closeable, container, index) //Timeline this.timeline = document.createElement("div"); this.timeline.style.position = "absolute"; - this.timeline.style.overflow = "auto"; + this.timeline.style.overflowY = "auto"; + this.timeline.style.overflowX = "hidden"; this.timeline.style.top = "20px"; this.element.appendChild(this.timeline); - //Track information + //Iformation this.info = document.createElement("div"); this.info.style.position = "absolute"; + this.info.style.overflow = "auto"; this.info.style.backgroundColor = Editor.theme.barColor; this.timeline.appendChild(this.info); + //Tracks + this.tracks = document.createElement("div"); + this.tracks.style.position = "absolute"; + this.tracks.style.overflowX = "auto"; + this.tracks.style.overflowY = "visible"; + this.tracks.style.backgroundColor = Editor.theme.panelColor; + this.timeline.appendChild(this.tracks); + //Temporary variables for mouse movement var mouse = 0, initial = 0; @@ -171,20 +181,14 @@ function AnimationTab(parent, closeable, container, index) { self.tabManager.destroy(); }); - - //Tracks - this.tracks = document.createElement("div"); - this.tracks.style.position = "absolute"; - this.tracks.style.backgroundColor = Editor.theme.panelColor; - this.timeline.appendChild(this.tracks); } AnimationTab.prototype = Object.create(TabElement.prototype); -AnimationTab.prototype.attach = function() +AnimationTab.prototype.attach = function(object) { - TabElement.prototype.attach.call(this); - + this.object = object; + this.createAnimationMixer(); this.createTimeline(); }; @@ -209,10 +213,7 @@ AnimationTab.prototype.deactivate = function() //Attach object to animation editor AnimationTab.prototype.updateSelection = function() { - this.object = Editor.selectedObjects.length > 0 ? Editor.selectedObjects[0] : null; - - this.createAnimationMixer(); - this.createTimeline(); + this.attach(Editor.selectedObjects.length > 0 ? Editor.selectedObjects[0] : null); }; //Create a new animation mixer @@ -366,20 +367,25 @@ AnimationTab.prototype.updateInterface = function() this.element.style.width = this.size.x + "px"; this.element.style.height = this.size.y + "px"; + //Options bar + this.bar.style.width = this.size.x + "px"; + + //Timeline this.timeline.style.width = this.size.x + "px"; this.timeline.style.height = (this.size.y - 20) + "px"; - this.bar.style.width = this.size.x + "px"; - - //Resizable division + //Information this.info.style.height = this.timeline.scrollHeight + "px"; this.info.style.width = this.tab.position + "px"; + //Tab this.tab.style.height = this.timeline.scrollHeight + "px"; this.tab.style.left = this.info.style.width; + //Tracks this.tracks.style.left = (this.tab.position + 5) + "px"; this.tracks.style.width = (this.size.x - this.tab.position - 5) + "px"; + this.tracks.style.height = "100px"; } else { diff --git a/source/lib/three/objects/LensFlare.js b/source/lib/three/objects/LensFlare.js index e69de29bb..5f427ddf5 100644 --- a/source/lib/three/objects/LensFlare.js +++ b/source/lib/three/objects/LensFlare.js @@ -0,0 +1,367 @@ +/** + * @author Mugen87 / https://github.com/Mugen87 + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Lensflare = function () { + + THREE.Mesh.call( this, THREE.Lensflare.Geometry, new THREE.MeshBasicMaterial( { opacity: 0, transparent: true } ) ); + + this.type = 'Lensflare'; + this.frustumCulled = false; + + // + + var positionScreen = new THREE.Vector3(); + + // textures + + var tempMap = new THREE.DataTexture( new Uint8Array( 16 * 16 * 3 ), 16, 16, THREE.RGBFormat ); + tempMap.minFilter = THREE.NearestFilter; + tempMap.magFilter = THREE.NearestFilter; + tempMap.wrapS = THREE.ClampToEdgeWrapping; + tempMap.wrapT = THREE.ClampToEdgeWrapping; + tempMap.needsUpdate = true; + + var occlusionMap = new THREE.DataTexture( new Uint8Array( 16 * 16 * 3 ), 16, 16, THREE.RGBFormat ); + occlusionMap.minFilter = THREE.NearestFilter; + occlusionMap.magFilter = THREE.NearestFilter; + occlusionMap.wrapS = THREE.ClampToEdgeWrapping; + occlusionMap.wrapT = THREE.ClampToEdgeWrapping; + occlusionMap.needsUpdate = true; + + // material + + var geometry = THREE.Lensflare.Geometry; + + var shader = THREE.Lensflare.Shader; + + var material1a = new THREE.RawShaderMaterial( { + uniforms: { + 'scale': { value: null }, + 'screenPosition': { value: null } + }, + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader1, + depthTest: true, + depthWrite: false, + transparent: false + } ); + + var material1b = new THREE.RawShaderMaterial( { + uniforms: { + 'map': { value: tempMap }, + 'scale': { value: null }, + 'screenPosition': { value: null } + }, + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader2, + depthTest: false, + depthWrite: false, + transparent: false + } ); + + // the following object is used for occlusionMap generation + + var mesh1 = new THREE.Mesh( geometry, material1a ); + + // + + var elements = []; + + var shader = THREE.LensflareElement.Shader; + + var material2 = new THREE.RawShaderMaterial( { + uniforms: { + 'map': { value: null }, + 'occlusionMap': { value: occlusionMap }, + 'color': { value: new THREE.Color( 0xffffff ) }, + 'scale': { value: new THREE.Vector2() }, + 'screenPosition': { value: new THREE.Vector3() } + }, + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader, + blending: THREE.AdditiveBlending, + transparent: true, + depthWrite: false + } ); + + var mesh2 = new THREE.Mesh( geometry, material2 ); + + this.addElement = function ( element ) { + + elements.push( element ); + + }; + + // + + var scale = new THREE.Vector2(); + var screenPositionPixels = new THREE.Vector2(); + var validArea = new THREE.Box2(); + var viewport = new THREE.Vector4(); + + this.onBeforeRender = function ( renderer, scene, camera ) { + + viewport.copy( renderer.getCurrentViewport() ); + + var invAspect = viewport.w / viewport.z; + var halfViewportWidth = viewport.z / 2.0; + var halfViewportHeight = viewport.w / 2.0; + + 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 + + positionScreen.setFromMatrixPosition( this.matrixWorld ); + + positionScreen.applyMatrix4( camera.matrixWorldInverse ); + positionScreen.applyMatrix4( camera.projectionMatrix ); + + // horizontal and vertical coordinate of the lower left corner of the pixels to copy + + screenPositionPixels.x = viewport.x + ( positionScreen.x * halfViewportWidth ) + halfViewportWidth - 8; + screenPositionPixels.y = viewport.y + ( positionScreen.y * halfViewportHeight ) + halfViewportHeight - 8; + + // screen cull + + if ( validArea.containsPoint( screenPositionPixels ) ) { + + // save current RGB to temp texture + + renderer.copyFramebufferToTexture( screenPositionPixels, tempMap ); + + // render pink quad + + var uniforms = material1a.uniforms; + uniforms.scale.value = scale; + uniforms.screenPosition.value = positionScreen; + + renderer.renderBufferDirect( camera, null, geometry, material1a, mesh1, null ); + + // copy result to occlusionMap + + renderer.copyFramebufferToTexture( screenPositionPixels, occlusionMap ); + + // restore graphics + + var uniforms = material1b.uniforms; + uniforms.scale.value = scale; + uniforms.screenPosition.value = positionScreen; + + renderer.renderBufferDirect( camera, null, geometry, material1b, mesh1, null ); + + // render elements + + var vecX = - positionScreen.x * 2; + var vecY = - positionScreen.y * 2; + + for ( var i = 0, l = elements.length; i < l; i ++ ) { + + var element = elements[ i ]; + + var uniforms = material2.uniforms; + + uniforms.color.value.copy( element.color ); + uniforms.map.value = element.texture; + uniforms.screenPosition.value.x = positionScreen.x + vecX * element.distance; + uniforms.screenPosition.value.y = positionScreen.y + vecY * element.distance; + + var size = element.size / viewport.w; + var invAspect = viewport.w / viewport.z; + + uniforms.scale.value.set( size * invAspect, size ); + + material2.uniformsNeedUpdate = true; + + renderer.renderBufferDirect( camera, null, geometry, material2, mesh2, null ); + + } + + } + + }; + + this.dispose = function () { + + material1.dispose(); + material2.dispose(); + + tempMap.dispose(); + occlusionMap.dispose(); + + }; + +}; + +THREE.Lensflare.prototype = Object.create( THREE.Mesh.prototype ); +THREE.Lensflare.prototype.constructor = THREE.Lensflare; +THREE.Lensflare.prototype.isLensflare = true; + +THREE.Lensflare.Shader = { + + 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' ), + + fragmentShader1: [ + + 'precision highp float;', + + 'void main() {', + + ' gl_FragColor = vec4( 1.0, 0.0, 1.0, 1.0 );', + + '}' + + ].join( '\n' ), + + fragmentShader2: [ + + 'precision highp float;', + + 'uniform sampler2D map;', + + 'varying vec2 vUV;', + + 'void main() {', + + ' gl_FragColor = texture2D( map, vUV );', + + '}' + + ].join( '\n' ) + +}; + +// + +THREE.LensflareElement = function ( texture, size, distance, color ) { + + this.texture = texture; + this.size = size || 1; + this.distance = distance || 0; + this.color = color || new THREE.Color( 0xffffff ); + +}; + +THREE.LensflareElement.Shader = { + + uniforms: { + + 'map': { value: null }, + 'occlusionMap': { value: null }, + 'color': { value: null }, + 'scale': { value: null }, + 'screenPosition': { value: null } + + }, + + vertexShader: [ + + 'precision highp float;', + + 'uniform vec3 screenPosition;', + 'uniform vec2 scale;', + + '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;', + + ' gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );', + + '}' + + ].join( '\n' ), + + fragmentShader: [ + + 'precision highp float;', + + 'uniform sampler2D map;', + 'uniform vec3 color;', + + 'varying vec2 vUV;', + 'varying float vVisibility;', + + 'void main() {', + + ' vec4 texture = texture2D( map, vUV );', + ' texture.a *= 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; + +} )();