<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<button id="btnRepeat" style="position: absolute; margin: 5px;">Repeat</button>
body {
overflow: hidden;
margin: 0;
}
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
1,
1000
);
camera.position.set(0, 8, 13);
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x101010);
document.body.appendChild(renderer.domElement);
window.addEventListener("resize", onWindowResize, false);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var grid = new THREE.GridHelper(10, 10);
//grid.position.z = -15;
grid.rotation.x = Math.PI * 0.5;
scene.add(grid);
//var pointsHolder = new THREE.Group();
var r = 0.5; // radius
var delayMax = 1; // seconds
var colors = [
0xd50f30,
0x039bdc,
0xfc5411,
0x1a2683,
0xfbe23d,
0x12923b
];
var c = new THREE.Color();
var MAX_POINTS = 5000;
var pointsCount = 0;
var pointsInitDist = 15;
var points = []; //3
var pointsDest = []; //3
var pointsPlaneDist = 5;
var sideSize = Math.tan(camera.fov * 0.5 * THREE.Math.DEG2RAD) * pointsPlaneDist;
sideSize *= window.innerWidth > window.innerHeight ? camera.aspect : 1;
var delay = []; //1
var color = []; //3
while( pointsCount < MAX_POINTS){
let vec = new THREE.Vector3(THREE.Math.randFloat(-r, r),
THREE.Math.randFloat(-r, r),
THREE.Math.randFloat(-r, r)
);
if (vec.length() <= r) {
vec.z -= pointsInitDist;
points.push(vec);
pointsDest.push(
THREE.Math.randFloat(-sideSize, sideSize),
THREE.Math.randFloat(-sideSize, sideSize),
- pointsPlaneDist
);
delay.push(THREE.Math.randFloat(-delayMax,0));
c.set(colors[THREE.Math.randInt(0, colors.length - 1)]);
color.push(c.r, c.g, c.b);
pointsCount++;
}
}
console.log(pointsDest);
console.log(delay);
var pointsGeom = new THREE.BufferGeometry().setFromPoints(points);
pointsGeom.setAttribute("color", new THREE.BufferAttribute(new Float32Array(color), 3));
pointsGeom.setAttribute("pointsDest", new THREE.BufferAttribute(new Float32Array(pointsDest), 3));
pointsGeom.setAttribute("delay", new THREE.BufferAttribute(new Float32Array(delay), 1));
var pointsMat = new THREE.PointsMaterial(
{
vertexColors: THREE.VertexColors,
size: 0.2,
map: new THREE.TextureLoader().load("https://threejs.org/examples/textures/sprites/ball.png", tex => {
tex.center.setScalar(0.5);
tex.rotation = -Math.PI * 0.5;
}),
alphaTest: 0.5});
var uniforms = {
time: {value: 0},
delayMax: {value: delayMax},
duration: {value: 0.5}, // seconds to move from init to dest (each particle)
fall: {value: sideSize * 2.1},
fallDelay: {value: .5},
fallDuration: {value: 1} // seconds
}
pointsMat.onBeforeCompile = shader => {
shader.uniforms.time = uniforms.time;
shader.uniforms.delayMax = uniforms.delayMax;
shader.uniforms.duration = uniforms.duration;
shader.uniforms.fall = uniforms.fall;
shader.uniforms.fallDelay = uniforms.fallDelay;
shader.uniforms.fallDuration = uniforms.fallDuration;
console.log(shader.vertexShader);
shader.vertexShader = `
uniform float time;
uniform float delayMax;
uniform float duration;
uniform float fall;
uniform float fallDelay;
uniform float fallDuration;
attribute vec3 pointsDest;
attribute float delay;
varying float vRatio;
` + shader.vertexShader;
shader.vertexShader = shader.vertexShader.replace(
`#include <begin_vertex>`,
`#include <begin_vertex>
float t = time + delay;
t = t < 0. ? 0. : t;
//t = 0.05;
float tRatio = 0.;
tRatio = clamp( t / duration, 0., 1.);
vRatio = step(0.25, tRatio);
transformed = mix(transformed, pointsDest, tRatio);
float fallStart = delayMax + duration + fallDelay;
if (time >= fallStart) {
float timeDiff = time - fallStart;
float fRatio = clamp(timeDiff / fallDuration, 0., 1.);
transformed.y -= fall * fRatio;
}
`
);
shader.vertexShader = shader.vertexShader.replace(
`gl_PointSize = size;`,
`gl_PointSize = size * smoothstep(0.25, 0.5, tRatio);`
);
shader.fragmentShader = `
varying float vRatio;
` + shader.fragmentShader;
shader.fragmentShader = shader.fragmentShader.replace(
`#include <clipping_planes_fragment>`,
`
if (floor(vRatio + 0.5) < 1.) discard;
#include <clipping_planes_fragment>`
);
}
var points = new THREE.Points(pointsGeom, pointsMat);
scene.add(points);
var clock = new THREE.Clock();
var t = 0;
btnRepeat.addEventListener("click", event => {t = 0;}, false);
renderer.setAnimationLoop(() => {
t += clock.getDelta();
uniforms.time.value = t;
points.position.copy(camera.position);
points.quaternion.copy(camera.quaternion);
renderer.render(scene, camera);
});
function onWindowResize() {
var width = window.innerWidth;
var height = window.innerHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height);
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.