浏览代码

Remove gpu particle system example

WestLangley 6 年之前
父节点
当前提交
616becaae8
共有 3 个文件被更改,包括 0 次插入678 次删除
  1. 0 1
      examples/files.js
  2. 0 501
      examples/js/objects/GPUParticleSystem.js
  3. 0 176
      examples/webgl_gpu_particle_system.html

+ 0 - 1
examples/files.js

@@ -306,7 +306,6 @@ var files = {
 		"webgl_gpgpu_birds",
 		"webgl_gpgpu_water",
 		"webgl_gpgpu_protoplanet",
-		"webgl_gpu_particle_system",
 		"webgl_lightningstrike",
 		"webgl_lightshafts",
 		"webgl_materials_modified",

+ 0 - 501
examples/js/objects/GPUParticleSystem.js

@@ -1,501 +0,0 @@
-/*
- * GPU Particle System
- * @author flimshaw - Charlie Hoey - http://charliehoey.com
- *
- * A simple to use, general purpose GPU system. Particles are spawn-and-forget with
- * several options available, and do not require monitoring or cleanup after spawning.
- * Because the paths of all particles are completely deterministic once spawned, the scale
- * and direction of time is also variable.
- *
- * Currently uses a static wrapping perlin noise texture for turbulence, and a small png texture for
- * particles, but adding support for a particle texture atlas or changing to a different type of turbulence
- * would be a fairly light day's work.
- *
- * Shader and javascript packing code derrived from several Stack Overflow examples.
- *
- */
-
-THREE.GPUParticleSystem = function ( options ) {
-
-	THREE.Object3D.apply( this, arguments );
-
-	options = options || {};
-
-	// parse options and use defaults
-
-	this.PARTICLE_COUNT = options.maxParticles || 1000000;
-	this.PARTICLE_CONTAINERS = options.containerCount || 1;
-
-	this.PARTICLE_NOISE_TEXTURE = options.particleNoiseTex || null;
-	this.PARTICLE_SPRITE_TEXTURE = options.particleSpriteTex || null;
-
-	this.PARTICLES_PER_CONTAINER = Math.ceil( this.PARTICLE_COUNT / this.PARTICLE_CONTAINERS );
-	this.PARTICLE_CURSOR = 0;
-	this.time = 0;
-	this.particleContainers = [];
-	this.rand = [];
-
-	// custom vertex and fragement shader
-
-	var GPUParticleShader = {
-
-		vertexShader: [
-
-			'uniform float uTime;',
-			'uniform float uScale;',
-			'uniform sampler2D tNoise;',
-
-			'attribute vec3 positionStart;',
-			'attribute float startTime;',
-			'attribute vec3 velocity;',
-			'attribute float turbulence;',
-			'attribute vec3 color;',
-			'attribute float size;',
-			'attribute float lifeTime;',
-
-			'varying vec4 vColor;',
-			'varying float lifeLeft;',
-
-			'void main() {',
-
-			// unpack things from our attributes'
-
-			'	vColor = vec4( color, 1.0 );',
-
-			// convert our velocity back into a value we can use'
-
-			'	vec3 newPosition;',
-			'	vec3 v;',
-
-			'	float timeElapsed = uTime - startTime;',
-
-			'	lifeLeft = 1.0 - ( timeElapsed / lifeTime );',
-
-			'	gl_PointSize = ( uScale * size ) * lifeLeft;',
-
-			'	v.x = ( velocity.x - 0.5 ) * 3.0;',
-			'	v.y = ( velocity.y - 0.5 ) * 3.0;',
-			'	v.z = ( velocity.z - 0.5 ) * 3.0;',
-
-			'	newPosition = positionStart + ( v * 10.0 ) * timeElapsed;',
-
-			'	vec3 noise = texture2D( tNoise, vec2( newPosition.x * 0.015 + ( uTime * 0.05 ), newPosition.y * 0.02 + ( uTime * 0.015 ) ) ).rgb;',
-			'	vec3 noiseVel = ( noise.rgb - 0.5 ) * 30.0;',
-
-			'	newPosition = mix( newPosition, newPosition + vec3( noiseVel * ( turbulence * 5.0 ) ), ( timeElapsed / lifeTime ) );',
-
-			'	if( v.y > 0. && v.y < .05 ) {',
-
-			'		lifeLeft = 0.0;',
-
-			'	}',
-
-			'	if( v.x < - 1.45 ) {',
-
-			'		lifeLeft = 0.0;',
-
-			'	}',
-
-			'	if( timeElapsed > 0.0 ) {',
-
-			'		gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );',
-
-			'	} else {',
-
-			'		gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
-			'		lifeLeft = 0.0;',
-			'		gl_PointSize = 0.;',
-
-			'	}',
-
-			'}'
-
-		].join( '\n' ),
-
-		fragmentShader: [
-
-			'float scaleLinear( float value, vec2 valueDomain ) {',
-
-			'	return ( value - valueDomain.x ) / ( valueDomain.y - valueDomain.x );',
-
-			'}',
-
-			'float scaleLinear( float value, vec2 valueDomain, vec2 valueRange ) {',
-
-			'	return mix( valueRange.x, valueRange.y, scaleLinear( value, valueDomain ) );',
-
-			'}',
-
-			'varying vec4 vColor;',
-			'varying float lifeLeft;',
-
-			'uniform sampler2D tSprite;',
-
-			'void main() {',
-
-			'	float alpha = 0.;',
-
-			'	if( lifeLeft > 0.995 ) {',
-
-			'		alpha = scaleLinear( lifeLeft, vec2( 1.0, 0.995 ), vec2( 0.0, 1.0 ) );',
-
-			'	} else {',
-
-			'		alpha = lifeLeft * 0.75;',
-
-			'	}',
-
-			'	vec4 tex = texture2D( tSprite, gl_PointCoord );',
-			'	gl_FragColor = vec4( vColor.rgb * tex.a, alpha * tex.a );',
-
-			'}'
-
-		].join( '\n' )
-
-	};
-
-	// preload a million random numbers
-
-	var i;
-
-	for ( i = 1e5; i > 0; i -- ) {
-
-		this.rand.push( Math.random() - 0.5 );
-
-	}
-
-	this.random = function () {
-
-		return ++ i >= this.rand.length ? this.rand[ i = 1 ] : this.rand[ i ];
-
-	};
-
-	var textureLoader = new THREE.TextureLoader();
-
-	this.particleNoiseTex = this.PARTICLE_NOISE_TEXTURE || textureLoader.load( 'textures/perlin-512.png' );
-	this.particleNoiseTex.wrapS = this.particleNoiseTex.wrapT = THREE.RepeatWrapping;
-
-	this.particleSpriteTex = this.PARTICLE_SPRITE_TEXTURE || textureLoader.load( 'textures/particle2.png' );
-	this.particleSpriteTex.wrapS = this.particleSpriteTex.wrapT = THREE.RepeatWrapping;
-
-	this.particleShaderMat = new THREE.ShaderMaterial( {
-		transparent: true,
-		depthWrite: false,
-		uniforms: {
-			'uTime': {
-				value: 0.0
-			},
-			'uScale': {
-				value: 1.0
-			},
-			'tNoise': {
-				value: this.particleNoiseTex
-			},
-			'tSprite': {
-				value: this.particleSpriteTex
-			}
-		},
-		blending: THREE.AdditiveBlending,
-		vertexShader: GPUParticleShader.vertexShader,
-		fragmentShader: GPUParticleShader.fragmentShader
-	} );
-
-	// define defaults for all values
-
-	this.particleShaderMat.defaultAttributeValues.particlePositionsStartTime = [ 0, 0, 0, 0 ];
-	this.particleShaderMat.defaultAttributeValues.particleVelColSizeLife = [ 0, 0, 0, 0 ];
-
-	this.init = function () {
-
-		for ( var i = 0; i < this.PARTICLE_CONTAINERS; i ++ ) {
-
-			var c = new THREE.GPUParticleContainer( this.PARTICLES_PER_CONTAINER, this );
-			this.particleContainers.push( c );
-			this.add( c );
-
-		}
-
-	};
-
-	this.spawnParticle = function ( options ) {
-
-		this.PARTICLE_CURSOR ++;
-
-		if ( this.PARTICLE_CURSOR >= this.PARTICLE_COUNT ) {
-
-			this.PARTICLE_CURSOR = 1;
-
-		}
-
-		var currentContainer = this.particleContainers[ Math.floor( this.PARTICLE_CURSOR / this.PARTICLES_PER_CONTAINER ) ];
-
-		currentContainer.spawnParticle( options );
-
-	};
-
-	this.update = function ( time ) {
-
-		for ( var i = 0; i < this.PARTICLE_CONTAINERS; i ++ ) {
-
-			this.particleContainers[ i ].update( time );
-
-		}
-
-	};
-
-	this.dispose = function () {
-
-		this.particleShaderMat.dispose();
-		this.particleNoiseTex.dispose();
-		this.particleSpriteTex.dispose();
-
-		for ( var i = 0; i < this.PARTICLE_CONTAINERS; i ++ ) {
-
-			this.particleContainers[ i ].dispose();
-
-		}
-
-	};
-
-	this.init();
-
-};
-
-THREE.GPUParticleSystem.prototype = Object.create( THREE.Object3D.prototype );
-THREE.GPUParticleSystem.prototype.constructor = THREE.GPUParticleSystem;
-
-
-// Subclass for particle containers, allows for very large arrays to be spread out
-
-THREE.GPUParticleContainer = function ( maxParticles, particleSystem ) {
-
-	THREE.Object3D.apply( this, arguments );
-
-	this.PARTICLE_COUNT = maxParticles || 100000;
-	this.PARTICLE_CURSOR = 0;
-	this.time = 0;
-	this.offset = 0;
-	this.count = 0;
-	this.DPR = window.devicePixelRatio;
-	this.GPUParticleSystem = particleSystem;
-	this.particleUpdate = false;
-
-	// geometry
-
-	this.particleShaderGeo = new THREE.BufferGeometry();
-
-	this.particleShaderGeo.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT * 3 ), 3 ).setDynamic( true ) );
-	this.particleShaderGeo.addAttribute( 'positionStart', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT * 3 ), 3 ).setDynamic( true ) );
-	this.particleShaderGeo.addAttribute( 'startTime', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT ), 1 ).setDynamic( true ) );
-	this.particleShaderGeo.addAttribute( 'velocity', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT * 3 ), 3 ).setDynamic( true ) );
-	this.particleShaderGeo.addAttribute( 'turbulence', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT ), 1 ).setDynamic( true ) );
-	this.particleShaderGeo.addAttribute( 'color', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT * 3 ), 3 ).setDynamic( true ) );
-	this.particleShaderGeo.addAttribute( 'size', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT ), 1 ).setDynamic( true ) );
-	this.particleShaderGeo.addAttribute( 'lifeTime', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT ), 1 ).setDynamic( true ) );
-
-	// material
-
-	this.particleShaderMat = this.GPUParticleSystem.particleShaderMat;
-
-	var position = new THREE.Vector3();
-	var velocity = new THREE.Vector3();
-	var color = new THREE.Color();
-
-	this.spawnParticle = function ( options ) {
-
-		var positionStartAttribute = this.particleShaderGeo.getAttribute( 'positionStart' );
-		var startTimeAttribute = this.particleShaderGeo.getAttribute( 'startTime' );
-		var velocityAttribute = this.particleShaderGeo.getAttribute( 'velocity' );
-		var turbulenceAttribute = this.particleShaderGeo.getAttribute( 'turbulence' );
-		var colorAttribute = this.particleShaderGeo.getAttribute( 'color' );
-		var sizeAttribute = this.particleShaderGeo.getAttribute( 'size' );
-		var lifeTimeAttribute = this.particleShaderGeo.getAttribute( 'lifeTime' );
-
-		options = options || {};
-
-		// setup reasonable default values for all arguments
-
-		position = options.position !== undefined ? position.copy( options.position ) : position.set( 0, 0, 0 );
-		velocity = options.velocity !== undefined ? velocity.copy( options.velocity ) : velocity.set( 0, 0, 0 );
-		color = options.color !== undefined ? color.set( options.color ) : color.set( 0xffffff );
-
-		var positionRandomness = options.positionRandomness !== undefined ? options.positionRandomness : 0;
-		var velocityRandomness = options.velocityRandomness !== undefined ? options.velocityRandomness : 0;
-		var colorRandomness = options.colorRandomness !== undefined ? options.colorRandomness : 1;
-		var turbulence = options.turbulence !== undefined ? options.turbulence : 1;
-		var lifetime = options.lifetime !== undefined ? options.lifetime : 5;
-		var size = options.size !== undefined ? options.size : 10;
-		var sizeRandomness = options.sizeRandomness !== undefined ? options.sizeRandomness : 0;
-		var smoothPosition = options.smoothPosition !== undefined ? options.smoothPosition : false;
-
-		if ( this.DPR !== undefined ) size *= this.DPR;
-
-		var i = this.PARTICLE_CURSOR;
-
-		// position
-
-		positionStartAttribute.array[ i * 3 + 0 ] = position.x + ( particleSystem.random() * positionRandomness );
-		positionStartAttribute.array[ i * 3 + 1 ] = position.y + ( particleSystem.random() * positionRandomness );
-		positionStartAttribute.array[ i * 3 + 2 ] = position.z + ( particleSystem.random() * positionRandomness );
-
-		if ( smoothPosition === true ) {
-
-			positionStartAttribute.array[ i * 3 + 0 ] += - ( velocity.x * particleSystem.random() );
-			positionStartAttribute.array[ i * 3 + 1 ] += - ( velocity.y * particleSystem.random() );
-			positionStartAttribute.array[ i * 3 + 2 ] += - ( velocity.z * particleSystem.random() );
-
-		}
-
-		// velocity
-
-		var maxVel = 2;
-
-		var velX = velocity.x + particleSystem.random() * velocityRandomness;
-		var velY = velocity.y + particleSystem.random() * velocityRandomness;
-		var velZ = velocity.z + particleSystem.random() * velocityRandomness;
-
-		velX = THREE.Math.clamp( ( velX - ( - maxVel ) ) / ( maxVel - ( - maxVel ) ), 0, 1 );
-		velY = THREE.Math.clamp( ( velY - ( - maxVel ) ) / ( maxVel - ( - maxVel ) ), 0, 1 );
-		velZ = THREE.Math.clamp( ( velZ - ( - maxVel ) ) / ( maxVel - ( - maxVel ) ), 0, 1 );
-
-		velocityAttribute.array[ i * 3 + 0 ] = velX;
-		velocityAttribute.array[ i * 3 + 1 ] = velY;
-		velocityAttribute.array[ i * 3 + 2 ] = velZ;
-
-		// color
-
-		color.r = THREE.Math.clamp( color.r + particleSystem.random() * colorRandomness, 0, 1 );
-		color.g = THREE.Math.clamp( color.g + particleSystem.random() * colorRandomness, 0, 1 );
-		color.b = THREE.Math.clamp( color.b + particleSystem.random() * colorRandomness, 0, 1 );
-
-		colorAttribute.array[ i * 3 + 0 ] = color.r;
-		colorAttribute.array[ i * 3 + 1 ] = color.g;
-		colorAttribute.array[ i * 3 + 2 ] = color.b;
-
-		// turbulence, size, lifetime and starttime
-
-		turbulenceAttribute.array[ i ] = turbulence;
-		sizeAttribute.array[ i ] = size + particleSystem.random() * sizeRandomness;
-		lifeTimeAttribute.array[ i ] = lifetime;
-		startTimeAttribute.array[ i ] = this.time + particleSystem.random() * 2e-2;
-
-		// offset
-
-		if ( this.offset === 0 ) {
-
-			this.offset = this.PARTICLE_CURSOR;
-
-		}
-
-		// counter and cursor
-
-		this.count ++;
-		this.PARTICLE_CURSOR ++;
-
-		if ( this.PARTICLE_CURSOR >= this.PARTICLE_COUNT ) {
-
-			this.PARTICLE_CURSOR = 0;
-
-		}
-
-		this.particleUpdate = true;
-
-	};
-
-	this.init = function () {
-
-		this.particleSystem = new THREE.Points( this.particleShaderGeo, this.particleShaderMat );
-		this.particleSystem.frustumCulled = false;
-		this.add( this.particleSystem );
-
-	};
-
-	this.update = function ( time ) {
-
-		this.time = time;
-		this.particleShaderMat.uniforms.uTime.value = time;
-
-		this.geometryUpdate();
-
-	};
-
-	this.geometryUpdate = function () {
-
-		if ( this.particleUpdate === true ) {
-
-			this.particleUpdate = false;
-
-			var positionStartAttribute = this.particleShaderGeo.getAttribute( 'positionStart' );
-			var startTimeAttribute = this.particleShaderGeo.getAttribute( 'startTime' );
-			var velocityAttribute = this.particleShaderGeo.getAttribute( 'velocity' );
-			var turbulenceAttribute = this.particleShaderGeo.getAttribute( 'turbulence' );
-			var colorAttribute = this.particleShaderGeo.getAttribute( 'color' );
-			var sizeAttribute = this.particleShaderGeo.getAttribute( 'size' );
-			var lifeTimeAttribute = this.particleShaderGeo.getAttribute( 'lifeTime' );
-
-			if ( this.offset + this.count < this.PARTICLE_COUNT ) {
-
-				positionStartAttribute.updateRange.offset = this.offset * positionStartAttribute.itemSize;
-				startTimeAttribute.updateRange.offset = this.offset * startTimeAttribute.itemSize;
-				velocityAttribute.updateRange.offset = this.offset * velocityAttribute.itemSize;
-				turbulenceAttribute.updateRange.offset = this.offset * turbulenceAttribute.itemSize;
-				colorAttribute.updateRange.offset = this.offset * colorAttribute.itemSize;
-				sizeAttribute.updateRange.offset = this.offset * sizeAttribute.itemSize;
-				lifeTimeAttribute.updateRange.offset = this.offset * lifeTimeAttribute.itemSize;
-
-				positionStartAttribute.updateRange.count = this.count * positionStartAttribute.itemSize;
-				startTimeAttribute.updateRange.count = this.count * startTimeAttribute.itemSize;
-				velocityAttribute.updateRange.count = this.count * velocityAttribute.itemSize;
-				turbulenceAttribute.updateRange.count = this.count * turbulenceAttribute.itemSize;
-				colorAttribute.updateRange.count = this.count * colorAttribute.itemSize;
-				sizeAttribute.updateRange.count = this.count * sizeAttribute.itemSize;
-				lifeTimeAttribute.updateRange.count = this.count * lifeTimeAttribute.itemSize;
-
-			} else {
-
-				positionStartAttribute.updateRange.offset = 0;
-				startTimeAttribute.updateRange.offset = 0;
-				velocityAttribute.updateRange.offset = 0;
-				turbulenceAttribute.updateRange.offset = 0;
-				colorAttribute.updateRange.offset = 0;
-				sizeAttribute.updateRange.offset = 0;
-				lifeTimeAttribute.updateRange.offset = 0;
-
-				// Use -1 to update the entire buffer, see #11476
-				positionStartAttribute.updateRange.count = - 1;
-				startTimeAttribute.updateRange.count = - 1;
-				velocityAttribute.updateRange.count = - 1;
-				turbulenceAttribute.updateRange.count = - 1;
-				colorAttribute.updateRange.count = - 1;
-				sizeAttribute.updateRange.count = - 1;
-				lifeTimeAttribute.updateRange.count = - 1;
-
-			}
-
-			positionStartAttribute.needsUpdate = true;
-			startTimeAttribute.needsUpdate = true;
-			velocityAttribute.needsUpdate = true;
-			turbulenceAttribute.needsUpdate = true;
-			colorAttribute.needsUpdate = true;
-			sizeAttribute.needsUpdate = true;
-			lifeTimeAttribute.needsUpdate = true;
-
-			this.offset = 0;
-			this.count = 0;
-
-		}
-
-	};
-
-	this.dispose = function () {
-
-		this.particleShaderGeo.dispose();
-
-	};
-
-	this.init();
-
-};
-
-THREE.GPUParticleContainer.prototype = Object.create( THREE.Object3D.prototype );
-THREE.GPUParticleContainer.prototype.constructor = THREE.GPUParticleContainer;

+ 0 - 176
examples/webgl_gpu_particle_system.html

@@ -1,176 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-	<head>
-		<title>three.js - gpu particle system</title>
-		<meta charset="utf-8">
-		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-		<link type="text/css" rel="stylesheet" href="main.css">
-	</head>
-	<body>
-		<div id="container"></div>
-		<div id="info">
-			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - GPU particle system plugin<br/>
-			by <a href="http://charliehoey.com">Charlie Hoey</a>.
-		</div>
-
-		<script type="module">
-			import {
-				Clock,
-				PerspectiveCamera,
-				Scene,
-				Vector3,
-				WebGLRenderer
-			} from "../build/three.module.js";
-
-			import Stats from './jsm/libs/stats.module.js';
-			import { GUI } from './jsm/libs/dat.gui.module.js';
-
-			import { TrackballControls } from './jsm/controls/TrackballControls.js';
-			import { GPUParticleSystem } from './jsm/objects/GPUParticleSystem.js';
-
-			var camera, tick = 0,
-				scene, renderer, clock = new Clock(),
-				controls, container, gui = new GUI( { width: 350 } ),
-				options, spawnerOptions, particleSystem;
-
-			var stats;
-
-			init();
-			animate();
-
-			function init() {
-
-				//
-
-				container = document.getElementById( 'container' );
-
-				camera = new PerspectiveCamera( 28, window.innerWidth / window.innerHeight, 1, 10000 );
-				camera.position.z = 100;
-
-				scene = new Scene();
-
-				// The GPU Particle system extends THREE.Object3D, and so you can use it
-				// as you would any other scene graph component.	Particle positions will be
-				// relative to the position of the particle system, but you will probably only need one
-				// system for your whole scene
-
-				particleSystem = new GPUParticleSystem( {
-					maxParticles: 250000
-				} );
-
-				scene.add( particleSystem );
-
-				// options passed during each spawned
-
-				options = {
-					position: new Vector3(),
-					positionRandomness: .3,
-					velocity: new Vector3(),
-					velocityRandomness: .5,
-					color: 0xaa88ff,
-					colorRandomness: .2,
-					turbulence: .5,
-					lifetime: 2,
-					size: 5,
-					sizeRandomness: 1
-				};
-
-				spawnerOptions = {
-					spawnRate: 15000,
-					horizontalSpeed: 1.5,
-					verticalSpeed: 1.33,
-					timeScale: 1
-				};
-
-				//
-
-				gui.add( options, "velocityRandomness", 0, 3 );
-				gui.add( options, "positionRandomness", 0, 3 );
-				gui.add( options, "size", 1, 20 );
-				gui.add( options, "sizeRandomness", 0, 25 );
-				gui.add( options, "colorRandomness", 0, 1 );
-				gui.add( options, "lifetime", .1, 10 );
-				gui.add( options, "turbulence", 0, 1 );
-
-				gui.add( spawnerOptions, "spawnRate", 10, 30000 );
-				gui.add( spawnerOptions, "timeScale", - 1, 1 );
-
-				//
-
-				stats = new Stats();
-				container.appendChild( stats.dom );
-
-				//
-
-				renderer = new WebGLRenderer();
-				renderer.setPixelRatio( window.devicePixelRatio );
-				renderer.setSize( window.innerWidth, window.innerHeight );
-				container.appendChild( renderer.domElement );
-
-				//
-
-				controls = new TrackballControls( camera, renderer.domElement );
-				controls.rotateSpeed = 5.0;
-				controls.zoomSpeed = 2.2;
-				controls.panSpeed = 1;
-				controls.dynamicDampingFactor = 0.3;
-
-				window.addEventListener( 'resize', onWindowResize, false );
-
-			}
-
-			function onWindowResize() {
-
-				camera.aspect = window.innerWidth / window.innerHeight;
-				camera.updateProjectionMatrix();
-
-				renderer.setSize( window.innerWidth, window.innerHeight );
-
-			}
-
-			function animate() {
-
-				requestAnimationFrame( animate );
-
-				controls.update();
-
-				var delta = clock.getDelta() * spawnerOptions.timeScale;
-
-				tick += delta;
-
-				if ( tick < 0 ) tick = 0;
-
-				if ( delta > 0 ) {
-
-					options.position.x = Math.sin( tick * spawnerOptions.horizontalSpeed ) * 20;
-					options.position.y = Math.sin( tick * spawnerOptions.verticalSpeed ) * 10;
-					options.position.z = Math.sin( tick * spawnerOptions.horizontalSpeed + spawnerOptions.verticalSpeed ) * 5;
-
-					for ( var x = 0; x < spawnerOptions.spawnRate * delta; x ++ ) {
-
-						// Yep, that's really it.	Spawning particles is super cheap, and once you spawn them, the rest of
-						// their lifecycle is handled entirely on the GPU, driven by a time uniform updated below
-
-						particleSystem.spawnParticle( options );
-
-					}
-
-				}
-
-				particleSystem.update( tick );
-
-				render();
-
-				stats.update();
-
-			}
-
-			function render() {
-
-				renderer.render( scene, camera );
-
-			}
-
-		</script>
-	</body>
-</html>