- canvas стартует с opacity:0 и плавно проявляется (0.9s) при .is-ready - initPageMeshShader ставит is-ready после первого кадра - modulepreload page-mesh-shader.js для параллельной загрузки с main.js - пересборка страниц (build:pages)
128 lines
3.5 KiB
JavaScript
128 lines
3.5 KiB
JavaScript
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Paper Shaders *
|
|
* https://github.com/paper-design/shaders *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
import {
|
|
} from "../shader-sizing.js";
|
|
import { declarePI, rotation2, proceduralHash21 } from "../shader-utils.js";
|
|
const meshGradientMeta = {
|
|
maxColorCount: 10
|
|
};
|
|
const meshGradientFragmentShader = `#version 300 es
|
|
precision mediump float;
|
|
|
|
uniform float u_time;
|
|
|
|
uniform vec4 u_colors[${meshGradientMeta.maxColorCount}];
|
|
uniform float u_colorsCount;
|
|
|
|
uniform float u_distortion;
|
|
uniform float u_swirl;
|
|
uniform float u_grainMixer;
|
|
uniform float u_grainOverlay;
|
|
|
|
in vec2 v_objectUV;
|
|
out vec4 fragColor;
|
|
|
|
${declarePI}
|
|
${rotation2}
|
|
${proceduralHash21}
|
|
|
|
float valueNoise(vec2 st) {
|
|
vec2 i = floor(st);
|
|
vec2 f = fract(st);
|
|
float a = hash21(i);
|
|
float b = hash21(i + vec2(1.0, 0.0));
|
|
float c = hash21(i + vec2(0.0, 1.0));
|
|
float d = hash21(i + vec2(1.0, 1.0));
|
|
vec2 u = f * f * (3.0 - 2.0 * f);
|
|
float x1 = mix(a, b, u.x);
|
|
float x2 = mix(c, d, u.x);
|
|
return mix(x1, x2, u.y);
|
|
}
|
|
|
|
float noise(vec2 n, vec2 seedOffset) {
|
|
return valueNoise(n + seedOffset);
|
|
}
|
|
|
|
vec2 getPosition(int i, float t) {
|
|
float a = float(i) * .37;
|
|
float b = .6 + fract(float(i) / 3.) * .9;
|
|
float c = .8 + fract(float(i + 1) / 4.);
|
|
|
|
float x = sin(t * b + a);
|
|
float y = cos(t * c + a * 1.5);
|
|
|
|
return .5 + .5 * vec2(x, y);
|
|
}
|
|
|
|
void main() {
|
|
vec2 uv = v_objectUV;
|
|
uv += .5;
|
|
vec2 grainUV = uv * 1000.;
|
|
|
|
float grain = noise(grainUV, vec2(0.));
|
|
float mixerGrain = .4 * u_grainMixer * (grain - .5);
|
|
|
|
const float firstFrameOffset = 41.5;
|
|
float t = .5 * (u_time + firstFrameOffset);
|
|
|
|
float radius = smoothstep(0., 1., length(uv - .5));
|
|
float center = 1. - radius;
|
|
for (float i = 1.; i <= 2.; i++) {
|
|
uv.x += u_distortion * center / i * sin(t + i * .4 * smoothstep(.0, 1., uv.y)) * cos(.2 * t + i * 2.4 * smoothstep(.0, 1., uv.y));
|
|
uv.y += u_distortion * center / i * cos(t + i * 2. * smoothstep(.0, 1., uv.x));
|
|
}
|
|
|
|
vec2 uvRotated = uv;
|
|
uvRotated -= vec2(.5);
|
|
float angle = 3. * u_swirl * radius;
|
|
uvRotated = rotate(uvRotated, -angle);
|
|
uvRotated += vec2(.5);
|
|
|
|
vec3 color = vec3(0.);
|
|
float opacity = 0.;
|
|
float totalWeight = 0.;
|
|
|
|
for (int i = 0; i < ${meshGradientMeta.maxColorCount}; i++) {
|
|
if (i >= int(u_colorsCount)) break;
|
|
|
|
vec2 pos = getPosition(i, t) + mixerGrain;
|
|
vec3 colorFraction = u_colors[i].rgb * u_colors[i].a;
|
|
float opacityFraction = u_colors[i].a;
|
|
|
|
float dist = length(uvRotated - pos);
|
|
|
|
dist = pow(dist, 3.5);
|
|
float weight = 1. / (dist + 1e-3);
|
|
color += colorFraction * weight;
|
|
opacity += opacityFraction * weight;
|
|
totalWeight += weight;
|
|
}
|
|
|
|
color /= max(1e-4, totalWeight);
|
|
opacity /= max(1e-4, totalWeight);
|
|
|
|
float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.));
|
|
grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5);
|
|
grainOverlay = pow(grainOverlay, 1.3);
|
|
|
|
float grainOverlayV = grainOverlay * 2. - 1.;
|
|
vec3 grainOverlayColor = vec3(step(0., grainOverlayV));
|
|
float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);
|
|
grainOverlayStrength = pow(grainOverlayStrength, .8);
|
|
color = mix(color, grainOverlayColor, .35 * grainOverlayStrength);
|
|
|
|
opacity += .5 * grainOverlayStrength;
|
|
opacity = clamp(opacity, 0., 1.);
|
|
|
|
fragColor = vec4(color, opacity);
|
|
}
|
|
`;
|
|
export {
|
|
meshGradientFragmentShader,
|
|
meshGradientMeta
|
|
};
|
|
//# sourceMappingURL=mesh-gradient.js.map
|