|
@@ -32,7 +32,8 @@ THREE.GPUParticleSystem = function( options ) {
|
|
|
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
|
|
|
|
|
@@ -40,69 +41,17 @@ THREE.GPUParticleSystem = function( options ) {
|
|
|
|
|
|
vertexShader: [
|
|
|
|
|
|
- 'precision highp float;',
|
|
|
-
|
|
|
- '#define FLOAT_MAX 1.70141184e38',
|
|
|
- '#define FLOAT_MIN 1.17549435e-38',
|
|
|
-
|
|
|
- 'lowp vec4 encode_float( highp float v ) {',
|
|
|
-
|
|
|
- ' highp float av = abs( v );',
|
|
|
-
|
|
|
- // handle special cases
|
|
|
-
|
|
|
- ' if( av < FLOAT_MIN ) {',
|
|
|
-
|
|
|
- ' return vec4( 0.0 );',
|
|
|
-
|
|
|
- ' } else if ( v > FLOAT_MAX ) {',
|
|
|
-
|
|
|
- ' return vec4( 127.0, 128.0, 0.0, 0.0 ) / 255.0;',
|
|
|
-
|
|
|
- ' } else if( v < -FLOAT_MAX ) {',
|
|
|
-
|
|
|
- ' return vec4( 255.0, 128.0, 0.0, 0.0 ) / 255.0;',
|
|
|
-
|
|
|
- ' }',
|
|
|
-
|
|
|
- ' highp vec4 c = vec4( 0 );',
|
|
|
-
|
|
|
- // compute exponent and mantissa
|
|
|
-
|
|
|
- ' highp float e = floor( log2( av ) );',
|
|
|
- ' highp float m = av * pow( 2.0, - e ) - 1.0;',
|
|
|
-
|
|
|
- // unpack mantissa
|
|
|
-
|
|
|
- ' c[ 1 ] = floor( 128.0 * m );',
|
|
|
- ' m -= c[ 1 ] / 128.0;',
|
|
|
- ' c[ 2 ] = floor( 32768.0 * m );',
|
|
|
- ' m -= c[ 2 ] / 32768.0;',
|
|
|
- ' c[ 3 ] = floor( 8388608.0 * m );',
|
|
|
-
|
|
|
- // unpack exponent
|
|
|
-
|
|
|
- ' highp float ebias = e + 127.0;',
|
|
|
- ' c[ 0 ] = floor( ebias / 2.0 );',
|
|
|
- ' ebias -= c[ 0 ] * 2.0;',
|
|
|
- ' c[ 1 ] += floor( ebias ) * 128.0;',
|
|
|
-
|
|
|
- // unpack sign bit
|
|
|
-
|
|
|
- ' c[ 0 ] += 128.0 * step( 0.0, - v );',
|
|
|
-
|
|
|
- // scale back to range
|
|
|
-
|
|
|
- ' return c / 255.0;',
|
|
|
-
|
|
|
- '}',
|
|
|
-
|
|
|
'uniform float uTime;',
|
|
|
'uniform float uScale;',
|
|
|
'uniform sampler2D tNoise;',
|
|
|
|
|
|
- 'attribute vec4 particlePositionsStartTime;',
|
|
|
- 'attribute vec4 particleVelColSizeLife;',
|
|
|
+ '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;',
|
|
@@ -111,40 +60,37 @@ THREE.GPUParticleSystem = function( options ) {
|
|
|
|
|
|
// unpack things from our attributes'
|
|
|
|
|
|
- ' vColor = encode_float( particleVelColSizeLife.y );',
|
|
|
+ ' vColor = vec4( color, 1.0 );',
|
|
|
|
|
|
// convert our velocity back into a value we can use'
|
|
|
|
|
|
- ' vec4 velTurb = encode_float( particleVelColSizeLife.x );',
|
|
|
- ' vec3 velocity = vec3( velTurb.xyz );',
|
|
|
- ' float turbulence = velTurb.w;',
|
|
|
-
|
|
|
' vec3 newPosition;',
|
|
|
+ ' vec3 v;',
|
|
|
|
|
|
- ' float timeElapsed = uTime - particlePositionsStartTime.a;',
|
|
|
+ ' float timeElapsed = uTime - startTime;',
|
|
|
|
|
|
- ' lifeLeft = 1.0 - ( timeElapsed / particleVelColSizeLife.w );',
|
|
|
+ ' lifeLeft = 1.0 - ( timeElapsed / lifeTime );',
|
|
|
|
|
|
- ' gl_PointSize = ( uScale * particleVelColSizeLife.z ) * lifeLeft;',
|
|
|
+ ' gl_PointSize = ( uScale * size ) * lifeLeft;',
|
|
|
|
|
|
- ' velocity.x = ( velocity.x - 0.5 ) * 3.0;',
|
|
|
- ' velocity.y = ( velocity.y - 0.5 ) * 3.0;',
|
|
|
- ' velocity.z = ( velocity.z - 0.5 ) * 3.0;',
|
|
|
+ ' 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 = particlePositionsStartTime.xyz + ( velocity * 10.0 ) * ( uTime - particlePositionsStartTime.a );',
|
|
|
+ ' newPosition = positionStart + ( v * 10.0 ) * ( uTime - startTime );',
|
|
|
|
|
|
' 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 / particleVelColSizeLife.a ) );',
|
|
|
+ ' newPosition = mix( newPosition, newPosition + vec3( noiseVel * ( turbulence * 5.0 ) ), ( timeElapsed / lifeTime ) );',
|
|
|
|
|
|
- ' if( velocity.y > 0. && velocity.y < .05 ) {',
|
|
|
+ ' if( v.y > 0. && v.y < .05 ) {',
|
|
|
|
|
|
' lifeLeft = 0.0;',
|
|
|
|
|
|
' }',
|
|
|
|
|
|
- ' if( velocity.x < - 1.45 ) {',
|
|
|
+ ' if( v.x < - 1.45 ) {',
|
|
|
|
|
|
' lifeLeft = 0.0;',
|
|
|
|
|
@@ -210,7 +156,6 @@ THREE.GPUParticleSystem = function( options ) {
|
|
|
|
|
|
// preload a million random numbers
|
|
|
|
|
|
- this.rand = [];
|
|
|
var i;
|
|
|
|
|
|
for ( i = 1e5; i > 0; i-- ) {
|
|
@@ -260,8 +205,6 @@ THREE.GPUParticleSystem = function( options ) {
|
|
|
this.particleShaderMat.defaultAttributeValues.particlePositionsStartTime = [ 0, 0, 0, 0 ];
|
|
|
this.particleShaderMat.defaultAttributeValues.particleVelColSizeLife = [ 0, 0, 0, 0 ];
|
|
|
|
|
|
- this.particleContainers = [];
|
|
|
-
|
|
|
this.init = function() {
|
|
|
|
|
|
for ( var i = 0; i < this.PARTICLE_CONTAINERS; i ++ ) {
|
|
@@ -331,176 +274,112 @@ THREE.GPUParticleContainer = function( maxParticles, particleSystem ) {
|
|
|
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;
|
|
|
-
|
|
|
- // construct a couple small arrays used for packing variables into floats etc.
|
|
|
-
|
|
|
- var UINT8_VIEW = new Uint8Array( 4 );
|
|
|
- var FLOAT_VIEW = new Float32Array( UINT8_VIEW.buffer );
|
|
|
-
|
|
|
- function decodeFloat( x, y, z, w ) {
|
|
|
-
|
|
|
- UINT8_VIEW[ 0 ] = Math.floor( w );
|
|
|
- UINT8_VIEW[ 1 ] = Math.floor( z );
|
|
|
- UINT8_VIEW[ 2 ] = Math.floor( y );
|
|
|
- UINT8_VIEW[ 3 ] = Math.floor( x );
|
|
|
-
|
|
|
- return FLOAT_VIEW[ 0 ];
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- function hexToRgb( hex ) {
|
|
|
-
|
|
|
- var r = hex >> 16;
|
|
|
- var g = ( hex & 0x00FF00 ) >> 8;
|
|
|
- var b = hex & 0x0000FF;
|
|
|
-
|
|
|
- if ( r > 0 ) r--;
|
|
|
- if ( g > 0 ) g--;
|
|
|
- if ( b > 0 ) b--;
|
|
|
-
|
|
|
- return [ r, g, b ];
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- this.particles = [];
|
|
|
- this.deadParticles = [];
|
|
|
- this.particlesAvailableSlot = [];
|
|
|
-
|
|
|
- // create a container for particles
|
|
|
-
|
|
|
this.particleUpdate = false;
|
|
|
|
|
|
- // shader based particle system
|
|
|
+ // geometry
|
|
|
|
|
|
this.particleShaderGeo = new THREE.BufferGeometry();
|
|
|
|
|
|
- // new hyper compressed attributes
|
|
|
-
|
|
|
- this.particleVertices = new Float32Array( this.PARTICLE_COUNT * 3 ); // position
|
|
|
- this.particlePositionsStartTime = new Float32Array( this.PARTICLE_COUNT * 4 ); // position
|
|
|
- this.particleVelColSizeLife = new Float32Array( this.PARTICLE_COUNT * 4 );
|
|
|
-
|
|
|
- var i;
|
|
|
-
|
|
|
- for ( i = 0; i < this.PARTICLE_COUNT; i ++ ) {
|
|
|
-
|
|
|
- this.particlePositionsStartTime[ i * 4 + 0 ] = 100; // x
|
|
|
- this.particlePositionsStartTime[ i * 4 + 1 ] = 0; // y
|
|
|
- this.particlePositionsStartTime[ i * 4 + 2 ] = 0.0; // z
|
|
|
- this.particlePositionsStartTime[ i * 4 + 3 ] = 0.0; // startTime
|
|
|
-
|
|
|
- this.particleVertices[ i * 3 + 0 ] = 0; // x
|
|
|
- this.particleVertices[ i * 3 + 1 ] = 0; // y
|
|
|
- this.particleVertices[ i * 3 + 2 ] = 0.0; // z
|
|
|
-
|
|
|
- this.particleVelColSizeLife[ i * 4 + 0 ] = decodeFloat( 128, 128, 0, 0 ); // velocity
|
|
|
- this.particleVelColSizeLife[ i * 4 + 1 ] = decodeFloat( 0, 254, 0, 254 ); // color
|
|
|
- this.particleVelColSizeLife[ i * 4 + 2 ] = 1.0; // size
|
|
|
- this.particleVelColSizeLife[ i * 4 + 3 ] = 0.0; // lifespan
|
|
|
-
|
|
|
- }
|
|
|
+ this.particleShaderGeo.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT * 3 ), 3 ) );
|
|
|
+ this.particleShaderGeo.addAttribute( 'positionStart', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT * 3 ), 3 ) );
|
|
|
+ this.particleShaderGeo.addAttribute( 'startTime', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT ), 1 ) );
|
|
|
+ this.particleShaderGeo.addAttribute( 'velocity', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT * 3 ), 3 ) );
|
|
|
+ this.particleShaderGeo.addAttribute( 'turbulence', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT ), 1 ) );
|
|
|
+ this.particleShaderGeo.addAttribute( 'color', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT * 3 ), 3 ) );
|
|
|
+ this.particleShaderGeo.addAttribute( 'size', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT ), 1 ) );
|
|
|
+ this.particleShaderGeo.addAttribute( 'lifeTime', new THREE.BufferAttribute( new Float32Array( this.PARTICLE_COUNT ), 1 ) );
|
|
|
|
|
|
- this.particleShaderGeo.addAttribute( 'position', new THREE.BufferAttribute( this.particleVertices, 3 ) );
|
|
|
- this.particleShaderGeo.addAttribute( 'particlePositionsStartTime', new THREE.BufferAttribute( this.particlePositionsStartTime, 4 ).setDynamic( true ) );
|
|
|
- this.particleShaderGeo.addAttribute( 'particleVelColSizeLife', new THREE.BufferAttribute( this.particleVelColSizeLife, 4 ).setDynamic( true ) );
|
|
|
-
|
|
|
- this.posStart = this.particleShaderGeo.getAttribute( 'particlePositionsStartTime' );
|
|
|
- this.velCol = this.particleShaderGeo.getAttribute( 'particleVelColSizeLife' );
|
|
|
+ // material
|
|
|
|
|
|
this.particleShaderMat = this.GPUParticleSystem.particleShaderMat;
|
|
|
|
|
|
- this.init = function() {
|
|
|
-
|
|
|
- this.particleSystem = new THREE.Points( this.particleShaderGeo, this.particleShaderMat );
|
|
|
- this.particleSystem.frustumCulled = false;
|
|
|
- this.add( this.particleSystem );
|
|
|
-
|
|
|
- };
|
|
|
-
|
|
|
- var options = {},
|
|
|
- position = new THREE.Vector3(),
|
|
|
- velocity = new THREE.Vector3(),
|
|
|
- positionRandomness = 0,
|
|
|
- velocityRandomness = 0,
|
|
|
- color = 0xffffff,
|
|
|
- colorRandomness = 0,
|
|
|
- turbulence = 0,
|
|
|
- lifetime = 0,
|
|
|
- size = 0,
|
|
|
- sizeRandomness = 0,
|
|
|
- smoothPosition = false;
|
|
|
-
|
|
|
- var maxVel = 2;
|
|
|
- var maxSource = 250;
|
|
|
- this.offset = 0;
|
|
|
- this.count = 0;
|
|
|
+ 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 );
|
|
|
- positionRandomness = options.positionRandomness !== undefined ? options.positionRandomness : 0;
|
|
|
- velocityRandomness = options.velocityRandomness !== undefined ? options.velocityRandomness : 0;
|
|
|
- color = options.color !== undefined ? options.color : 0xffffff;
|
|
|
- colorRandomness = options.colorRandomness !== undefined ? options.colorRandomness : 1;
|
|
|
- turbulence = options.turbulence !== undefined ? options.turbulence : 1;
|
|
|
- lifetime = options.lifetime !== undefined ? options.lifetime : 5;
|
|
|
- size = options.size !== undefined ? options.size : 10;
|
|
|
- sizeRandomness = options.sizeRandomness !== undefined ? options.sizeRandomness : 0;
|
|
|
- smoothPosition = options.smoothPosition !== undefined ? options.smoothPosition : false;
|
|
|
+ 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;
|
|
|
|
|
|
i = this.PARTICLE_CURSOR;
|
|
|
|
|
|
- this.posStart.array[ i * 4 + 0 ] = position.x + ( ( particleSystem.random() ) * positionRandomness ); // - ( velocity.x * particleSystem.random() ); //x
|
|
|
- this.posStart.array[ i * 4 + 1 ] = position.y + ( ( particleSystem.random() ) * positionRandomness ); // - ( velocity.y * particleSystem.random() ); //y
|
|
|
- this.posStart.array[ i * 4 + 2 ] = position.z + ( ( particleSystem.random() ) * positionRandomness ); // - ( velocity.z * particleSystem.random() ); //z
|
|
|
- this.posStart.array[ i * 4 + 3 ] = this.time + ( particleSystem.random() * 2e-2 ); //startTime
|
|
|
+ // 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 ) {
|
|
|
|
|
|
- this.posStart.array[ i * 4 + 0 ] += - ( velocity.x * particleSystem.random() ); //x
|
|
|
- this.posStart.array[ i * 4 + 1 ] += - ( velocity.y * particleSystem.random() ); //y
|
|
|
- this.posStart.array[ i * 4 + 2 ] += - ( velocity.z * particleSystem.random() ); //z
|
|
|
+ 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() );
|
|
|
|
|
|
}
|
|
|
|
|
|
- var velX = velocity.x + ( particleSystem.random() ) * velocityRandomness;
|
|
|
- var velY = velocity.y + ( particleSystem.random() ) * velocityRandomness;
|
|
|
- var velZ = velocity.z + ( particleSystem.random() ) * velocityRandomness;
|
|
|
+ // velocity
|
|
|
|
|
|
- // convert turbulence rating to something we can pack into a vec4
|
|
|
+ var maxVel = 2;
|
|
|
|
|
|
- var turbulence = Math.floor( turbulence * 254 );
|
|
|
+ var velX = velocity.x + particleSystem.random() * velocityRandomness;
|
|
|
+ var velY = velocity.y + particleSystem.random() * velocityRandomness;
|
|
|
+ var velZ = velocity.z + particleSystem.random() * velocityRandomness;
|
|
|
|
|
|
- // clamp our value to between 0.0 and 1.0
|
|
|
+ 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 );
|
|
|
|
|
|
- velX = Math.floor( maxSource * ( ( velX - ( - maxVel ) ) / ( maxVel - ( - maxVel ) ) ) );
|
|
|
- velY = Math.floor( maxSource * ( ( velY - ( - maxVel ) ) / ( maxVel - ( - maxVel ) ) ) );
|
|
|
- velZ = Math.floor( maxSource * ( ( velZ - ( - maxVel ) ) / ( maxVel - ( - maxVel ) ) ) );
|
|
|
+ velocityAttribute.array[ i * 3 + 0 ] = velX;
|
|
|
+ velocityAttribute.array[ i * 3 + 1 ] = velY;
|
|
|
+ velocityAttribute.array[ i * 3 + 2 ] = velZ;
|
|
|
|
|
|
- this.velCol.array[ i * 4 + 0 ] = decodeFloat( velX, velY, velZ, turbulence ); // vel
|
|
|
+ // color
|
|
|
|
|
|
- var rgb = hexToRgb( 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 );
|
|
|
|
|
|
- for ( var c = 0; c < rgb.length; c ++ ) {
|
|
|
+ colorAttribute.array[ i * 3 + 0 ] = color.r;
|
|
|
+ colorAttribute.array[ i * 3 + 1 ] = color.g;
|
|
|
+ colorAttribute.array[ i * 3 + 2 ] = color.b;
|
|
|
|
|
|
- rgb[ c ] = Math.floor( rgb[ c ] + ( ( particleSystem.random() ) * colorRandomness ) * 254 );
|
|
|
- if ( rgb[ c ] > 254 ) rgb[ c ] = 254;
|
|
|
- if ( rgb[ c ] < 0 ) rgb[ c ] = 0;
|
|
|
+ // 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;
|
|
|
|
|
|
- this.velCol.array[ i * 4 + 1 ] = decodeFloat( rgb[ 0 ], rgb[ 1 ], rgb[ 2 ], 254 ); // color
|
|
|
- this.velCol.array[ i * 4 + 2 ] = size + ( particleSystem.random() ) * sizeRandomness; // size
|
|
|
- this.velCol.array[ i * 4 + 3 ] = lifetime; // lifespan
|
|
|
+ // offset
|
|
|
|
|
|
if ( this.offset === 0 ) {
|
|
|
|
|
@@ -508,6 +387,8 @@ THREE.GPUParticleContainer = function( maxParticles, particleSystem ) {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ // counter and cursor
|
|
|
+
|
|
|
this.count ++;
|
|
|
this.PARTICLE_CURSOR ++;
|
|
|
|
|
@@ -521,6 +402,14 @@ THREE.GPUParticleContainer = function( maxParticles, particleSystem ) {
|
|
|
|
|
|
};
|
|
|
|
|
|
+ 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;
|
|
@@ -536,22 +425,59 @@ THREE.GPUParticleContainer = function( maxParticles, particleSystem ) {
|
|
|
|
|
|
this.particleUpdate = false;
|
|
|
|
|
|
- // if we can get away with a partial buffer update, do so
|
|
|
-
|
|
|
- if ( ( this.offset + this.count ) < this.PARTICLE_COUNT ) {
|
|
|
-
|
|
|
- this.posStart.updateRange.offset = this.velCol.updateRange.offset = this.offset * 4;
|
|
|
- this.posStart.updateRange.count = this.velCol.updateRange.count = this.count * 4;
|
|
|
+ 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 {
|
|
|
|
|
|
- this.posStart.updateRange.offset = 0;
|
|
|
- this.posStart.updateRange.count = this.velCol.updateRange.count = ( this.PARTICLE_COUNT * 4 );
|
|
|
+ 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;
|
|
|
+
|
|
|
+ positionStartAttribute.updateRange.count = positionStartAttribute.count;
|
|
|
+ startTimeAttribute.updateRange.count = startTimeAttribute.count;
|
|
|
+ velocityAttribute.updateRange.count = velocityAttribute.count;
|
|
|
+ turbulenceAttribute.updateRange.count = turbulenceAttribute.count;
|
|
|
+ colorAttribute.updateRange.count = colorAttribute.count;
|
|
|
+ sizeAttribute.updateRange.count = sizeAttribute.count;
|
|
|
+ lifeTimeAttribute.updateRange.count = lifeTimeAttribute.count;
|
|
|
|
|
|
}
|
|
|
|
|
|
- this.posStart.needsUpdate = true;
|
|
|
- this.velCol.needsUpdate = true;
|
|
|
+ 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;
|