Skip to content

Instantly share code, notes, and snippets.

@joemccann
Created June 16, 2019 15:19
Show Gist options
  • Save joemccann/9fb647f00b9bd54dc55a6da4b43c81ad to your computer and use it in GitHub Desktop.
Save joemccann/9fb647f00b9bd54dc55a6da4b43c81ad to your computer and use it in GitHub Desktop.
WebGL Smoke
var camera, scene, renderer,
geometry, material, mesh;
init();
animate();
function init() {
stats = new Stats();
stats.setMode(0);
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.body.appendChild(stats.domElement);
clock = new THREE.Clock();
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = 1000;
scene.add( camera );
geometry = new THREE.CubeGeometry( 200, 200, 200 );
material = new THREE.MeshLambertMaterial( { color: 0xaa6666, wireframe: false } );
mesh = new THREE.Mesh( geometry, material );
//scene.add( mesh );
cubeSineDriver = 0;
textGeo = new THREE.PlaneGeometry(300,300);
THREE.ImageUtils.crossOrigin = ''; //Need this to pull in crossdomain images from AWS
textTexture = THREE.ImageUtils.loadTexture('https://s3-us-west-2.amazonaws.com/s.cdpn.io/95637/quickText.png');
textMaterial = new THREE.MeshLambertMaterial({color: 0x00ffff, opacity: 1, map: textTexture, transparent: true, blending: THREE.AdditiveBlending})
text = new THREE.Mesh(textGeo,textMaterial);
text.position.z = 800;
scene.add(text);
light = new THREE.DirectionalLight(0xffffff,0.5);
light.position.set(-1,0,1);
scene.add(light);
smokeTexture = THREE.ImageUtils.loadTexture('https://s3-us-west-2.amazonaws.com/s.cdpn.io/95637/Smoke-Element.png');
smokeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff, map: smokeTexture, transparent: true});
smokeGeo = new THREE.PlaneGeometry(300,300);
smokeParticles = [];
for (p = 0; p < 150; p++) {
var particle = new THREE.Mesh(smokeGeo,smokeMaterial);
particle.position.set(Math.random()*500-250,Math.random()*500-250,Math.random()*1000-100);
particle.rotation.z = Math.random() * 360;
scene.add(particle);
smokeParticles.push(particle);
}
document.body.appendChild( renderer.domElement );
}
function animate() {
// note: three.js includes requestAnimationFrame shim
stats.begin();
delta = clock.getDelta();
requestAnimationFrame( animate );
evolveSmoke();
render();
stats.end();
}
function evolveSmoke() {
var sp = smokeParticles.length;
while(sp--) {
smokeParticles[sp].rotation.z += (delta * 0.2);
}
}
function render() {
mesh.rotation.x += 0.005;
mesh.rotation.y += 0.01;
cubeSineDriver += .01;
mesh.position.z = 100 + (Math.sin(cubeSineDriver) * 500);
renderer.render( scene, camera );
}
<script src="//cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/stats.js/r11/Stats.js"></script>
* {
margin: 0;
padding: 0;
outline: 0;
}
html, body {
width: 100%;
height: 100%;
overflow: hidden;
}

WebGL Smoke

Smoke particle system using an old vfx trick of scaled and rotating single sprite texture in WebGL, plus some additive blending for extra sass :)

Color of smoke may be changed by modifying "color" attribute for smokeMaterial on line 45.

Performance improvement can be had by reducing number of particles, and/or removing "opacity" setting from smokeTex (png will supply opacity, opacity setting simply allows us to "tone it back" or make it slightly more transparent)

Low hanging fruit for visual improvement is randomly setting individual particles to have opposite direction rotation (helps with random look, and avoids edge cases where spinning particles are noticeable)

Coolness improvement: wire up angular with an input box to change the text to user input. Tough to execute on canvas with good, non-aliased results though. Best bet might be wiring up a spritesheet with every letter of the alphabet, then generating planes and painting correct sprite position tex on them...

A Pen by Joe McCann on CodePen.

License.

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