three.fbo-helper
Version:
FrameBuffer Object inspector for three.js
927 lines (716 loc) • 25.5 kB
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>;
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>