UNPKG

three.fbo-helper

Version:

FrameBuffer Object inspector for three.js

927 lines (716 loc) 25.5 kB
<!doctype html> <html lang="en"> <head> <title>Demo</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> <style> *{ box-sizing: border-box; font-family: 'Roboto Slab', sans-serif; font-size: 13px; font-weight: 100; margin :0; padding: 0; } html { height: 100%; } body { margin: 0; padding: 0; background-color: #000000; color: #ffffff; line-height: 1.4em; height: 100%; overflow: hidden; font-family: 'Roboto Slab', sans-serif; font-size: 13px; font-weight: 100; } #container { position: absolute; left: 0; top: 0; right: 0; bottom: 0; } #info{ position: absolute; left: 2em; bottom: 1em; z-index: 10000; } #info h1{ font-weight: bold } #info p{ margin-bottom: 1em; } #info a{ font: inherit; color: inherit; } </style> </head> <body> <div id="container"></div> <div id="info"> <h1>Demo for THREE.FBOHelper · <a href="https://github.com/spite/THREE.FBOHelper" >GitHub</a></h1> <p>FrameBuffer Object inspector for three.js</p> <p>Number of particles: <a href="#128" >Mobile</a> <a href="#512" >Normal</a> <a href="#1024" >More!</a> <a href="#2048" >MOAR!</a></p> <p>Click the FBO buttons on the top left.<br/>You can drag the viewer, zoom in and out with scroll.<br/>Hover to see the values in the FBO.</p> <p>Click and drag to rotate the scene, press Space to freeze and unfreeze.</p> <p><a href="https://twitter.com/thespite" >@thespite</a> · <a href="https://clicktorelease.com" >clicktorelease.com</a> </div> <script src="js/three.js"></script> <script src="../src/THREE.FBOHelper.js"></script> <script src="js/isMobile.min.js"></script> <script src="js/OrbitControls.js"></script> <script src="js/Maf.js"></script> <script src="js/dat.gui.min.js"></script> <script> window.onhashchange = function() { window.location.reload() } </script> <script id="ortho-vs" type="x-shader/x-vertex" > precision highp float; attribute vec3 position; attribute vec2 uv; uniform mat4 modelViewMatrix; uniform mat4 projectionMatrix; varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1. ); } </script> <script id="velocity-fs" type="x-shader/x-fragment" > precision highp float; uniform sampler2D inputTexture; uniform sampler2D infoTexture; uniform sampler2D positionTexture; uniform sampler2D originalTexture; uniform float time; uniform vec4 sphere[ 20 ]; uniform vec4 sphereVelocities[ 20 ]; uniform mat4 sphereRotationMatrix; uniform float bounce; uniform float friction; uniform float gravity; uniform float pressure; varying vec2 vUv; const float PI = 3.14159265359; float random(vec2 co){ return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); } float hash( float n ) { // 0 - 1 return fract(sin(n)*3538.5453); } vec3 randomSphereDir(vec2 rnd) { float s = rnd.x*PI*2.; float t = rnd.y*2.-1.; return vec3(sin(s), cos(s), t) / sqrt(1.0 + t * t); } vec3 randomHemisphereDir(vec3 dir, float i) { vec3 v = randomSphereDir( vec2(hash(i+1.), hash(i+2.)) ); return v * sign(dot(v, dir)); } void main() { vec4 info = texture2D( infoTexture, vUv ); vec4 c = texture2D( inputTexture, vUv ); vec4 p = texture2D( positionTexture, vUv ); if( p.a == 0. ) { vec4 o = texture2D( originalTexture, vUv ); c.xyz = normalize( o.xyz ); c.y = 0.; } c.y -= .1 * pressure; c.y -= .1 * info.x * gravity; c *= .99; if( ( p.y + c.y ) < -500. ) { vec3 n = vec3( 0., 1., 0. ); vec3 i = normalize( c.xyz ); float f = length( c.xyz ); c.xyz = f * randomHemisphereDir( reflect( i, n ), hash( length( c ) + time ) ); c.xz *= bounce; c.xyz *= friction; } for( int j = 0; j < 20; j++ ) { float r = sphere[ j ].a; vec3 pp = ( sphereRotationMatrix * vec4( sphere[ j ].xyz, 0. ) ).xyz - ( p.xyz + c.xyz ); float d = ( r * r ) / ( pp.x * pp.x + pp.y * pp.y + pp.z * pp.z ) ; if( d >= .9 ) { vec3 n = normalize( pp.xyz ); vec3 i = normalize( c.xyz ); float f = length( c.xyz ); vec3 r = reflect( i, n ); c.xyz = f * randomHemisphereDir( r, hash( length( c ) + time ) ); c *= bounce; c.xyz += sphereVelocities[ j ].xyz; c.xyz *= friction; } } gl_FragColor = c; } </script> <script id="position-fs" type="x-shader/x-fragment" > precision highp float; uniform sampler2D originalTexture; uniform sampler2D infoTexture; uniform sampler2D inputTexture; uniform sampler2D velocityTexture; uniform float spread; varying vec2 vUv; void main() { vec4 c = texture2D( inputTexture, vUv ); vec4 i = texture2D( infoTexture, vUv ); vec4 or = texture2D( originalTexture, vUv ); if( c.a == 0. ) { c = or * vec4( spread, 1., spread, 1. ); } float delta = 1.; vec4 v = texture2D( velocityTexture, vUv ); c.xyz += delta * i.x * v.xyz; c.a += delta * i.x; if( c.a > 1000. ) c.a = 0.; gl_FragColor = vec4( c ); } </script> <script id="particle-vs" type="x-shader/x-vertex"> precision highp float; attribute vec3 position; attribute vec2 uv; attribute vec2 id; uniform mat4 modelMatrix; uniform mat4 modelViewMatrix; uniform mat4 projectionMatrix; uniform mat4 prevModelViewMatrix; uniform mat4 prevProjectionMatrix; uniform vec2 dimensions; uniform float size; uniform vec3 cameraPosition; uniform sampler2D infoTexture; uniform sampler2D originalTexture; uniform sampler2D positionTexture; uniform sampler2D previousPositionTexture; uniform sampler2D velocityTexture; varying vec2 vUv; varying float life; varying vec2 vSpeed; varying float vSize; float modI(float a,float b) { float m=a-floor((a+0.5)/b)*b; return floor(m+0.5); } const float PI = 3.14159265359; void main() { float ptr = id.x; float u = modI( ptr, dimensions.x ) / dimensions.x; float v = ( ptr / dimensions.x ) / dimensions.y; vec2 puv = vec2( u, v ); vec4 velocity = texture2D( velocityTexture, puv ); vSpeed = .1 * ( projectionMatrix * modelViewMatrix * vec4( velocity.xyz, 1. ) ).xy; vec4 i = texture2D( infoTexture, puv ); vec4 c = texture2D( positionTexture, puv ); vec3 p = c.xyz; vUv = uv; float delta = 10.; life = 1. - ( c.a / 1000. ); if( c.a == 0. ) life = 0.; vec4 modified = modelViewMatrix * vec4( p, 1. ); float a = -atan( vSpeed.y, vSpeed.x ) - .5 * PI; float l = clamp( length( vSpeed ), .5, 4. ); mat2 rot = mat2( cos( a ), -sin( a ), sin( a ), cos( a ) ); modified.xyz += size * i.x * 10. * vec3( rot * position.xy, 0. ); gl_Position = projectionMatrix * modified; /* vec4 prev = texture2D( previousPositionTexture, uv ); vSpeed = gl_Position.xy - ( prevProjectionMatrix * prevModelViewMatrix * vec4( prev.xyz, 1. ) ).xy; vSpeed += gl_Position.xy - ( prevProjectionMatrix * prevModelViewMatrix * vec4( p.xyz, 1. ) ).xy;*/ } </script> <script id="particle-fs" type="x-shader/x-vertex"> precision highp float; varying float vSize; varying vec2 vUv; varying float life; varying vec2 vSpeed; uniform float useTriangles; void main() { if( useTriangles == 1. ) { float d = 1.; gl_FragColor = vec4( vSpeed, life, d * life ); } else { vec2 barycenter = vec2( .5, .6666 ); float d = smoothstep( .5, .55, 1. - 2. * length( vUv - barycenter ) ); if( d <= 0. ) discard; gl_FragColor = vec4( vSpeed, life, d * life ); } } </script> <script id="object-vs" type="x-shader/x-fragment" > precision highp float; attribute vec3 position; attribute vec3 normal; uniform mat4 modelViewMatrix; uniform mat4 projectionMatrix; uniform mat3 normalMatrix; varying vec3 vPosition; varying vec3 vNormal; void main() { vec4 pos = modelViewMatrix * vec4( position, 1.0 ); vPosition = pos.xyz; vNormal = normalMatrix * normal; gl_Position = projectionMatrix * pos; } </script> <script id="object-fs" type="x-shader/x-fragment" > precision highp float; varying vec3 vPosition; varying vec3 vNormal; void main() { float rim = max( 0., abs( dot( normalize( vNormal ), normalize( -vPosition ) ) ) ); float r = .1 * smoothstep( .25, .75, 1. - rim ); vec3 c = vec3( 149., 200., 233. ) / 255.; float h = ( vPosition.y + 500. ) / 2000.; gl_FragColor = vec4( c * ( r * h ), 1. ); } </script> <script id="final-fs" type="x-shader/x-fragment" > precision highp float; uniform sampler2D motionBuffer; uniform vec2 dimensions; uniform float time; varying vec2 vUv; float random(vec2 n, float offset ){ return .5 - fract(sin(dot(n.xy + vec2( offset, 0. ), vec2(12.9898, 78.233)))* 43758.5453); } void main() { vec4 motion = texture2D( motionBuffer, vUv ); vec2 inc = motion.xy / dimensions; vec2 sum = motion.ba; vec2 uv = vUv - 10. * inc; for(int i = 1; i < 20; ++i ) { uv += inc; uv += .0001 * vec2( random( uv.xy, .0001 * time ), random( uv.yx, .00011 * time ) ); sum += texture2D( motionBuffer, uv ).ba; } sum /= 20.; vec3 color = mix( vec3( 149., 200., 233. ) / 255., vec3( 24., 113., 169. ) / 255., motion.b ); float v = clamp( length( motion.xy ), 0., 1. ); color = mix( vec3( 1. ), color, v ); color *= sum.x; color += vec3( .25 * random( vUv, .00001 * time ) ); float boost = 1.4; float reduction = 1.; vec2 center = vec2( 0.5 ); float vignette = length( vUv - .5 ); vignette = boost - vignette * reduction; color *= vignette; gl_FragColor = vec4( color, sum.y ); } </script> <script> 'use strict'; var camera, controls, geometry, scene, material, particleGeometry, particleMaterial, particleSystem, renderer, container, mesh, helper, sphere; var positionSim, velocitySim; var spheres = [], sphereMesh = [], sphereObject = new THREE.Object3D(); var floor, world; var container = document.getElementById( 'container' ); var Params = function() { this.bounce = .5; this.friction = .99; this.pressure = .1; this.spread = .5; this.gravity = .5; this.size = 1.; this.useTriangles = false; this.showSpheres = true; this.jet = function() { this.bounce = .5; this.friction = .99; this.pressure = .1; this.spread = .1; this.size = 1.; }.bind( this ); this.rain = function() { this.bounce = .66; this.friction = .99; this.pressure = .1; this.spread = 2; this.size = .7; }.bind( this ); this.confetti = function() { this.bounce = 0; this.friction = .4; this.pressure = .1; this.spread = 1.11; this.size = .6; }.bind( this ); this.sand = function() { this.bounce = .09; this.friction = .1; this.pressure = .1; this.spread = .5; this.size = .5; }.bind( this ); this.waterfall = function() { this.bounce = .29; this.friction = .1; this.pressure = .1; this.spread = .37; this.size = .3; }.bind( this ); }; var params = new Params(); window.addEventListener( 'load', init ); function createFBO( width, height ) { var fbo = new THREE.WebGLRenderTarget( width, height, { wrapS: THREE.ClampToEdgeWrapping, wrapT: THREE.ClampToEdgeWrapping, minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat, type: THREE.FloatType, stencilBuffer: false, depthBuffer: false }); fbo.texture.generateMipmaps = false; return fbo; } function createRenderTarger( width, height ) { var rt = new THREE.WebGLRenderTarget( width, height, { wrapS: THREE.ClampToEdgeWrapping, wrapT: THREE.ClampToEdgeWrapping, format: THREE.RGBAFormat, type: isMobile.any ? THREE.HalfFloatType : THREE.FloatType, stencilBuffer: false, depthBuffer: true }); rt.flipY = true; return rt; } var motionRT = createRenderTarger( 1, 1 ), colorRT = createRenderTarger( 1, 1 ); var rtScene, rtQuad, rtShader, rtCamera; var size = window.location.hash.substr( 1 ) ||( isMobile.any ? 64 : 256 ); var width = size; var height = size; function GPUSim( renderer, width, height, shader ) { this.renderer = renderer; this.shader = shader; this.orthoScene = new THREE.Scene(); var fbo = createFBO( width, height ); this.fbos = [ fbo, fbo.clone() ]; this.current = 0; this.output = this.fbos[ 0 ]; this.orthoCamera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, .00001, 1000 ); this.orthoQuad = new THREE.Mesh( new THREE.PlaneBufferGeometry( width, height ), this.shader ); this.orthoScene.add( this.orthoQuad ); } GPUSim.prototype.render = function() { this.shader.uniforms.inputTexture.value = this.fbos[ this.current ]; this.input = this.fbos[ this.current ]; this.current = 1 - this.current; this.output = this.fbos[ this.current ]; this.renderer.render( this.orthoScene, this.orthoCamera, this.output ); } function init() { container = document.getElementById( 'container' ); scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, .01, 10000 ); camera.target = new THREE.Vector3( 0, 0, 0 ); camera.position.set( -573.2129761886051, -319.17158861924224, -212.626789135172 ); camera.position.set( -386.9360624668476, 592.0399594581557, -163.735637229391 ); camera.position.set( -881.9551097834948, -469.4538738739556, -327.1511479058356 ); //camera.position.set( 2.2142345804263397, 860.3191694902855, 1309.7027716556265 ); scene.add( camera ); world = new THREE.Object3D(); scene.add( world ); renderer = new THREE.WebGLRenderer( { antialias: true, alpha: false } ); renderer.setPixelRatio( window.devicePixelRatio ); helper = new FBOHelper( renderer ); container.appendChild( renderer.domElement ); var light = new THREE.HemisphereLight( 0xffffbb, 0x080820, 1 ); world.add( light ); var material = new THREE.RawShaderMaterial( { vertexShader: document.getElementById( 'object-vs' ).textContent, fragmentShader: document.getElementById( 'object-fs' ).textContent }); controls = new THREE.OrbitControls( camera, renderer.domElement ); controls.noPan = true; var ptr = 0; var data = new Float32Array( width * height * 4 ); var data2 = new Float32Array( width * height * 4 ); for( var y = 0; y < height; y++ ) { for( var x = 0; x < width; x++ ) { var a = Maf.randomInRange( 0, 1 ); var b = Maf.randomInRange( 0, 1 ); if( a > b ) { var tmp = b; b = a; a = tmp; } var px = b * 400 * Math.cos( 2 * Math.PI * a / b ); var pz = b * 400 * Math.sin( 2 * Math.PI * a / b ); data[ ptr ] = px data[ ptr + 1 ] = Maf.randomInRange( 1000, 2000 ); data[ ptr + 2 ] = pz; data[ ptr + 3 ] = Maf.randomInRange( 1, 499 ); data2[ ptr ] = Maf.randomInRange( 1, 2 ); ptr += 4; } } var texture = new THREE.DataTexture( data, width, height, THREE.RGBAFormat, THREE.FloatType ); texture.minFilter = THREE.NearestFilter; texture.magFilter = THREE.NearestFilter; texture.needsUpdate = true; var texture2 = new THREE.DataTexture( data2, width, height, THREE.RGBAFormat, THREE.FloatType ); texture2.minFilter = THREE.NearestFilter; texture2.magFilter = THREE.NearestFilter; texture2.needsUpdate = true; var uniformSpheres = []; var uniformSpheresVelocities = []; for( var j = 0; j < 20; j++ ) { var r = Maf.randomInRange( 100, 200 ); var x = Maf.randomInRange( -400, 400 ); var y = Maf.randomInRange( -400, 400 ); var z = Maf.randomInRange( -400, 400 ); spheres.push( { origin: new THREE.Vector3( x, y, z ), radius: r, orbit: Maf.randomInRange( 50, 100 ), speed: Maf.randomInRange( 1, 2 ), beat: Maf.randomInRange( 1, 2 ) } ); uniformSpheres.push( new THREE.Vector4( 0, 0, 0, 0 ) ); uniformSpheresVelocities.push( new THREE.Vector4( 0, 0, 0, 0 ) ); var s = new THREE.Mesh( new THREE.IcosahedronGeometry( 1, 3 ), material ); s.scale.set( r, r, r ); sphereObject.add( s ); sphereMesh.push( s ); } world.add( sphereObject ); var velocityShader = new THREE.RawShaderMaterial( { uniforms:{ time: { type: 'f', value: 0 }, bounce: { type: 'f', value: .5 }, friction: { type: 'f', value: .99 }, gravity: { type: 'f', value: .1 }, pressure: { type: 'f', value: .1 }, infoTexture: { type: 't', value: texture2 }, originalTexture: { type: 't', value: texture }, positionTexture: { type: 't', value: texture }, inputTexture: { type: 't', value: null }, sphere: { type: 'v4v', value: uniformSpheres }, sphereVelocities: { type: 'v4v', value: uniformSpheresVelocities }, sphereRotationMatrix: { type: 'm4', value: new THREE.Matrix4() } }, vertexShader: document.getElementById( 'ortho-vs' ).textContent, fragmentShader: document.getElementById( 'velocity-fs' ).textContent, depthTest: false, depthWrite: false } ); velocitySim = new GPUSim( renderer, width, height, velocityShader ); helper.attach( velocitySim.fbos[ 0 ], 'Velocity FBO#0' ); helper.attach( velocitySim.fbos[ 1 ], 'Velocity FBO#1' ); var positionShader = new THREE.RawShaderMaterial( { uniforms:{ spread: { type: 'f', value: 1. }, originalTexture: { type: 't', value: texture }, infoTexture: { type: 't', value: texture2 }, inputTexture: { type: 't', value: null }, velocityTexture: { type: 't', value: null } }, vertexShader: document.getElementById( 'ortho-vs' ).textContent, fragmentShader: document.getElementById( 'position-fs' ).textContent, depthTest: false, depthWrite: false } ); positionSim = new GPUSim( renderer, width, height, positionShader ); helper.attach( positionSim.fbos[ 0 ], 'Position FBO#0' ); helper.attach( positionSim.fbos[ 1 ], 'Position FBO#1' ); particleGeometry = new THREE.BufferGeometry(); var dimensions = new THREE.Vector2( width, height ); var particles = width * height * 3; var positions = new Float32Array( particles * 3 ); var uvs = new Float32Array( particles * 2 ); var ids = new Float32Array( particles * 2 ); var h = Math.sqrt( 1 * 1 - .5 * .5 ); var points = [ new THREE.Vector3( -.5, - .5 * h ), new THREE.Vector3( 0, .5 * h ), new THREE.Vector3( .5, - .5 * h ) ]; var coords = [ new THREE.Vector2( 0, 1 ), new THREE.Vector2( .5, 0 ), new THREE.Vector2( 1, 1 ) ]; for ( var i = 0, i2 = 0; i < particles * 3; i += 3, i2++ ) { positions[ i + 0 ] = points[ i2 % 3 ].x; positions[ i + 1 ] = points[ i2 % 3 ].y; positions[ i + 2 ] = points[ i2 % 3 ].z; } for ( var i = 0, i2 = 0; i < particles * 2; i += 2, i2++ ) { uvs[ i + 0 ] = coords[ i2 % 3 ].x; uvs[ i + 1 ] = coords[ i2 % 3 ].y; } for ( var i = 0, i2 = 0; i < particles * 2; i += 6, i2++ ) { ids[ i + 0 ] = i2; ids[ i + 1 ] = i2; ids[ i + 2 ] = i2; ids[ i + 3 ] = i2; ids[ i + 4 ] = i2; ids[ i + 5 ] = i2; } particleGeometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) ); particleGeometry.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) ); particleGeometry.addAttribute( 'id', new THREE.BufferAttribute( ids, 2 ) ); particleMaterial = new THREE.RawShaderMaterial( { uniforms:{ size: { type: 'f', value: 1 }, useTriangles: { type: 'f', value: 0 }, originalTexture: { type: 't', value: texture }, infoTexture: { type: 't', value: texture2 }, positionTexture: { type: 't', value: positionSim.fbos[ 0 ] }, previousPositionTexture: { type: 't', value: positionSim.fbos[ 1 ] }, velocityTexture: { type: 't', value: velocitySim.fbos[ 1 ] }, dimensions: { type: 'v2', value: dimensions }, cameraPosition: { type: 'v3', value: new THREE.Vector3() }, prevModelViewMatrix: { type: 'm4', value: new THREE.Matrix4() }, prevProjectionMatrix: { type: 'm4', value: new THREE.Matrix4() } }, vertexShader: document.getElementById( 'particle-vs' ).textContent, fragmentShader: document.getElementById( 'particle-fs' ).textContent, transparent: false, side: THREE.DoubleSide, depthTest: true, depthWrite: true } ); particleSystem = new THREE.Mesh( particleGeometry, particleMaterial ); world.add( particleSystem ); rtShader = new THREE.RawShaderMaterial( { uniforms:{ time: { type: 'f', value: 0 }, motionBuffer: { type: 't', value: null }, dimensions: { type: 'v2', value: new THREE.Vector2( 1, 1 ) } }, vertexShader: document.getElementById( 'ortho-vs' ).textContent, fragmentShader: document.getElementById( 'final-fs' ).textContent, depthTest: false, depthWrite: false } ); rtScene = new THREE.Scene(); rtCamera = new THREE.OrthographicCamera( 1 / - 2, 1 / 2, 1 / 2, 1 / - 2, .00001, 1000 ); rtQuad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 1, 1 ), rtShader ); rtScene.add( rtQuad ); helper.attach( motionRT, 'Motion', function( i ) { return 'Speed: (' + i.r + ', ' + i.g + ')<br/>Life: ' + i.b + ' dLife: ' + i.a } ); var gui = new dat.GUI(); gui.add( params, "bounce", 0, 1 ).listen();; gui.add( params, "friction", 0, 1 ).listen();; gui.add( params, "pressure", 0, 1 ).listen();; gui.add( params, "gravity", .1, 1 ).listen();; gui.add( params, "spread", 0, 2 ).listen();; gui.add( params, "size", .1, 2 ).listen();; gui.add( params, "useTriangles" ); gui.add( params, "showSpheres" ); gui.add( params, "jet" ); gui.add( params, "rain" ); gui.add( params, "confetti" ); gui.add( params, "sand" ); gui.add( params, "waterfall" ); window.addEventListener( 'resize', onWindowResized ); onWindowResized(); animate(); } function onWindowResized( event ) { var w = container.clientWidth; var h = container.clientHeight; renderer.setSize( w, h ); camera.aspect = w / h; camera.updateProjectionMatrix(); helper.setSize( w, h ); motionRT.setSize( w, h ); colorRT.setSize( w, h ); rtCamera.left = - w / 2; rtCamera.right = w / 2; rtCamera.top = h / 2; rtCamera.bottom = - h / 2; rtCamera.updateProjectionMatrix(); rtQuad.scale.set( w, h, 1 ); rtShader.uniforms.dimensions.value.set( w, h ); helper.refreshFBO( motionRT ); } function animate() { controls.update(); requestAnimationFrame( animate ); render(); } var tmpVector = new THREE.Vector3(); var runAnimation = true; window.addEventListener( 'keydown', function(e ) { if( e.keyCode === 32 ) runAnimation = !runAnimation; } ); var time = 0; var lastTime = 0; var tmpVector = new THREE.Vector4(); function render() { velocitySim.shader.uniforms.bounce.value = params.bounce; velocitySim.shader.uniforms.friction.value = params.friction; velocitySim.shader.uniforms.gravity.value = params.gravity; velocitySim.shader.uniforms.pressure.value = params.pressure; positionSim.shader.uniforms.spread.value = params.spread; particleMaterial.uniforms.size.value = params.size; particleMaterial.uniforms.useTriangles.value = params.useTriangles ? 1 : 0; sphereObject.visible = params.showSpheres; if( runAnimation ) { time += .0005 * ( performance.now() - lastTime ); spheres.forEach( function( s, i ) { var r = 400; tmpVector.copy( velocitySim.shader.uniforms.sphere.value[ i ] ); velocitySim.shader.uniforms.sphere.value[ i ].set( s.origin.x + s.orbit * Math.cos( s.speed * time ), s.origin.y, s.origin.z + s.orbit * Math.sin( s.speed * time ), s.radius * ( .75 + .25 * Math.cos( .1 * s.beat * time ) ) ); velocitySim.shader.uniforms.sphereVelocities.value[ i ].copy( velocitySim.shader.uniforms.sphere.value[ i ] ); velocitySim.shader.uniforms.sphereVelocities.value[ i ].sub( tmpVector ); sphereMesh[ i ].position.set( velocitySim.shader.uniforms.sphere.value[ i ].x, velocitySim.shader.uniforms.sphere.value[ i ].y, velocitySim.shader.uniforms.sphere.value[ i ].z ); var scale = velocitySim.shader.uniforms.sphere.value[ i ].w; sphereMesh[ i ].scale.set( scale, scale, scale ); } ) velocitySim.shader.uniforms.time.value = time; sphereObject.rotation.z = time; velocitySim.shader.uniforms.sphereRotationMatrix.value.makeRotationZ( time ); velocitySim.render(); positionSim.shader.uniforms.velocityTexture.value = velocitySim.output; positionSim.render(); particleMaterial.uniforms.positionTexture.value = positionSim.output; particleMaterial.uniforms.previousPositionTexture.value = positionSim.input; particleMaterial.uniforms.velocityTexture.value = velocitySim.output; velocitySim.shader.uniforms.positionTexture.value = positionSim.output; world.rotation.y = .1 * time; } particleMaterial.uniforms.cameraPosition.value.copy( camera.position ); renderer.render( scene, camera, motionRT ); rtShader.uniforms.time.value = time; rtShader.uniforms.motionBuffer.value = motionRT; renderer.render( rtScene, rtCamera ); particleMaterial.uniforms.prevModelViewMatrix.value.multiplyMatrices( camera.matrixWorldInverse, particleSystem.matrixWorld ); particleMaterial.uniforms.prevProjectionMatrix.value.copy( camera.projectionMatrix ); helper.update(); lastTime = performance.now(); } </script> </body> </html>