nonRepeatingParticles = function(n){
const material = new THREE.ShaderMaterial({
vertexShader: `
#include <common>
attribute float particleID;
uniform float time; // in seconds
float _seed = 0.;
float _seed2 = 0.;
float random() {
_seed2 += 0.1; // auto-increment so each call to random() gives a different result
return rand( vec2( _seed, _seed2 ) );
}
void main() {
_seed = particleID/100. + 2.; // the seed is based upon the id of the particle, so each particle will be different
// **START NEW CODE**
float lifeTime = 1. + random()*2.; // loop every 1 to 3 seconds, this will be constant for each particle
float t = mod( time, lifeTime );
float loop = floor( time/lifeTime );
_seed = particleID/100. + loop/10000. + 2.; // use a loop based seed for the other random numbers
// **END NEW CODE**
vec3 v = vec3( 2.*random() - 1., random()*0.5 + 0.5, 2.*random() - 1. );
vec3 a = vec3( 0., -1., 0.);
vec3 p = v * t + 0.5 * a * t * t; // projectile motion
gl_Position = projectionMatrix * modelViewMatrix * vec4( p, 1.0 ); // convert 3D point p into clip space
gl_PointSize = 3.; // particle size in pixels
}`,
fragmentShader: `
void main() {
gl_FragColor = vec4(1., 0., 0., 1.); // red = 1, blue = 0, green = 0, alpha = 1
}`,
uniforms: {
time: { value: 0 }
}
})
let ids = new Float32Array(n)
for (let i = 0; i < n; i++) ids[i] = i
let positions = new Float32Array(3*n).fill(0)
const geometry = new THREE.BufferGeometry()
geometry.addAttribute('position', new THREE.BufferAttribute(positions, 3))
geometry.addAttribute('particleID', new THREE.BufferAttribute(ids, 1))
return new THREE.Points(geometry, material)
}