<div id="world"></div>
* {
	margin: 0;
	padding: 0;
	box-sizing: border-box;
}
import { EffectComposer } from "https://unpkg.com/three@0.120.0/examples/jsm/postprocessing/EffectComposer.js";
import { RenderPass } from "https://unpkg.com/three@0.120.0/examples/jsm/postprocessing/RenderPass.js";
import { UnrealBloomPass } from "https://unpkg.com/three@0.120.0/examples/jsm/postprocessing/UnrealBloomPass.js";
import { ShaderPass } from "https://unpkg.com/three@0.120.0/examples/jsm/postprocessing/ShaderPass.js";
import { OrbitControls } from "https://unpkg.com/three@0.120.0/examples/jsm/controls/OrbitControls.js";

const ENTIRE_SCENE = 0,
	BLOOM_SCENE = 1;

const bloomLayer = new THREE.Layers();
bloomLayer.set(BLOOM_SCENE);
const materials = {};
const darkMaterial = new THREE.MeshBasicMaterial({ color: "black" });

const vert = `
    varying vec3 vNormal;
    varying vec3 camPos;
    varying vec2 vUv;

    void main() {
    vNormal = normal;
    vUv = uv;
    camPos = cameraPosition;
    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
    }
`;

const frag = `
#define NUM_OCTAVES 5
#define M_PI 3.1415926535897932384626433832795
uniform vec4 resolution;
varying vec3 vNormal;
uniform sampler2D perlinnoise;
uniform sampler2D sparknoise;
uniform float time;
uniform vec3 color0;
uniform vec3 color1;
uniform vec3 color2;
uniform vec3 color3;
uniform vec3 color4;
uniform vec3 color5;
varying vec3 camPos;
varying vec2 vUv;

float setOpacity(float r, float g, float b, float tonethreshold) {
  float tone = (r + g + b) / 3.0;
  float alpha = 1.0;
  if(tone<tonethreshold) {
    alpha = 0.0;
  }
  return alpha;
}

vec3 rgbcol(vec3 col) {
  return vec3(col.r/255.0,col.g/255.0,col.b/255.0);
}

vec2 rotate(vec2 v, float a) {
  float s = sin(a);
  float c = cos(a);
  mat2 m = mat2(c, -s, s, c);
  return m * v;
}

vec2 UnityPolarCoordinates (vec2 UV, vec2 Center, float RadialScale, float LengthScale){
  //https://twitter.com/Cyanilux/status/1123950519133908995/photo/1
  vec2 delta = UV - Center;
  float radius = length(delta) * 2. * RadialScale;
  float angle = atan(delta.x, delta.y) * 1.0/6.28 * LengthScale;
  return vec2(radius, angle);
}

void main() {
  vec2 olduv = gl_FragCoord.xy/resolution.xy ;
  vec2 uv = vUv ; 
  vec2 imguv = uv;
  float scale = 1.;
  olduv *= 0.5 + time; 
  olduv.y = olduv.y ;
  vec2 p = olduv*scale;
  vec4 txt = texture2D(perlinnoise, olduv);
  float gradient = dot(normalize( -camPos ), normalize( vNormal ));
  float pct = distance(vUv,vec2(0.5));

  vec3 rgbcolor0 = rgbcol(color0);
  vec3 rgbcolor1 = rgbcol(color1);
  vec3 rgbcolor2 = rgbcol(color2);
  vec3 rgbcolor5 = rgbcol(color5);

  // set solid background
  float y = smoothstep(0.16,0.525,pct);
  vec3 backcolor = mix(rgbcolor0, rgbcolor5, y);

  gl_FragColor = vec4(backcolor,1.);

  // set polar coords
  vec2 center = vec2(0.5);
  vec2 cor = UnityPolarCoordinates(vec2(vUv.x,vUv.y), center, 1., 1.);

  // set textures
  vec2 newUv = vec2(cor.x + time,cor.x*0.2+cor.y);
  vec3 noisetex = texture2D(perlinnoise,mod(newUv,1.)).rgb;    
  vec3 noisetex2 = texture2D(sparknoise,mod(newUv,1.)).rgb;    


  // set textures tones
  float tone0 =  1. - smoothstep(0.3,0.6,noisetex.r);
  float tone1 =  smoothstep(0.3,0.6,noisetex2.r);


  // set opacity for each tone
  float opacity0 = setOpacity(tone0,tone0,tone0,.29);
  float opacity1 = setOpacity(tone1,tone1,tone1,.49);

  //set final render
  if(opacity1>0.0){
    gl_FragColor = vec4(rgbcolor2,0.)*vec4(opacity1);
  } else if(opacity0>0.0){
    gl_FragColor = vec4(rgbcolor1,0.)*vec4(opacity0);
  }   
}
`;

