fbm + voronoi fire rings
A Pen by Stranger in the Q on CodePen.
fbm + voronoi fire rings
A Pen by Stranger in the Q on CodePen.
<canvas id="canvas"></canvas> | |
<script type="glsl"> | |
precision highp float; | |
uniform float time; | |
uniform vec2 resolution; | |
// taken from https://www.shadertoy.com/view/4tlSzl | |
vec3 firePalette(float i) { | |
float T = 1400. + 1300.*i; | |
vec3 L = vec3(7.4, 5.6, 4.4); | |
L = pow(L,vec3(5.0)) * (exp(1.43876719683e5/(T*L))-1.0); | |
return 1.0-exp(-5e8/L); | |
} | |
vec3 hash33(vec3 p) { | |
float n = sin(dot(p, vec3(7, 157, 113))); | |
return fract(vec3(2097152, 262144, 32768)*n); | |
} | |
float voronoi(vec3 p) { | |
vec3 b, r, g = floor(p); | |
p = fract(p); | |
float d = 1.; | |
for(int j = -1; j <= 1; j++) { | |
for(int i = -1; i <= 1; i++) { | |
b = vec3(i, j, -1); | |
r = b - p + hash33(g+b); | |
d = min(d, dot(r,r)); | |
b.z = 0.0; | |
r = b - p + hash33(g+b); | |
d = min(d, dot(r,r)); | |
b.z = 1.; | |
r = b - p + hash33(g+b); | |
d = min(d, dot(r,r)); | |
} | |
} | |
return d; | |
} | |
float noiseLayers(in vec3 p) { | |
vec3 t = vec3(0., 0., p.z+time); | |
float tot = 0., sum = 0., amp = 1.; | |
for (int i = 0; i < 6; i++) { | |
tot += voronoi(p + t) * amp; | |
p *= 2.0; | |
t *= 1.5; | |
sum += amp; | |
amp *= 0.5; | |
} | |
return tot/sum; | |
} | |
void main(void) { | |
vec2 uv = (gl_FragCoord.xy - resolution.xy*0.5)/ resolution.y; | |
vec3 rd = normalize(vec3(uv.x, uv.y, 3.1415/8.)); | |
float c = noiseLayers(rd*4.); | |
vec3 col = firePalette(c); | |
gl_FragColor = vec4(sqrt(col), 1.); | |
} | |
</script> |
let gl = canvas.getContext('webgl'); | |
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer()); | |
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,3,-1,-1,3,-1]), gl.STATIC_DRAW); | |
let pid = gl.createProgram(); | |
shader(`attribute vec2 v;void main(void){gl_Position=vec4(v,0.,1.);}`,gl.VERTEX_SHADER); | |
shader(document.querySelector(`script[type="glsl"]`).textContent,gl.FRAGMENT_SHADER); | |
gl.linkProgram(pid); | |
gl.useProgram(pid); | |
let v = gl.getAttribLocation(pid, "v"); | |
gl.vertexAttribPointer(v, 2, gl.FLOAT, false, 0, 0); | |
gl.enableVertexAttribArray(v); | |
let resolution = gl.getUniformLocation(pid, 'resolution'); | |
let time = gl.getUniformLocation(pid, 'time'); | |
let fill = gl.getUniformLocation(pid, 'fill'); | |
requestAnimationFrame(draw); | |
function draw(t) { | |
gl.uniform1f(time, t/1000); | |
gl.drawArrays(gl.TRIANGLES, 0, 3); | |
requestAnimationFrame(draw); | |
} | |
function shader(src, type) { | |
let sid = gl.createShader(type); | |
gl.shaderSource(sid, src); | |
gl.compileShader(sid); | |
var message = gl.getShaderInfoLog(sid); | |
gl.attachShader(pid, sid); | |
if (message.length > 0) { | |
console.log(src.split("\n").map((str, i) => | |
(""+(1+i)).padStart(4, "0")+": "+str).join("\n")); | |
throw message; | |
} | |
} | |
addEventListener('resize', function(){ | |
if (innerWidth === canvas.width && | |
innerHeight === canvas.height ) | |
return; | |
canvas.width = innerWidth; | |
canvas.height = innerHeight; | |
gl.uniform2f(resolution, gl.drawingBufferWidth, gl.drawingBufferHeight); | |
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); | |
}) | |
dispatchEvent(new Event('resize')) |
body { | |
overflow:hidden; | |
margin:0; | |
} |
{ | |
"title": "GLSL: fire ", | |
"description": "GLSL: fire ", | |
"steps": [ | |
{ | |
"file": "index.html", | |
"line": 7, | |
"description": "# Heading\n\nOne" | |
}, | |
{ | |
"file": "style.css", | |
"line": 3, | |
"description": "Two" | |
}, | |
{ | |
"file": "script.js", | |
"line": 7, | |
"description": "Three" | |
} | |
] | |
} |