- canvas стартует с opacity:0 и плавно проявляется (0.9s) при .is-ready - initPageMeshShader ставит is-ready после первого кадра - modulepreload page-mesh-shader.js для параллельной загрузки с main.js - пересборка страниц (build:pages)
202 lines
5.5 KiB
JavaScript
202 lines
5.5 KiB
JavaScript
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Paper Shaders *
|
|
* https://github.com/paper-design/shaders *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
import {} from "../shader-sizing.js";
|
|
import { proceduralHash21, declarePI } from "../shader-utils.js";
|
|
const imageDitheringFragmentShader = `#version 300 es
|
|
precision mediump float;
|
|
|
|
uniform vec2 u_resolution;
|
|
uniform float u_pixelRatio;
|
|
uniform float u_originX;
|
|
uniform float u_originY;
|
|
uniform float u_worldWidth;
|
|
uniform float u_worldHeight;
|
|
uniform float u_fit;
|
|
|
|
uniform float u_scale;
|
|
uniform float u_rotation;
|
|
uniform float u_offsetX;
|
|
uniform float u_offsetY;
|
|
|
|
uniform vec4 u_colorFront;
|
|
uniform vec4 u_colorBack;
|
|
uniform vec4 u_colorHighlight;
|
|
|
|
uniform sampler2D u_image;
|
|
uniform float u_imageAspectRatio;
|
|
|
|
uniform float u_type;
|
|
uniform float u_pxSize;
|
|
uniform bool u_originalColors;
|
|
uniform bool u_inverted;
|
|
uniform float u_colorSteps;
|
|
|
|
out vec4 fragColor;
|
|
|
|
|
|
${proceduralHash21}
|
|
${declarePI}
|
|
|
|
float getUvFrame(vec2 uv, vec2 pad) {
|
|
float aa = 0.0001;
|
|
|
|
float left = smoothstep(-pad.x, -pad.x + aa, uv.x);
|
|
float right = smoothstep(1.0 + pad.x, 1.0 + pad.x - aa, uv.x);
|
|
float bottom = smoothstep(-pad.y, -pad.y + aa, uv.y);
|
|
float top = smoothstep(1.0 + pad.y, 1.0 + pad.y - aa, uv.y);
|
|
|
|
return left * right * bottom * top;
|
|
}
|
|
|
|
vec2 getImageUV(vec2 uv) {
|
|
vec2 boxOrigin = vec2(.5 - u_originX, u_originY - .5);
|
|
float r = u_rotation * PI / 180.;
|
|
mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r));
|
|
vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);
|
|
|
|
vec2 imageBoxSize;
|
|
if (u_fit == 1.) { // contain
|
|
imageBoxSize.x = min(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;
|
|
} else if (u_fit == 2.) { // cover
|
|
imageBoxSize.x = max(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;
|
|
} else {
|
|
imageBoxSize.x = min(10.0, 10.0 / u_imageAspectRatio * u_imageAspectRatio);
|
|
}
|
|
imageBoxSize.y = imageBoxSize.x / u_imageAspectRatio;
|
|
vec2 imageBoxScale = u_resolution.xy / imageBoxSize;
|
|
|
|
vec2 imageUV = uv;
|
|
imageUV *= imageBoxScale;
|
|
imageUV += boxOrigin * (imageBoxScale - 1.);
|
|
imageUV += graphicOffset;
|
|
imageUV /= u_scale;
|
|
imageUV.x *= u_imageAspectRatio;
|
|
imageUV = graphicRotation * imageUV;
|
|
imageUV.x /= u_imageAspectRatio;
|
|
|
|
imageUV += .5;
|
|
imageUV.y = 1. - imageUV.y;
|
|
|
|
return imageUV;
|
|
}
|
|
|
|
const int bayer2x2[4] = int[4](0, 2, 3, 1);
|
|
const int bayer4x4[16] = int[16](
|
|
0, 8, 2, 10,
|
|
12, 4, 14, 6,
|
|
3, 11, 1, 9,
|
|
15, 7, 13, 5
|
|
);
|
|
|
|
const int bayer8x8[64] = int[64](
|
|
0, 32, 8, 40, 2, 34, 10, 42,
|
|
48, 16, 56, 24, 50, 18, 58, 26,
|
|
12, 44, 4, 36, 14, 46, 6, 38,
|
|
60, 28, 52, 20, 62, 30, 54, 22,
|
|
3, 35, 11, 43, 1, 33, 9, 41,
|
|
51, 19, 59, 27, 49, 17, 57, 25,
|
|
15, 47, 7, 39, 13, 45, 5, 37,
|
|
63, 31, 55, 23, 61, 29, 53, 21
|
|
);
|
|
|
|
float getBayerValue(vec2 uv, int size) {
|
|
ivec2 pos = ivec2(fract(uv / float(size)) * float(size));
|
|
int index = pos.y * size + pos.x;
|
|
|
|
if (size == 2) {
|
|
return float(bayer2x2[index]) / 4.0;
|
|
} else if (size == 4) {
|
|
return float(bayer4x4[index]) / 16.0;
|
|
} else if (size == 8) {
|
|
return float(bayer8x8[index]) / 64.0;
|
|
}
|
|
return 0.0;
|
|
}
|
|
|
|
|
|
void main() {
|
|
|
|
float pxSize = u_pxSize * u_pixelRatio;
|
|
vec2 pxSizeUV = gl_FragCoord.xy - .5 * u_resolution;
|
|
pxSizeUV /= pxSize;
|
|
vec2 canvasPixelizedUV = (floor(pxSizeUV) + .5) * pxSize;
|
|
vec2 normalizedUV = canvasPixelizedUV / u_resolution;
|
|
|
|
vec2 imageUV = getImageUV(normalizedUV);
|
|
vec2 ditheringNoiseUV = canvasPixelizedUV;
|
|
vec4 image = texture(u_image, imageUV);
|
|
float frame = getUvFrame(imageUV, pxSize / u_resolution);
|
|
|
|
int type = int(floor(u_type));
|
|
float dithering = 0.0;
|
|
|
|
float lum = dot(vec3(.2126, .7152, .0722), image.rgb);
|
|
lum = u_inverted ? (1. - lum) : lum;
|
|
|
|
switch (type) {
|
|
case 1: {
|
|
dithering = step(hash21(ditheringNoiseUV), lum);
|
|
} break;
|
|
case 2:
|
|
dithering = getBayerValue(pxSizeUV, 2);
|
|
break;
|
|
case 3:
|
|
dithering = getBayerValue(pxSizeUV, 4);
|
|
break;
|
|
default :
|
|
dithering = getBayerValue(pxSizeUV, 8);
|
|
break;
|
|
}
|
|
|
|
float colorSteps = max(floor(u_colorSteps), 1.);
|
|
vec3 color = vec3(0.0);
|
|
float opacity = 1.;
|
|
|
|
dithering -= .5;
|
|
float brightness = clamp(lum + dithering / colorSteps, 0.0, 1.0);
|
|
brightness = mix(0.0, brightness, frame);
|
|
brightness = mix(0.0, brightness, image.a);
|
|
float quantLum = floor(brightness * colorSteps + 0.5) / colorSteps;
|
|
quantLum = mix(0.0, quantLum, frame);
|
|
|
|
if (u_originalColors == true) {
|
|
vec3 normColor = image.rgb / max(lum, 0.001);
|
|
color = normColor * quantLum;
|
|
|
|
float quantAlpha = floor(image.a * colorSteps + 0.5) / colorSteps;
|
|
opacity = mix(quantLum, 1., quantAlpha);
|
|
} else {
|
|
vec3 fgColor = u_colorFront.rgb * u_colorFront.a;
|
|
float fgOpacity = u_colorFront.a;
|
|
vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
|
|
float bgOpacity = u_colorBack.a;
|
|
vec3 hlColor = u_colorHighlight.rgb * u_colorHighlight.a;
|
|
float hlOpacity = u_colorHighlight.a;
|
|
|
|
fgColor = mix(fgColor, hlColor, step(1.02 - .02 * u_colorSteps, brightness));
|
|
fgOpacity = mix(fgOpacity, hlOpacity, step(1.02 - .02 * u_colorSteps, brightness));
|
|
|
|
color = fgColor * quantLum;
|
|
opacity = fgOpacity * quantLum;
|
|
color += bgColor * (1.0 - opacity);
|
|
opacity += bgOpacity * (1.0 - opacity);
|
|
}
|
|
|
|
fragColor = vec4(color, opacity);
|
|
}
|
|
`;
|
|
const DitheringTypes = {
|
|
"random": 1,
|
|
"2x2": 2,
|
|
"4x4": 3,
|
|
"8x8": 4
|
|
};
|
|
export {
|
|
DitheringTypes,
|
|
imageDitheringFragmentShader
|
|
};
|
|
//# sourceMappingURL=image-dithering.js.map
|