const vertcylinder = `
    varying vec2 vUv;

    void main() {
        vUv = uv;
        vec3 pos = vec3(position.x/1.,position.y,position.z/1.);
        if(pos.y >= 1.87){
            pos = vec3(position.x*(sin((position.y - 0.6)*1.27)-0.16),position.y,position.z*(sin((position.y - 0.6)*1.27)-0.16));
        } else{
            pos = vec3(position.x*(sin((position.y/2. -  .01)*.11)+0.75),position.y,position.z*(sin((position.y/2. -  .01)*.11)+0.75));
        }
        gl_Position = projectionMatrix * modelViewMatrix * vec4( pos, 1.0 );
    }
`;

const fragcylinder = `
    varying vec2 vUv;
    uniform sampler2D perlinnoise;
    uniform vec3 color4;
    uniform float time;
    varying vec3 vNormal;

    vec3 rgbcol(vec3 col) {
        return vec3(col.r/255.0,col.g/255.0,col.b/255.0);
    }

    void main() {
        vec3 noisetex = texture2D(perlinnoise,mod(1.*vec2(vUv.y-time*2.,vUv.x + time*1.),1.)).rgb;    
        gl_FragColor = vec4(noisetex.r);

        if(gl_FragColor.r >= 0.5){
            gl_FragColor = vec4(rgbcol(color4),gl_FragColor.r);
        }else{
            gl_FragColor = vec4(0.);
        }
        gl_FragColor *= vec4(sin(vUv.y) - 0.1);
        gl_FragColor *= vec4(smoothstep(0.3,0.628,vUv.y));

    }

`;

const vertflame = `
    varying vec2 vUv;
    varying vec3 camPos;
    varying vec3 vNormal;
    varying vec3 nois;
    uniform sampler2D noise;
    uniform float time;

    void main() {
        vUv = uv;
        camPos = cameraPosition;
        vNormal = normal;
        vec3 pos = vec3(position.x/1.,position.y,position.z/1.);
        vec3 noisetex = texture2D(noise,mod(1.*vec2(vUv.y-time*2.,vUv.x + time*1.),1.)).rgb;
        if(pos.y >= 1.87){
            pos = vec3(position.x*(sin((position.y - 0.64)*1.27)-0.12),position.y,position.z*(sin((position.y - 0.64)*1.27)-0.12));
        } else{
            pos = vec3(position.x*(sin((position.y/2. -  .01)*.11)+0.79),position.y,position.z*(sin((position.y/2. -  .01)*.11)+0.79));
        }
        pos.xz *= noisetex.r;
        gl_Position = projectionMatrix * modelViewMatrix * vec4( pos, 1.0 );
    }
`;

const fragflame = `
    varying vec2 vUv;
    uniform sampler2D perlinnoise;
    uniform sampler2D noise;
    uniform vec3 color4;
    uniform float time;
    varying vec3 camPos;
    varying vec3 vNormal;
    varying vec3 nois;

    vec3 rgbcol(vec3 col) {
        return vec3(col.r/255.0,col.g/255.0,col.b/255.0);
    }

      
    void main() {
        // vec3 noisetex = texture2D(perlinnoise,mod(1.*vec2(vUv.y-time*2.,vUv.x + time*1.),1.)).rgb;    
        // gl_FragColor += vec4(sin((vUv.y - time)*(20. + vUv.y)));
        vec3 noisetex = texture2D(noise,mod(1.*vec2(vUv.y-time*2.,vUv.x + time*1.),1.)).rgb;
        // nois = noisetex;
        gl_FragColor = vec4(noisetex.r);

        if(gl_FragColor.r >= 0.44){
            gl_FragColor = vec4(rgbcol(color4),gl_FragColor.r);
        }
        // else if(gl_FragColor.r >= 0.9){
        //     // gl_FragColor = vec4(rgbcol(color4),gl_FragColor.r)*0.5;
        // }
        else{
            gl_FragColor = vec4(0.);
        }
        gl_FragColor *= vec4(smoothstep(0.2,0.628,vUv.y));
        // gl_FragColor = vec4(vUv.y - 0.3 );
        // gl_FragColor = 1. - vec4(dot(normalize(vNormal),normalize(camPos)).r);
    }

`;

