The Momentum Equation


Direct Link

Source code

<!DOCTYPE html>
<html>
<head>
<title>The Momentum Equation - Interactive DHTML demos</title>
<meta name="Author" content="Gerard Ferrandez at http://www.dhteumeuleu.com">
<style type="text/css">
body {
margin: 0px;
padding: 0px;
background: #111;
width: 100%;
height: 100%;
color:#fff;
font-size:12px;
font-family: arial,verdana;
}
#screen {
position: absolute;
left: 50%;
top: 50%;
background: #000;
overflow: hidden;
width: 800px;
height: 500px;
margin-left:-400px;
margin-top:-250px;
}
#screen img {
position: absolute;
}
</style>
<script type="text/javascript">
// =========================================================================
// ===== fluid js implementation =====
// ----------------------------------------------------------------------
// script: Gerard Ferrandez - 1 May 2011
// http://www.dhteumeuleu.com/
// use under a CC-BY-NC license
// ----------------------------------------------------------------------
// adapted from : http://www.processing.org/learning/topics/fluid.html
// and from : http://violentcoding.com/blog/2008/07/26/archives/135
// ref: http://www.cs.ubc.ca/~rbridson/fluidsimulation/
// =========================================================================
"use strict";
var fluid = function () {
// ----- private vars -----
var canvas, ctx, nw, nh, nx, ny,
mouseX = 0, mouseY = 0, pmX = 0, pmY = 0, nbX, nbY, res, psi,
nbP, grid = [], particles, cells, prev;
// ----- Particle prototype -----
var Particle = function (x, y) {
this.x = this.px = x;
this.y = this.py = y;
this.xvel = 0;
this.yvel = 0;
if (!particles) particles = this; else prev.nextParticle = this;
prev = this;
};
Particle.prototype.update = function () {
if (this.x > 0 && this.x < nw && this.y > 0 && this.y < nh) {
var x = (0.5 + this.x / res) | 0;
var y = (0.5 + this.y / res) | 0;
if (x >= nbX) x = nbX - 1;
if (y >= nbY) y = nbY - 1;
// ----- apply grid -----
var cell = grid[y * nbX + x];
var ax = (this.x % res) / res;
var ay = (this.y % res) / res;
this.xvel += (1 - ax) * cell.xvel * 0.05 + ax * cell.R.xvel * 0.05 + ay * cell.B.xvel * 0.05;
this.yvel += (1 - ay) * cell.yvel * 0.05 + ax * cell.R.yvel * 0.05 + ay * cell.B.yvel * 0.05;
this.x += this.xvel;
this.y += this.yvel;
// ----- canvas painting -----
var speed = (0.5 + this.xvel + this.yvel) | 0;
ctx.lineWidth = speed * 0.8 + 2;
ctx.lineCap = "round";
ctx.beginPath();
ctx.moveTo((0.5 + this.x) | 0, (0.5 + this.y) | 0);
ctx.lineTo((0.5 + this.px) | 0, (1.5 + this.py) | 0);
ctx.strokeStyle = "rgba(" + (speed * 25) + "," + 255 + "," + (speed * 25) + ", 1)";
ctx.stroke();
this.px = this.x;
this.py = this.y;
}
else {
// ----- new particle -----
this.x = this.px = Math.random() * nw;
this.y = this.py = Math.random() * nh;
this.xvel = 0;
this.yvel = 0;
}
this.xvel *= 0.5;
this.yvel *= 0.5;
// ----- next particle -----
this.nextParticle ? this.nextParticle.update() : false;
};
// ----- Grid prototype -----
var Grid = function (x, y) {
this.x = x;
this.y = y;
this.xvel = 0;
this.yvel = 0;
this.pressure = 0;
this.L = new nullGrid();
this.B = new nullGrid();
this.T = new nullGrid();
this.R = new nullGrid();
this.TL = new nullGrid();
this.TR = new nullGrid();
this.BL = new nullGrid();
this.BR = new nullGrid();
if (!cells) cells = this; else prev.nextCell = this;
prev = this;
};
var nullGrid = function () {
this.x = 0;
this.y = 0;
this.xvel = 0;
this.yvel = 0;
this.pressure = 0;
};
Grid.prototype.update = function (mxvel, myvel) {
//----- mouse ------
var dx = this.x - mouseX;
var dy = this.y - mouseY;
var dist = Math.sqrt(dy * dy + dx * dx);
if (dist < psi) {
if (dist < 4) dist = psi;
var p = psi / dist;
this.xvel += mxvel * p;
this.yvel += myvel * p;
}
// ----- pressure -----
this.pressure = (
this.TL.xvel * 0.5 + this.L.xvel + this.BL.xvel * 0.5 - this.TR.xvel * 0.5 - this.R.xvel - this.BR.xvel * 0.5 +
this.TL.yvel * 0.5 + this.T.yvel + this.TR.yvel * 0.5 - this.BL.yvel * 0.5 - this.B.yvel - this.BR.yvel * 0.5
) * 0.25;
// ----- velocity -----
this.xvel += (this.TL.pressure * 0.5 + this.L.pressure + this.BL.pressure * 0.5 - this.TR.pressure * 0.5 - this.R.pressure - this.BR.pressure * 0.5) * 0.25;
this.yvel += (this.TL.pressure * 0.5 + this.T.pressure + this.TR.pressure * 0.5 - this.BL.pressure * 0.5 - this.B.pressure - this.BR.pressure * 0.5) * 0.25;
this.xvel *= 0.99;
this.yvel *= 0.99;
// ---- next cell -----
this.nextCell ? this.nextCell.update(mxvel, myvel) : false;
};
// ----- main loop -----
var run = function () {
ctx.fillStyle = "rgba(0,0,0,0.05)";
ctx.fillRect(0, 0, nw, nh);
cells.update(mouseX - pmX, mouseY - pmY);
particles.update();
pmX = mouseX;
pmY = mouseY;
};
// ----- initialization -----
var init = function (params) {
res = params.resolution;
nbP = params.nParticles;
psi = params.penSize;
var d = canvas = document.getElementById("screen");
ctx = canvas.getContext("2d");
// ---- dimensions ----
nw = d.offsetWidth;
nh = d.offsetHeight;
canvas.width = nw;
canvas.height = nh;
for (nx = 0, ny = 0; d != null; d = d.offsetParent) {
nx += d.offsetLeft;
ny += d.offsetTop;
}
nbX = nw / res;
nbY = nh / res;
// ----- create grid -----
for (var y = 0; y < nbY; y++) {
for (var x = 0; x < nbX; x++) {
grid[y * nbX + x] = new Grid(x * res, y * res);
}
}
// ----- link surrounding cells -----
for (var x = 0; x < nbX; x++) {
for (var y = 0; y < nbY; y++) {
var cell = grid[y * nbX + x];
if (y > 0) {
var T = grid[(y - 1) * nbX + x];
cell.T = T;
T.B = cell;
}
if (x > 0) {
var L = grid[y * nbX + x - 1];
cell.L = L;
L.R = cell;
}
if (y > 0 && x > 0) {
var TL = grid[(y - 1) * nbX + x - 1];
cell.TL = TL;
TL.BR = cell;
}
if (y > 0 && x < nbX - 1) {
var TR = grid[(y - 1) * nbX + x + 1];
cell.TR = TR;
TR.BL = cell;
}
}
}
// ---- create particles -----
for (var i = 0; i < nbP; i++) {
new Particle(
Math.random() * nw,
Math.random() * nh
);
}
// ----- mouse events -----
document.addEventListener('mousemove', function (e) {
mouseX = e.clientX - nx;
mouseY = e.clientY - ny;
}, false);
canvas.addEventListener('click', function (e) {
pmX = mouseX;
pmY = mouseY + 100;
}, false);
// ----- touch event -----
document.addEventListener('touchmove', function(e) {
e.preventDefault();
var touch = e.touches[0];
mouseX = touch.pageX - nx;
mouseY = touch.pageY - ny;
}, false);
// ----- start engine -----
setInterval(run, 16);
};
return {
////////////////////////////////////////////////////////////////////////////
/* ==== public functions ==== */
init : function (params) {
window.addEventListener('load', function () {
init(params);
}, false);
}
}
}();
////////////////////////////////////////////////////////////////////////////////
// ---- start script ----
fluid.init({
nParticles: 500,
resolution: 20,
penSize: 80
});
// ----------------------
//
</script>
</head>
<body>
<canvas id="screen">Sorry, this demo requires a web browser which supports HTML5 canvas!</canvas>
</body>
</html>

Tagged with:
 

Feed updates subscription

Enter your email address:

Delivered by FeedBurner

Donate

Want to give me some extra encouragement ?

License

Creative Commons License

Except where otherwise noted, all Javascript code on this site is licensed under a Creative Commons License.