- canvas стартует с opacity:0 и плавно проявляется (0.9s) при .is-ready - initPageMeshShader ставит is-ready после первого кадра - modulepreload page-mesh-shader.js для параллельной загрузки с main.js - пересборка страниц (build:pages)
185 lines
5.5 KiB
JavaScript
185 lines
5.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 staticRadialGradientMeta = {
|
|
maxColorCount: 10
|
|
};
|
|
const staticRadialGradientFragmentShader = `#version 300 es
|
|
precision mediump float;
|
|
|
|
uniform vec4 u_colorBack;
|
|
uniform vec4 u_colors[${staticRadialGradientMeta.maxColorCount}];
|
|
uniform float u_colorsCount;
|
|
|
|
uniform float u_radius;
|
|
uniform float u_focalDistance;
|
|
uniform float u_focalAngle;
|
|
uniform float u_falloff;
|
|
uniform float u_mixing;
|
|
uniform float u_distortion;
|
|
uniform float u_distortionShift;
|
|
uniform float u_distortionFreq;
|
|
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 + mod(float(i), 3.) * .3;
|
|
float c = .8 + mod(float(i + 1), 4.) * 0.25;
|
|
|
|
float x = sin(t * b + a);
|
|
float y = cos(t * c + a * 1.5);
|
|
|
|
return .5 + .5 * vec2(x, y);
|
|
}
|
|
|
|
void main() {
|
|
vec2 uv = 2. * v_objectUV;
|
|
vec2 grainUV = uv * 1000.;
|
|
|
|
vec2 center = vec2(0.);
|
|
float angleRad = -radians(u_focalAngle + 90.);
|
|
vec2 focalPoint = vec2(cos(angleRad), sin(angleRad)) * u_focalDistance;
|
|
float radius = u_radius;
|
|
|
|
vec2 c_to_uv = uv - center;
|
|
vec2 f_to_uv = uv - focalPoint;
|
|
vec2 f_to_c = center - focalPoint;
|
|
float r = length(c_to_uv);
|
|
|
|
float fragAngle = atan(c_to_uv.y, c_to_uv.x);
|
|
float angleDiff = fract((fragAngle - angleRad + PI) / TWO_PI) * TWO_PI - PI;
|
|
|
|
float halfAngle = acos(clamp(radius / max(u_focalDistance, 1e-4), 0.0, 1.0));
|
|
float e0 = 0.6 * PI, e1 = halfAngle;
|
|
float lo = min(e0, e1), hi = max(e0, e1);
|
|
float s = smoothstep(lo, hi, abs(angleDiff));
|
|
float isInSector = (e1 >= e0) ? (1.0 - s) : s;
|
|
|
|
float a = dot(f_to_uv, f_to_uv);
|
|
float b = -2.0 * dot(f_to_uv, f_to_c);
|
|
float c = dot(f_to_c, f_to_c) - radius * radius;
|
|
|
|
float discriminant = b * b - 4.0 * a * c;
|
|
float t = 1.0;
|
|
|
|
if (discriminant >= 0.0) {
|
|
float sqrtD = sqrt(discriminant);
|
|
float div = max(1e-4, 2.0 * a);
|
|
float t0 = (-b - sqrtD) / div;
|
|
float t1 = (-b + sqrtD) / div;
|
|
t = max(t0, t1);
|
|
if (t < 0.0) t = 0.0;
|
|
}
|
|
|
|
float dist = length(f_to_uv);
|
|
float normalized = dist / max(1e-4, length(f_to_uv * t));
|
|
float shape = clamp(normalized, 0.0, 1.0);
|
|
|
|
float falloffMapped = mix(.2 + .8 * max(0., u_falloff + 1.), mix(1., 15., u_falloff * u_falloff), step(.0, u_falloff));
|
|
|
|
float falloffExp = mix(falloffMapped, 1., shape);
|
|
shape = pow(shape, falloffExp);
|
|
shape = 1. - clamp(shape, 0., 1.);
|
|
|
|
|
|
float outerMask = .002;
|
|
float outer = 1.0 - smoothstep(radius - outerMask, radius + outerMask, r);
|
|
outer = mix(outer, 1., isInSector);
|
|
|
|
shape = mix(0., shape, outer);
|
|
shape *= 1. - smoothstep(radius - .01, radius, r);
|
|
|
|
float angle = atan(f_to_uv.y, f_to_uv.x);
|
|
shape -= pow(u_distortion, 2.) * shape * pow(abs(sin(PI * clamp(length(f_to_uv) - 0.2 + u_distortionShift, 0.0, 1.0))), 4.0) * (sin(u_distortionFreq * angle) + cos(floor(0.65 * u_distortionFreq) * angle));
|
|
|
|
float grain = noise(grainUV, vec2(0.));
|
|
float mixerGrain = .4 * u_grainMixer * (grain - .5);
|
|
|
|
float mixer = shape * u_colorsCount + mixerGrain;
|
|
vec4 gradient = u_colors[0];
|
|
gradient.rgb *= gradient.a;
|
|
|
|
float outerShape = 0.;
|
|
for (int i = 1; i < ${staticRadialGradientMeta.maxColorCount + 1}; i++) {
|
|
if (i > int(u_colorsCount)) break;
|
|
float mLinear = clamp(mixer - float(i - 1), 0.0, 1.0);
|
|
|
|
float aa = fwidth(mLinear);
|
|
float width = min(u_mixing, 0.5);
|
|
float t = clamp((mLinear - (0.5 - width - aa)) / (2. * width + 2. * aa), 0., 1.);
|
|
float p = mix(2., 1., clamp((u_mixing - 0.5) * 2., 0., 1.));
|
|
float m = t < 0.5
|
|
? 0.5 * pow(2. * t, p)
|
|
: 1. - 0.5 * pow(2. * (1. - t), p);
|
|
|
|
float quadBlend = clamp((u_mixing - 0.5) * 2., 0., 1.);
|
|
m = mix(m, m * m, 0.5 * quadBlend);
|
|
|
|
if (i == 1) {
|
|
outerShape = m;
|
|
}
|
|
|
|
vec4 c = u_colors[i - 1];
|
|
c.rgb *= c.a;
|
|
gradient = mix(gradient, c, m);
|
|
}
|
|
|
|
vec3 color = gradient.rgb * outerShape;
|
|
float opacity = gradient.a * outerShape;
|
|
|
|
vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
|
|
color = color + bgColor * (1.0 - opacity);
|
|
opacity = opacity + u_colorBack.a * (1.0 - opacity);
|
|
|
|
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 {
|
|
staticRadialGradientFragmentShader,
|
|
staticRadialGradientMeta
|
|
};
|
|
//# sourceMappingURL=static-radial-gradient.js.map
|