let options = {
	exposure: 2.8,
	bloomStrength: 3.5,
	bloomRadius: 0.39,
	color0: [0, 0, 0],
	color1: [81, 14, 5],
	color2: [181, 156, 24],
	color3: [66, 66, 66],
	color4: [79, 79, 79],
	color5: [64, 27, 0]
};

// let options = {
//   exposure: 2.8,
//   bloomStrength: 3.5,
//   //   bloomStrength: 0,
//   bloomRadius: 0.39,
//   color0: [15, 0, 10],
//   color1: [13, 6, 5],
//   color2: [137, 56, 10],
//   color3: [166, 166, 166],
//   color4: [237, 149, 67],
//   color5: [20, 0, 51],
// };
let gui = new dat.GUI();

let bloom = gui.addFolder("Bloom");
bloom.add(options, "bloomStrength", 0.0, 5.0).name("bloomStrength").listen();
bloom.add(options, "bloomRadius", 0.1, 2.0).name("bloomRadius").listen();
bloom.open();

let color = gui.addFolder("Colors");
color.addColor(options, "color0").name("ball0");
color.addColor(options, "color1").name("ball1");
color.addColor(options, "color2").name("ball2");
color.addColor(options, "color4").name("steam");
color.addColor(options, "color5").name("trail");
color.open();
gui.close();

let scene,
	camera,
	renderer,
	controls,
	material,
	material2,
	material3,
	bloomPass,
	bloomComposer,
	composer,
	finalPass,
	finalComposer;
const width = window.innerWidth,
	height = window.innerHeight;

function init() {
	createScene();
	postProc();
	mesh();
	flame();
	cylinder();
	animatBloom();
}

function createScene() {
	scene = new THREE.Scene();
	camera = new THREE.PerspectiveCamera(
		75,
		window.innerWidth / window.innerHeight,
		0.1,
		1000
	);
	camera.position.set(3.4369982203815655, 3.5239085092722098, 2.994862383531814);
	renderer = new THREE.WebGLRenderer();
	renderer.antialias = true;
	renderer.setClearColor(new THREE.Color('#000'));
	renderer.setPixelRatio(window.devicePixelRatio);
	renderer.setSize(width, height);
	controls = new OrbitControls(camera, renderer.domElement);
	document.getElementById("world").appendChild(renderer.domElement);
}

function postProc() {
	const renderScene = new RenderPass(scene, camera);
	bloomPass = new UnrealBloomPass(
		new THREE.Vector2(window.innerWidth, window.innerHeight),
		1.5,
		0.4,
		0.85
	);
	bloomPass.threshold = options.bloomThreshold;
	bloomPass.strength = options.bloomStrength;
	bloomPass.radius = options.bloomRadius;

	bloomComposer = new EffectComposer(renderer);
	bloomComposer.addPass(renderScene);
	bloomComposer.addPass(bloomPass);
}

function mesh() {
	const geometry = new THREE.SphereBufferGeometry(1, 30, 30);
	material = new THREE.ShaderMaterial({
		uniforms: {
			time: {
				type: "f",
				value: 0.0
			},
			perlinnoise: {
				type: "t",
				value: new THREE.TextureLoader().load(
					"https://raw.githubusercontent.com/pizza3/asset/master/noise9.jpg"
				)
			},
			sparknoise: {
				type: "t",
				value: new THREE.TextureLoader().load(
					"https://raw.githubusercontent.com/pizza3/asset/master/sparklenoise.jpg"
				)
			},
			color5: {
				value: new THREE.Vector3(...options.color5)
			},
			color4: {
				value: new THREE.Vector3(...options.color4)
			},
			color3: {
				value: new THREE.Vector3(...options.color3)
			},
			color2: {
				value: new THREE.Vector3(...options.color2)
			},
			color1: {
				value: new THREE.Vector3(...options.color1)
			},
			color0: {
				value: new THREE.Vector3(...options.color0)
			},
			resolution: { value: new THREE.Vector2(width, height) }
		},
		vertexShader: vert,
		fragmentShader: frag
	});

	const mesh = new THREE.Mesh(geometry, material);
	mesh.scale.set(0.78, 0.78, 0.78);
	mesh.position.set(1 + 0, 0, 0);
	scene.add(mesh);
}

function cylinder() {
	const geometry = new THREE.CylinderBufferGeometry(1.11, 0, 5.3, 50, 50, true);
	material2 = new THREE.ShaderMaterial({
		uniforms: {
			perlinnoise: {
				type: "t",
				value: new THREE.TextureLoader().load(
					"https://raw.githubusercontent.com/pizza3/asset/master/water-min.jpg"
				)
			},
			color4: {
				value: new THREE.Vector3(...options.color4)
			},
			time: {
				type: "f",
				value: 0.0
			},
			noise: {
				type: "t",
				value: new THREE.TextureLoader().load(
					"https://raw.githubusercontent.com/pizza3/asset/master/noise9.jpg"
				)
			}
		},
		// wireframe:true,
		vertexShader: vertcylinder,
		fragmentShader: fragcylinder,
		transparent: true,
		depthWrite: false,
		side: THREE.DoubleSide
	});

	const mesh = new THREE.Mesh(geometry, material2);
	mesh.rotation.set(0, 0, -Math.PI / 2);
	mesh.position.set(1 + -4.05, 0, 0);
	mesh.scale.set(1.5, 1.7, 1.5);
	scene.add(mesh);
}

function flame() {
	const geometry = new THREE.CylinderBufferGeometry(1, 0, 5.3, 50, 50, true);
	material3 = new THREE.ShaderMaterial({
		uniforms: {
			perlinnoise: {
				type: "t",
				value: new THREE.TextureLoader().load(
					"https://raw.githubusercontent.com/pizza3/asset/master/water-min.jpg"
				)
			},
			color4: {
				value: new THREE.Vector3(...options.color5)
			},
			time: {
				type: "f",
				value: 0.0
			},
			noise: {
				type: "t",
				value: new THREE.TextureLoader().load(
					"https://raw.githubusercontent.com/pizza3/asset/master/noise9.jpg"
				)
			}
		},
		// wireframe:true,
		vertexShader: vertflame,
		fragmentShader: fragflame,
		transparent: true,
		depthWrite: false,
		side: THREE.DoubleSide
	});

	const mesh = new THREE.Mesh(geometry, material3);
	mesh.rotation.set(0, 0, -Math.PI / 2);
	mesh.position.set(1 + -4.78, 0, 0);
	mesh.scale.set(2, 2, 2);
	scene.add(mesh);
}

function updateDraw(deltaTime) {
	material.uniforms.time.value = -deltaTime / (1000 * 2);
	material2.uniforms.time.value = -deltaTime / (3000 * 2);
	material3.uniforms.time.value = -deltaTime / (3000 * 2);
	material.uniforms.color5.value = new THREE.Vector3(...options.color5);
	material2.uniforms.color4.value = new THREE.Vector3(...options.color4);
	material3.uniforms.color4.value = new THREE.Vector3(...options.color5);
	material.uniforms.color3.value = new THREE.Vector3(...options.color3);
	material.uniforms.color2.value = new THREE.Vector3(...options.color2);
	material.uniforms.color1.value = new THREE.Vector3(...options.color1);
	material.uniforms.color0.value = new THREE.Vector3(...options.color0);
}



function animatBloom(deltaTime) {
	requestAnimationFrame(animatBloom);
	updateDraw(deltaTime);
	controls.update();
	bloomPass.strength = options.bloomStrength;
	bloomPass.radius = options.bloomRadius;
	bloomComposer.render();
}


function handleResize() {
	camera.aspect = window.innerWidth / window.innerHeight;
	camera.updateProjectionMatrix();
	renderer.setSize(window.innerWidth, window.innerHeight);
}

window.addEventListener("load", init);
window.addEventListener("resize", handleResize, false);
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/three.js/r120/three.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.min.js