159 lines
3.4 KiB
JavaScript
159 lines
3.4 KiB
JavaScript
|
const warpSpeed = document.querySelector('#warpSpeed');
|
|||
|
gsap.registerPlugin(ScrollTrigger);
|
|||
|
gsap.to('#warpSpeed', {
|
|||
|
value: 100,
|
|||
|
ease: 'none',
|
|||
|
scrollTrigger: { scrub: 0.1 }
|
|||
|
});
|
|||
|
const glsl = x => x;
|
|||
|
|
|||
|
const frag = glsl`
|
|||
|
precision highp float;
|
|||
|
uniform float time;
|
|||
|
uniform float width;
|
|||
|
uniform float height;
|
|||
|
uniform float warpSpeed;
|
|||
|
|
|||
|
const float PI = 3.141592654;
|
|||
|
const float DEG = PI / 180.0;
|
|||
|
|
|||
|
vec2 coords() {
|
|||
|
float vmin = min(width, height);
|
|||
|
return vec2((gl_FragCoord.x - width * .5) / vmin,
|
|||
|
(gl_FragCoord.y - height * .5) / vmin);
|
|||
|
}
|
|||
|
|
|||
|
vec2 rotate(vec2 p, float a) {
|
|||
|
return vec2(p.x * cos(a) - p.y * sin(a),
|
|||
|
p.x * sin(a) + p.y * cos(a));
|
|||
|
}
|
|||
|
|
|||
|
vec2 repeat(in vec2 p, in vec2 c) {
|
|||
|
return mod(p, c) - 0.5 * c;
|
|||
|
}
|
|||
|
|
|||
|
// Distance functions by Inigo Quilez
|
|||
|
// https://iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm
|
|||
|
float circle(in vec2 p, in vec2 pos, float radius) {
|
|||
|
return length((p - pos)) - radius;
|
|||
|
}
|
|||
|
|
|||
|
float symmetricDiff(float a, float b)
|
|||
|
{
|
|||
|
// (A ∪ B) \ (A ∩ B)
|
|||
|
return max(min(a, b), -max(a, b));
|
|||
|
}
|
|||
|
|
|||
|
float subtract(float a, float b)
|
|||
|
{
|
|||
|
return max(-a, b);
|
|||
|
}
|
|||
|
|
|||
|
float circlesField(vec2 p, vec2 pCenter) {
|
|||
|
float d = 1000.;
|
|||
|
float s = .7;
|
|||
|
for (int i = 9; i >= 0; i-= 2) {
|
|||
|
d = min(d, circle(p, pCenter, float(i) * s));
|
|||
|
d = subtract(circle(p, pCenter, float(i-1) * s), d);
|
|||
|
}
|
|||
|
return d;
|
|||
|
}
|
|||
|
|
|||
|
float rectanglesField(vec2 p, vec2 pCenter) {
|
|||
|
return 0.;
|
|||
|
}
|
|||
|
|
|||
|
vec2 dotPattern(vec2 p) {
|
|||
|
float w = 55. - max(0., warpSpeed / 6.);
|
|||
|
return p + sin(p.x * w + time) * cos(p.y * w + time * .1 ) * .125;
|
|||
|
}
|
|||
|
|
|||
|
float aa(float d) {
|
|||
|
return smoothstep(.0, .05, d);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
vec2 scene1(in vec2 p) {
|
|||
|
p = rotate(p, -time * DEG);
|
|||
|
float d0 = circlesField(p, vec2(sin(time * .3), cos(time * .2)));
|
|||
|
float d1 = circlesField(p, vec2(sin(1. + time * .3), cos(1. + time * .2)));
|
|||
|
return vec2(d0, d1);
|
|||
|
}
|
|||
|
|
|||
|
vec2 scene2(in vec2 p) {
|
|||
|
p = rotate(p, time * DEG);
|
|||
|
vec2 q = vec2(cos(time * .2) * .7, sin(time * .3) * .7);
|
|||
|
return vec2(
|
|||
|
circle(mod(p, 4.) - 2., vec2(0.), 2.),
|
|||
|
circle(mod(p + q, 4.) - 2., vec2(0.), 2.)
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
vec3 shade(in vec2 p)
|
|||
|
{
|
|||
|
float sceneId = floor(time / 1e3);
|
|||
|
p = dotPattern(p);
|
|||
|
vec3 background = vec3(.5 + sin(time * .05 + p.x * .1) * cos(p.y * .4 + p.x * .2), .2 + sin(time *.1 + p.x * .2) * cos(time * .1 + p.y * .13), .7);
|
|||
|
vec3 white = vec3(1., 1., 1.);
|
|||
|
vec3 black = vec3(0., 0., 0.);
|
|||
|
vec2 s1 = scene1(p);
|
|||
|
vec2 s2 = scene2(p);
|
|||
|
float x = warpSpeed / 100.; // .5 + sin(time * .1) * .5
|
|||
|
vec2 s = mix(s1, s2, x);
|
|||
|
vec3 col0 = mix(white, black, aa(s.x));
|
|||
|
vec3 col1 = mix(white, black, aa(s.y));
|
|||
|
vec3 col = background + col0 - col1;
|
|||
|
|
|||
|
return col;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void main () {
|
|||
|
vec2 p0 = coords();
|
|||
|
float zoom = 7.;
|
|||
|
vec3 col = shade(p0 * zoom);
|
|||
|
gl_FragColor = vec4(col, 1.0);
|
|||
|
}
|
|||
|
`
|
|||
|
|
|||
|
const vert = glsl`
|
|||
|
precision mediump float;
|
|||
|
attribute vec2 position;
|
|||
|
|
|||
|
void main () {
|
|||
|
gl_Position = vec4(position, 0, 1.0);
|
|||
|
}
|
|||
|
`
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
let texture = null;
|
|||
|
|
|||
|
const glea = new GLea({
|
|||
|
shaders: [
|
|||
|
GLea.fragmentShader(frag),
|
|||
|
GLea.vertexShader(vert)
|
|||
|
]
|
|||
|
}).create();
|
|||
|
|
|||
|
function loop(time) {
|
|||
|
const { gl } = glea;
|
|||
|
glea.clear();
|
|||
|
glea.uni('width', glea.width);
|
|||
|
glea.uni('height', glea.height);
|
|||
|
glea.uni('time', time * .005);
|
|||
|
glea.uni('warpSpeed', parseFloat(warpSpeed.value));
|
|||
|
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|||
|
requestAnimationFrame(loop);
|
|||
|
}
|
|||
|
|
|||
|
function setup() {
|
|||
|
const { gl } = glea;
|
|||
|
window.addEventListener('resize', () => {
|
|||
|
glea.resize();
|
|||
|
});
|
|||
|
loop(0);
|
|||
|
}
|
|||
|
|
|||
|
setup();
|