threejs-orbitingballs
Version:
A tiny physics sim of balls orbitting thier center of mass, as a single threejs object.
79 lines (68 loc) • 2.36 kB
JavaScript
var THREE = require('three');
function OrbitingBalls(totalBalls, material) {
THREE.Object3D.call(this);
material = material ? material : new THREE.MeshBasicMaterial();
//all units are in metres
this.totalBalls = totalBalls ? totalBalls : 100;
this.balls = [];
var birthBoxSize = 1;
var birthBoxSizeHalf = birthBoxSize * .5;
//for center of gravity
this.totalMass = 0;
this.centerOfMass = new THREE.Vector3();
//for ball physics
var initVelocity = .0002;
var initVelocityHalf = initVelocity * .5;
//let make some balls!
for (var i = this.totalBalls - 1; i >= 0; i--) {
//standard threejs ball stuff
var radius = Math.pow(Math.random(), 4) * .2 + .05;
var ball = new THREE.Mesh(
new THREE.SphereGeometry(radius),
material
);
ball.position.set(
Math.random() * birthBoxSize - birthBoxSizeHalf,
Math.random() * birthBoxSize - birthBoxSizeHalf,
Math.random() * birthBoxSize - birthBoxSizeHalf
)
this.balls.push(ball);
this.add(ball);
//extra stuff for physics
var mass = Math.pow(radius, 3)
ball.mass = mass;
this.totalMass += mass;
ball.velocity = new THREE.Vector3(
Math.random() * (initVelocity - initVelocityHalf) / mass,
Math.random() * (initVelocity - initVelocityHalf) / mass,
Math.random() * (initVelocity - initVelocityHalf) / mass
);
}
this.onEnterFrame = this.onEnterFrame.bind(this);
}
OrbitingBalls.prototype = Object.create(THREE.Object3D.prototype);
//on every frame
OrbitingBalls.prototype.onEnterFrame = function () {
// console.log(FPS.animSpeedCompensation);
//calculate center of gravity
this.centerOfMass.set(0,0,0);
for (var i = this.totalBalls - 1; i >= 0; i--) {
var ball = this.balls[i];
this.centerOfMass.add(ball.position.clone().multiplyScalar(ball.mass/this.totalMass));
};
//keeps the center of gravity from drifting into space
this.centerOfMass.multiplyScalar(.99);
//apply physics
for (var i = this.totalBalls - 1; i >= 0; i--) {
var ball = this.balls[i];
var dist = ball.position.clone().sub(this.centerOfMass);
ball.velocity.sub(
dist.multiplyScalar(.00001 / (ball.mass * dist.length()))
);
ball.position.add(ball.velocity);
ball.scale.z = 1 + ball.velocity.length() * 30;
ball.scale.x = ball.scale.y = 1/Math.sqrt(ball.scale.z);
ball.lookAt(ball.position.clone().add(ball.velocity))
};
}
module.exports = OrbitingBalls;