Skip to content

Instantly share code, notes, and snippets.

@AndrewKhassapov
Created June 3, 2022 15:44
Show Gist options
  • Save AndrewKhassapov/fea03daf3ff4ce1b76004a86c3abbe7e to your computer and use it in GitHub Desktop.
Save AndrewKhassapov/fea03daf3ff4ce1b76004a86c3abbe7e to your computer and use it in GitHub Desktop.
Three.js explosion
<div id="main-container">
<!-- <script src="./main.js"><script/> //-->
</div>
/**
* Variables and properties.
*/
const SCENE_SIZE = 1000; // Relative size to scale to.
const TOTAL = 40; // Number of items in ring field.
var scene = new THREE.Scene();
var clock = new THREE.Clock();
var camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
1,
10000
);
camera.position.z = 1000;
scene.add(camera);
// Axis: TODO: Remove after testing.
var plane = new THREE.GridHelper(100, 10);
scene.add(plane);
var renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.autoClear = false;
renderer.setClearColor(0x000000, 0.0);
document.getElementById('main-container').appendChild(renderer.domElement);
var items = []; // Circulating item properties.
var itemEffects = [];
/**
* Item properties.
*/
class Item {
#angle = 0; //Orbital angle in radians.
constructor(
mesh,
radius,
spin,
velocity = new THREE.Vector3(1, 1, 1),
ecliptic = new THREE.Vector3(1,1,1)
) {
this.mesh = mesh; // THREE.Mesh type
this.radius = radius; // Vector3 type. Position.
this.spin = spin; // Vector3 type
this.velocity = velocity; // Float type.
this.ecliptic = ecliptic; // Vector3 type. Variation in orbit by scale.
this.#angle = Math.atan2(radius.y, radius.x); // Initial angle, in radians.
this.initPosition(this.radius);
}
/**
* Update item shape.
*/
setShape(mesh)
{
this.mesh = mesh;
}
/**
* Sets initial position.
*/
initPosition(iPosition) {
this.mesh.position.set(iPosition.x, iPosition.y, iPosition.z);
}
/**
* Rotate the mesh object over input time.
*/
rotateItem(dTime) {
this.mesh.rotation.x += this.spin.x * dTime;
this.mesh.rotation.y += this.spin.y * dTime;
this.mesh.rotation.z += this.spin.z * dTime;
}
/**
* Rotation animation over the ellipse of object radius (x, y, z).
*/
animateRotation(dTime) {
this.#angle += dTime * this.velocity;
this.mesh.position.set(
this.radius.length() * this.ecliptic.x * Math.cos(this.#angle),
this.radius.length() * this.ecliptic.y * Math.sin(this.#angle),
this.radius.z
);
if (this.#angle > Math.PI) {
this.#angle = -Math.PI;
}
}
/**
* Explosion and implosion animation over the ellipse of object radius (x, y, z).
*/
animateExplosion(dTime) {
this.#angle += dTime * this.velocity;
this.mesh.position.x += this.radius.length() * this.ecliptic.x * (dTime) * Math.cos(this.#angle);
this.mesh.position.y += this.radius.length() * this.ecliptic.x * (dTime) * Math.sin(this.#angle);
//this.mesh.position.z += this.radius.z * this.velocity.z * dTime; TODO z-axis motion.
if (this.#angle > Math.PI) {
this.#angle = -Math.PI;
}
}
/**
* Rotate the mesh object over input time.
*/
rotateItem(dTime) {
this.mesh.rotation.x += this.spin.x * dTime;
this.mesh.rotation.y += this.spin.y * dTime;
this.mesh.rotation.z += this.spin.z * dTime;
}
}
/**
* Generates a random color:
* @return: Color in 0x000000 format.
*/
function colorRandom(){
return new THREE.Color("0x" + Math.floor(Math.random()*16777215).toString(16));
}
/**
* Generates an object-specific random color.
* @return: Color in THREE.Color format.
*/
function colorObject()
{
let newColor = 'hsl('+mathRange(0,360)+', 100%, 50%)';
return new THREE.Color(newColor);
}
/**
* Generates an object-specific random color across the hue range.
* Hue ranges from 0 (red), 120 (green), 240 (blue) to 360.
* @return: Color in THREE.Color format.
*/
function colorObjectHue(hueInit, hueFinal, sat = 100, light = 50)
{
// Edge cases:
hueInit = (hueInit < 0 || hueInit > 360) ? 0 : hueInit;
hueFinal = (hueFinal < 0 || hueFinal > 360) ? 360 : hueFinal;
sat = (sat < 0 || sat > 100) ? sat = 100 : sat;
light = (light < 0 || light > 100) ? light = 50 : light;
let newColor = 'hsl('+mathRange(hueInit,hueFinal)+', '+sat+'%, '+light+'%)';
return new THREE.Color(newColor);
}
/**
* Generates a random position as Vector3(x, y, z).
*/
function randomPosition() {
const MIN_DISTANCE = -SCENE_SIZE;
const MAX_DISTANCE = SCENE_SIZE;
//const RANGE_DISTANCE = 1.2; // Variation in position.
function posRange() {
return Math.random() * (MAX_DISTANCE - MIN_DISTANCE + 1) + MIN_DISTANCE;
}
let posX = posRange()/2;
let posY = posRange()/2;
return new THREE.Vector3(posX, posY, mathRange(-10, 10));
}
/**
* A value between low (inclusive) and high (inclusive).
* @returns A value between low (inclusive) and high (inclusive).
*/
function mathRange(low, high) {
return Math.random() * (high - low + 1) + low;
}
/**
* Generate number of items.
*/
function buildItems(){
for (let i = 0; i < TOTAL; i++) {
// Shapes
/*let shapeGeometry = new THREE.BoxGeometry(
mathRange(50, 150),
mathRange(50, 150),
mathRange(50, 150)
);
let shapeVelocity = (Math.random() * 0.25) + 0.25;*/
//shapeGeometry = new THREE.IcosahedronGeometry(mathRange(25, 50), 0);
//shapeGeometry = new THREE.TorusKnotGeometry( 50, 10, 100, 16 );
let shapeGeometry = new THREE.TetrahedronGeometry(mathRange(50, 100), 0);
let shapeMaterial = new THREE.MeshLambertMaterial({
color: colorObjectHue(0, 60),
wireframe: false
});
let shape = new THREE.Mesh(shapeGeometry, shapeMaterial);
// Shape wireframe:
let wfGeometry = new THREE.TetrahedronGeometry(shapeGeometry.parameters.radius * 1.5, shapeGeometry.parameters.detail);
let wfMaterial = new THREE.MeshLambertMaterial({
color: 0xffffff,
wireframe: true
});
let wireframe = new THREE.Mesh(wfGeometry, wfMaterial);
//let pos = randomPosition();
//cube.position.set(pos.x, pos.y, pos.z);
scene.add(shape);
scene.add(wireframe);
let shapeVelocity = 1;
let shapePosition = randomPosition();
let shapeRadii = new THREE.Vector3(1.5* window.innerWidth/SCENE_SIZE, 1.5* window.innerHeight/SCENE_SIZE, 1);
let shapeSpin = new THREE.Vector3(Math.random(), Math.random(), Math.random());
let shapeItem = new Item(shape, shapePosition, shapeSpin, shapeVelocity, shapeRadii);
let wireframeItem = new Item(wireframe, shapePosition, shapeSpin, shapeVelocity, shapeRadii);
items.push(shapeItem);
itemEffects.push(wireframeItem);
}
}
buildItems();
/**
Skybox,
*/
function buildSkybox(){
var skyboxGeometry = new THREE.BoxGeometry(10000, 10000, 10000);
var skyboxMaterial = new THREE.MeshBasicMaterial({
color: 0x000000,
side: THREE.BackSide
});
var skybox = new THREE.Mesh(skyboxGeometry, skyboxMaterial);
scene.add(skybox);
}
// buildSkybox();
function buildLight(){
var pointLight = new THREE.PointLight(0xffffff);
pointLight.position.set(0, 0, 10000);
scene.add(pointLight);
}
buildLight();
/**
* Render animation.
*/
function render() {
requestAnimationFrame(render);
let delta = clock.getDelta();
for (var i = 0; i < TOTAL; i++) {
items[i].rotateItem(delta);
items[i].animateExplosion(delta);
itemEffects[i].rotateItem(delta);
itemEffects[i].animateExplosion(delta);
}
renderer.render(scene, camera);
}
render();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
body {
background-color: #000000;
margin: 0px;
overflow: hidden;
position: fixed;
top: 0px;
left: 0px;
}
div#main-container {
width: 100%;
height: 100%;
background: linear-gradient(350deg, #000000, #000736 70%, #000000);
}

Three.js explosion

Using THREE.js to create a simulated explosion effect.

Object mesh shapes can be changed. All objects rotate around their own elliptic center point, culminating at (0,0,0).

Oribital animation also possible.

Background is a CSS gradient. Skybox disabled.

Updates suggested: Light source and color variations. Refactoring. Documentation. Add more bugs.

A Pen by Andrew Khassapov on CodePen.

License.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment