Skip to content

Instantly share code, notes, and snippets.

@espace3d
Created July 24, 2021 10:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save espace3d/a779e4eed7ea46e0f7ca6b108ce12222 to your computer and use it in GitHub Desktop.
Save espace3d/a779e4eed7ea46e0f7ca6b108ce12222 to your computer and use it in GitHub Desktop.
03 three.js particle system
<div id="container"></div>
import { OrbitControls } from "https://cdn.skypack.dev/three@0.124.0/examples/jsm/controls/OrbitControls";
import * as dat from "https://cdn.skypack.dev/dat.gui@0.7.7";
// import * as THREE from "https://cdn.skypack.dev/three@0.124.0";
import Stats from "https://cdn.skypack.dev/three@0.124.0/examples/jsm/libs/stats.module";
/**
* Global utils
*/
(function () {
var _w = window,
_s = window.screen,
_b = document.body,
_d = document.documentElement;
window.Utils = {
// screen info
screen: function () {
var width = Math.max(
0,
_w.innerWidth || _d.clientWidth || _b.clientWidth || 0
);
var height = Math.max(
0,
_w.innerHeight || _d.clientHeight || _b.clientHeight || 0
);
return {
width: width,
height: height,
centerx: width / 2,
centery: height / 2,
ratio: width / height
};
},
// mouse info
mouse: function (e) {
var x = Math.max(0, e.pageX || e.clientX || 0);
var y = Math.max(0, e.pageY || e.clientY || 0);
var s = this.screen();
return {
x: x,
y: y,
centerx: x - s.centerx,
centery: y - s.centery
};
}
};
})();
// constructor
var Firework = function (scene) {
this.scene = scene;
this.done = false;
this.dest = [];
this.colors = [];
this.geometry = null;
this.points = null;
this.material = new THREE.PointsMaterial({
size: 16,
color: 0xffffff,
opacity: 1,
vertexColors: true,
transparent: true,
depthTest: false
});
this.launch();
};
// prototype
Firework.prototype = {
constructor: Firework,
// reset
reset: function () {
this.scene.remove(this.points);
this.dest = [];
this.colors = [];
this.geometry = null;
this.points = null;
},
// launch
launch: function () {
var s = Utils.screen();
var x = THREE.Math.randInt(-s.width, s.width);
var y = THREE.Math.randInt(100, 800);
var z = THREE.Math.randInt(-1000, -3000);
var from = new THREE.Vector3(x, -800, z);
var to = new THREE.Vector3(x, y, z);
var color = new THREE.Color();
color.setHSL(THREE.Math.randFloat(0.1, 0.9), 1, 0.9);
this.colors.push(color);
this.geometry = new THREE.Geometry();
this.points = new THREE.Points(this.geometry, this.material);
this.geometry.colors = this.colors;
this.geometry.vertices.push(from);
this.dest.push(to);
this.colors.push(color);
this.scene.add(this.points);
},
// explode
explode: function (vector) {
this.scene.remove(this.points);
this.dest = [];
this.colors = [];
this.geometry = new THREE.Geometry();
this.points = new THREE.Points(this.geometry, this.material);
for (var i = 0; i < 80; i++) {
var color = new THREE.Color();
color.setHSL(THREE.Math.randFloat(0.1, 0.9), 1, 0.5);
this.colors.push(color);
var from = new THREE.Vector3(
THREE.Math.randInt(vector.x - 10, vector.x + 10),
THREE.Math.randInt(vector.y - 10, vector.y + 10),
THREE.Math.randInt(vector.z - 10, vector.z + 10)
);
var to = new THREE.Vector3(
THREE.Math.randInt(vector.x - 1000, vector.x + 1000),
THREE.Math.randInt(vector.y - 1000, vector.y + 1000),
THREE.Math.randInt(vector.z - 1000, vector.z + 1000)
);
this.geometry.vertices.push(from);
this.dest.push(to);
}
this.geometry.colors = this.colors;
this.scene.add(this.points);
},
// update
update: function () {
// only if objects exist
if (this.points && this.geometry) {
var total = this.geometry.vertices.length;
// lerp particle positions
for (var i = 0; i < total; i++) {
this.geometry.vertices[i].x +=
(this.dest[i].x - this.geometry.vertices[i].x) / 20;
this.geometry.vertices[i].y +=
(this.dest[i].y - this.geometry.vertices[i].y) / 20;
this.geometry.vertices[i].z +=
(this.dest[i].z - this.geometry.vertices[i].z) / 20;
this.geometry.verticesNeedUpdate = true;
}
// watch first particle for explosion
if (total === 1) {
if (Math.ceil(this.geometry.vertices[0].y) > this.dest[0].y - 20) {
this.explode(this.geometry.vertices[0]);
return;
}
}
// fade out exploded particles
if (total > 1) {
this.material.opacity -= 0.015;
this.material.colorsNeedUpdate = true;
}
// remove, reset and stop animating
if (this.material.opacity <= 0) {
this.reset();
this.done = true;
return;
}
}
}
};
// export
window.Firework = Firework;
var container,
point,
ambient,
clock,
controls,
gui,
camera,
scene,
renderer,
stats,
to = { px: 0, py: 0, pz: 500 },
fireworks = [],
screen = Utils.screen();
const debug = true;
const { innerWidth, innerHeight } = window;
// animate()
window.onload = () => {
init("#container");
};
function init(el) {
container = document.querySelector(el);
initScene();
initCamera();
initRenderer();
initLight();
debug && initHelper();
initControls();
onWindowResize();
window.addEventListener("resize", onWindowResize, false);
// addCubes()
render();
}
function initScene() {
scene = new THREE.Scene();
}
function initCamera() {
const ratio = innerWidth / innerHeight;
camera = new THREE.PerspectiveCamera(75, ratio, 0.1, 20000);
console.log("camera==>", camera);
// camera.position.set(0, 0, 120)
}
function initRenderer() {
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0x000000, 1);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
// renderer.setPixelRatio(1)
renderer.setSize(innerWidth, innerHeight);
container.appendChild(renderer.domElement);
}
function initLight() {
point = new THREE.DirectionalLight(0xffffff);
point.position.set(400, 200, 600);
scene.add(point);
ambient = new THREE.AmbientLight(0x444444);
scene.add(ambient);
}
function initHelper() {
stats = new Stats();
container && container.appendChild(stats.dom);
}
function onWindowResize() {
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
}
function render() {
renderer.render(scene, camera);
// addCubes()
// add fireworks
if (THREE.Math.randInt(1, 20) >= 1) {
fireworks.push(new Firework(scene));
fireworks.push(new Firework(scene));
fireworks.push(new Firework(scene));
fireworks.push(new Firework(scene));
fireworks.push(new Firework(scene));
fireworks.push(new Firework(scene));
fireworks.push(new Firework(scene));
fireworks.push(new Firework(scene));
}
// update fireworks
for (var i = 0; i < fireworks.length; i++) {
if (fireworks[i].done) {
// cleanup
fireworks.splice(i, 1);
continue;
}
fireworks[i].update();
}
stats.update();
requestAnimationFrame(render);
}
function initControls() {
controls = new OrbitControls(camera, renderer.domElement);
controls.update();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r77/three.min.js"></script>
* {
margin: 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment