Skip to content

Instantly share code, notes, and snippets.

@veeenu
Last active October 10, 2015 11:49
Show Gist options
  • Save veeenu/f326c99248e4ae244aef to your computer and use it in GitHub Desktop.
Save veeenu/f326c99248e4ae244aef to your computer and use it in GitHub Desktop.
Particle System - I
<!DOCTYPE html>
<html>
<head>
<link rel='stylesheet' href='style.css'/>
</head>
<body>
<script type='application/x-shader' id='vertex'>
attribute vec3 Position;
attribute float Size, Life;
varying float vLife;
void main() {
gl_Position = vec4(Position, 1.);
gl_PointSize = Size;
vLife = Life;
}
</script>
<script type='application/x-shader' id='fragment'>
precision highp float;
varying float vLife;
void main() {
float dist = 1. - length(gl_PointCoord - .5) * 2.;
gl_FragColor = vec4(1., .2, .1, vLife * .35 * mix(0., 1., dist * dist));
}
</script>
<script src='particles.js'></script>
</body>
</html>
(function() {
var canvas = document.createElement('canvas'),
gl = canvas.getContext('webgl'),
prog = [ { t: gl.VERTEX_SHADER, e: 'vertex' },
{ t: gl.FRAGMENT_SHADER, e: 'fragment' } ]
.reduce(function(prog, i) {
var sh = gl.createShader(i.t);
gl.shaderSource(sh, document.getElementById(i.e).textContent);
gl.compileShader(sh);
gl.attachShader(prog, sh);
console.log(gl.getShaderInfoLog(sh));
return prog;
}, gl.createProgram());
document.body.appendChild(canvas);
gl.linkProgram(prog);
gl.useProgram(prog);
prog.position = gl.getAttribLocation(prog, 'Position');
prog.size = gl.getAttribLocation(prog, 'Size');
prog.life = gl.getAttribLocation(prog, 'Life');
console.log(gl.getProgramInfoLog(prog));
var ParticleSystem = function(count) {
this.count = count;
this.position = new Float32Array(3 * count);
this.size = new Float32Array(1 * count);
this.life = new Float32Array(1 * count);
this.angle = new Float32Array(1 * count);
this.displ = new Float32Array(1 * count);
this.aging = new Float32Array(1 * count);
this.positionB = gl.createBuffer();
this.sizeB = gl.createBuffer();
this.lifeB = gl.createBuffer();
this.deadParticles = count + 1;
};
ParticleSystem.prototype.recalcParticle = function(i) {
this.angle[i] = 2 * Math.PI * i / this.count;
this.displ[i] = (Math.random() -.5) * .0625;
this.size[i] = Math.random() * .125 * canvas.width;
this.life[i] = 1 - Math.random() * .125;
}
ParticleSystem.prototype.enable = function(gl, positionL, sizeL, lifeL) {
gl.enableVertexAttribArray(positionL);
gl.enableVertexAttribArray(sizeL);
gl.enableVertexAttribArray(lifeL);
gl.bindBuffer(gl.ARRAY_BUFFER, this.positionB);
gl.bufferData(gl.ARRAY_BUFFER, this.position, gl.DYNAMIC_DRAW);
gl.vertexAttribPointer(positionL, 3, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, this.sizeB);
gl.bufferData(gl.ARRAY_BUFFER, this.size, gl.DYNAMIC_DRAW);
gl.vertexAttribPointer(sizeL, 1, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, this.lifeB);
gl.bufferData(gl.ARRAY_BUFFER, this.life, gl.DYNAMIC_DRAW);
gl.vertexAttribPointer(lifeL, 1, gl.FLOAT, false, 0, 0);
}
ParticleSystem.prototype.update = function() {
if(this.deadParticles > this.count) {
for(var i = 0; i < this.count; i++) {
this.recalcParticle(i);
}
this.deadParticles = 0;
}
for(var i = 0; i < this.count; i++) {
this.life[i] *= .975;
this.angle[i] -= Math.PI * this.life[i] * this.displ[i] / .25
if(this.life[i] <= .01) {
this.deadParticles++;
continue;
}
var l = this.life[i],
lC = 1 - l,
d = this.displ[i],
a = this.angle[i],
sp = a / (4 * Math.PI);
this.position[i * 3] = .5 * (lC + d) * sp * Math.cos(a);
this.position[i * 3 + 1] = .5 * (lC + d) * sp * Math.sin(a);
}
gl.bindBuffer(gl.ARRAY_BUFFER, this.positionB);
gl.bufferSubData(gl.ARRAY_BUFFER, this.positionB, this.position);
gl.bindBuffer(gl.ARRAY_BUFFER, this.sizeB);
gl.bufferSubData(gl.ARRAY_BUFFER, this.sizeB, this.size);
gl.bindBuffer(gl.ARRAY_BUFFER, this.lifeB);
gl.bufferSubData(gl.ARRAY_BUFFER, this.lifeB, this.life);
}
var ps = new ParticleSystem(2048);
ps.enable(gl, prog.position, prog.size, prog.life);
canvas.width = canvas.height = Math.min(innerWidth, innerHeight);
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
var r = function() {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.depthMask(false);
gl.drawArrays(gl.POINTS, 0, ps.count);
gl.depthMask(true);
requestAnimationFrame(r);
ps.update();
}
r();
}());
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
body {
margin: 0;
padding: 0;
overflow: hidden;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment