enhance(frontend): glslを単独のファイルに分離 (#16665)

This commit is contained in:
かっこかり 2025-10-20 15:23:19 +09:00 committed by GitHub
parent 4e9070a4c5
commit b8433b2413
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
43 changed files with 1052 additions and 970 deletions

View File

@ -142,6 +142,7 @@
"storybook": "9.1.10",
"storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme",
"tsx": "4.20.6",
"vite-plugin-glsl": "1.5.4",
"vite-plugin-turbosnap": "1.0.3",
"vitest": "3.2.4",
"vitest-fetch-mock": "0.4.5",

View File

@ -0,0 +1,85 @@
// Description : Array and textureless GLSL 2D/3D/4D simplex
// noise functions.
// Author : Ian McEwan, Ashima Arts.
// Maintainer : stegu
// Lastmod : 20201014 (stegu)
// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
// Distributed under the MIT License. See LICENSE file.
// https://github.com/ashima/webgl-noise
// https://github.com/stegu/webgl-noise
vec3 mod289(vec3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 mod289(vec4 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 permute(vec4 x) {
return mod289(((x * 34.0) + 10.0) * x);
}
vec4 taylorInvSqrt(vec4 r) {
return 1.79284291400159 - 0.85373472095314 * r;
}
float snoise(vec3 v) {
const vec2 C = vec2(1.0/6.0, 1.0/3.0);
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
vec3 i = floor(v + dot(v, C.yyy));
vec3 x0 = v - i + dot(i, C.xxx);
vec3 g = step(x0.yzx, x0.xyz);
vec3 l = 1.0 - g;
vec3 i1 = min(g.xyz, l.zxy);
vec3 i2 = max(g.xyz, l.zxy);
vec3 x1 = x0 - i1 + C.xxx;
vec3 x2 = x0 - i2 + C.yyy;
vec3 x3 = x0 - D.yyy;
i = mod289(i);
vec4 p = permute(permute(permute(
i.z + vec4(0.0, i1.z, i2.z, 1.0))
+ i.y + vec4(0.0, i1.y, i2.y, 1.0))
+ i.x + vec4(0.0, i1.x, i2.x, 1.0));
float n_ = 0.142857142857;
vec3 ns = n_ * D.wyz - D.xzx;
vec4 j = p - 49.0 * floor(p * ns.z * ns.z);
vec4 x_ = floor(j * ns.z);
vec4 y_ = floor(j - 7.0 * x_);
vec4 x = x_ * ns.x + ns.yyyy;
vec4 y = y_ * ns.x + ns.yyyy;
vec4 h = 1.0 - abs(x) - abs(y);
vec4 b0 = vec4(x.xy, y.xy);
vec4 b1 = vec4(x.zw, y.zw);
vec4 s0 = floor(b0) * 2.0 + 1.0;
vec4 s1 = floor(b1) * 2.0 + 1.0;
vec4 sh = -step(h, vec4(0.0));
vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;
vec3 p0 = vec3(a0.xy, h.x);
vec3 p1 = vec3(a0.zw, h.y);
vec3 p2 = vec3(a1.xy, h.z);
vec3 p3 = vec3(a1.zw, h.w);
vec4 norm = taylorInvSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));
p0 *= norm.x;
p1 *= norm.y;
p2 *= norm.z;
p3 *= norm.w;
vec4 m = max(0.5 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0);
m = m * m;
return 105.0 * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3)));
}

View File

@ -0,0 +1,43 @@
#version 300 es
precision mediump float;
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform int u_amount;
uniform float u_shiftStrengths[128];
uniform vec2 u_shiftOrigins[128];
uniform vec2 u_shiftSizes[128];
uniform float u_channelShift;
out vec4 out_color;
void main() {
// TODO: ピクセル毎に計算する必要はないのでuniformにする
float aspect_ratio = min(in_resolution.x, in_resolution.y) / max(in_resolution.x, in_resolution.y);
float aspect_ratio_x = in_resolution.x > in_resolution.y ? 1.0 : aspect_ratio;
float aspect_ratio_y = in_resolution.x < in_resolution.y ? 1.0 : aspect_ratio;
float v = 0.0;
for (int i = 0; i < u_amount; i++) {
if (
in_uv.x * aspect_ratio_x > ((u_shiftOrigins[i].x * aspect_ratio_x) - u_shiftSizes[i].x) &&
in_uv.x * aspect_ratio_x < ((u_shiftOrigins[i].x * aspect_ratio_x) + u_shiftSizes[i].x) &&
in_uv.y * aspect_ratio_y > ((u_shiftOrigins[i].y * aspect_ratio_y) - u_shiftSizes[i].y) &&
in_uv.y * aspect_ratio_y < ((u_shiftOrigins[i].y * aspect_ratio_y) + u_shiftSizes[i].y)
) {
v += u_shiftStrengths[i];
}
}
float r = texture(in_texture, vec2(in_uv.x + (v * (1.0 + u_channelShift)), in_uv.y)).r;
float g = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).g;
float b = texture(in_texture, vec2(in_uv.x + (v * (1.0 + (u_channelShift / 2.0))), in_uv.y)).b;
float a = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).a;
out_color = vec4(r, g, b, a);
}

View File

@ -4,49 +4,10 @@
*/
import seedrandom from 'seedrandom';
import shader from './blockNoise.glsl';
import { defineImageEffectorFx } from '../ImageEffector.js';
import { i18n } from '@/i18n.js';
const shader = `#version 300 es
precision mediump float;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform int u_amount;
uniform float u_shiftStrengths[128];
uniform vec2 u_shiftOrigins[128];
uniform vec2 u_shiftSizes[128];
uniform float u_channelShift;
out vec4 out_color;
void main() {
// TODO: ピクセル毎に計算する必要はないのでuniformにする
float aspect_ratio = min(in_resolution.x, in_resolution.y) / max(in_resolution.x, in_resolution.y);
float aspect_ratio_x = in_resolution.x > in_resolution.y ? 1.0 : aspect_ratio;
float aspect_ratio_y = in_resolution.x < in_resolution.y ? 1.0 : aspect_ratio;
float v = 0.0;
for (int i = 0; i < u_amount; i++) {
if (
in_uv.x * aspect_ratio_x > ((u_shiftOrigins[i].x * aspect_ratio_x) - u_shiftSizes[i].x) &&
in_uv.x * aspect_ratio_x < ((u_shiftOrigins[i].x * aspect_ratio_x) + u_shiftSizes[i].x) &&
in_uv.y * aspect_ratio_y > ((u_shiftOrigins[i].y * aspect_ratio_y) - u_shiftSizes[i].y) &&
in_uv.y * aspect_ratio_y < ((u_shiftOrigins[i].y * aspect_ratio_y) + u_shiftSizes[i].y)
) {
v += u_shiftStrengths[i];
}
}
float r = texture(in_texture, vec2(in_uv.x + (v * (1.0 + u_channelShift)), in_uv.y)).r;
float g = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).g;
float b = texture(in_texture, vec2(in_uv.x + (v * (1.0 + (u_channelShift / 2.0))), in_uv.y)).b;
float a = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).a;
out_color = vec4(r, g, b, a);
}
`;
export const FX_blockNoise = defineImageEffectorFx({
id: 'blockNoise',
name: i18n.ts._imageEffector._fxs.glitch + ': ' + i18n.ts._imageEffector._fxs.blockNoise,

View File

@ -0,0 +1,78 @@
#version 300 es
precision mediump float;
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
const float PI = 3.141592653589793;
const float TWO_PI = 6.283185307179586;
const float HALF_PI = 1.5707963267948966;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform vec2 u_offset;
uniform vec2 u_scale;
uniform bool u_ellipse;
uniform float u_angle;
uniform float u_radius;
uniform int u_samples;
out vec4 out_color;
void main() {
float angle = -(u_angle * PI);
vec2 centeredUv = in_uv - vec2(0.5, 0.5) - u_offset;
vec2 rotatedUV = vec2(
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
) + u_offset;
bool isInside = false;
if (u_ellipse) {
vec2 norm = (rotatedUV - u_offset) / u_scale;
isInside = dot(norm, norm) <= 1.0;
} else {
isInside = rotatedUV.x > u_offset.x - u_scale.x && rotatedUV.x < u_offset.x + u_scale.x && rotatedUV.y > u_offset.y - u_scale.y && rotatedUV.y < u_offset.y + u_scale.y;
}
if (!isInside) {
out_color = texture(in_texture, in_uv);
return;
}
vec4 result = vec4(0.0);
float totalSamples = 0.0;
// Make blur radius resolution-independent by using a percentage of image size
// This ensures consistent visual blur regardless of image resolution
float referenceSize = min(in_resolution.x, in_resolution.y);
float normalizedRadius = u_radius / 100.0; // Convert radius to percentage (0-15 -> 0-0.15)
vec2 blurOffset = vec2(normalizedRadius) / in_resolution * referenceSize;
// Calculate how many samples to take in each direction
// This determines the grid density, not the blur extent
int sampleRadius = int(sqrt(float(u_samples)) / 2.0);
// Sample in a grid pattern within the specified radius
for (int x = -sampleRadius; x <= sampleRadius; x++) {
for (int y = -sampleRadius; y <= sampleRadius; y++) {
// Normalize the grid position to [-1, 1] range
float normalizedX = float(x) / float(sampleRadius);
float normalizedY = float(y) / float(sampleRadius);
// Scale by radius to get the actual sampling offset
vec2 offset = vec2(normalizedX, normalizedY) * blurOffset;
vec2 sampleUV = in_uv + offset;
// Only sample if within texture bounds
if (sampleUV.x >= 0.0 && sampleUV.x <= 1.0 && sampleUV.y >= 0.0 && sampleUV.y <= 1.0) {
result += texture(in_texture, sampleUV);
totalSamples += 1.0;
}
}
}
out_color = totalSamples > 0.0 ? result / totalSamples : texture(in_texture, in_uv);
}

View File

@ -4,83 +4,9 @@
*/
import { defineImageEffectorFx } from '../ImageEffector.js';
import shader from './blur.glsl';
import { i18n } from '@/i18n.js';
const shader = `#version 300 es
precision mediump float;
const float PI = 3.141592653589793;
const float TWO_PI = 6.283185307179586;
const float HALF_PI = 1.5707963267948966;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform vec2 u_offset;
uniform vec2 u_scale;
uniform bool u_ellipse;
uniform float u_angle;
uniform float u_radius;
uniform int u_samples;
out vec4 out_color;
void main() {
float angle = -(u_angle * PI);
vec2 centeredUv = in_uv - vec2(0.5, 0.5) - u_offset;
vec2 rotatedUV = vec2(
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
) + u_offset;
bool isInside = false;
if (u_ellipse) {
vec2 norm = (rotatedUV - u_offset) / u_scale;
isInside = dot(norm, norm) <= 1.0;
} else {
isInside = rotatedUV.x > u_offset.x - u_scale.x && rotatedUV.x < u_offset.x + u_scale.x && rotatedUV.y > u_offset.y - u_scale.y && rotatedUV.y < u_offset.y + u_scale.y;
}
if (!isInside) {
out_color = texture(in_texture, in_uv);
return;
}
vec4 result = vec4(0.0);
float totalSamples = 0.0;
// Make blur radius resolution-independent by using a percentage of image size
// This ensures consistent visual blur regardless of image resolution
float referenceSize = min(in_resolution.x, in_resolution.y);
float normalizedRadius = u_radius / 100.0; // Convert radius to percentage (0-15 -> 0-0.15)
vec2 blurOffset = vec2(normalizedRadius) / in_resolution * referenceSize;
// Calculate how many samples to take in each direction
// This determines the grid density, not the blur extent
int sampleRadius = int(sqrt(float(u_samples)) / 2.0);
// Sample in a grid pattern within the specified radius
for (int x = -sampleRadius; x <= sampleRadius; x++) {
for (int y = -sampleRadius; y <= sampleRadius; y++) {
// Normalize the grid position to [-1, 1] range
float normalizedX = float(x) / float(sampleRadius);
float normalizedY = float(y) / float(sampleRadius);
// Scale by radius to get the actual sampling offset
vec2 offset = vec2(normalizedX, normalizedY) * blurOffset;
vec2 sampleUV = in_uv + offset;
// Only sample if within texture bounds
if (sampleUV.x >= 0.0 && sampleUV.x <= 1.0 && sampleUV.y >= 0.0 && sampleUV.y <= 1.0) {
result += texture(in_texture, sampleUV);
totalSamples += 1.0;
}
}
}
out_color = totalSamples > 0.0 ? result / totalSamples : texture(in_texture, in_uv);
}
`;
export const FX_blur = defineImageEffectorFx({
id: 'blur',
name: i18n.ts._imageEffector._fxs.blur,

View File

@ -0,0 +1,43 @@
#version 300 es
precision mediump float;
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
const float PI = 3.141592653589793;
const float TWO_PI = 6.283185307179586;
const float HALF_PI = 1.5707963267948966;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform float u_angle;
uniform float u_scale;
uniform vec3 u_color;
uniform float u_opacity;
out vec4 out_color;
void main() {
vec4 in_color = texture(in_texture, in_uv);
float x_ratio = max(in_resolution.x / in_resolution.y, 1.0);
float y_ratio = max(in_resolution.y / in_resolution.x, 1.0);
float angle = -(u_angle * PI);
vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio);
vec2 rotatedUV = vec2(
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
);
float fmodResult = mod(floor(u_scale * rotatedUV.x) + floor(u_scale * rotatedUV.y), 2.0);
float fin = max(sign(fmodResult), 0.0);
out_color = vec4(
mix(in_color.r, u_color.r, fin * u_opacity),
mix(in_color.g, u_color.g, fin * u_opacity),
mix(in_color.b, u_color.b, fin * u_opacity),
in_color.a
);
}

View File

@ -4,48 +4,9 @@
*/
import { defineImageEffectorFx } from '../ImageEffector.js';
import shader from './checker.glsl';
import { i18n } from '@/i18n.js';
const shader = `#version 300 es
precision mediump float;
const float PI = 3.141592653589793;
const float TWO_PI = 6.283185307179586;
const float HALF_PI = 1.5707963267948966;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform float u_angle;
uniform float u_scale;
uniform vec3 u_color;
uniform float u_opacity;
out vec4 out_color;
void main() {
vec4 in_color = texture(in_texture, in_uv);
float x_ratio = max(in_resolution.x / in_resolution.y, 1.0);
float y_ratio = max(in_resolution.y / in_resolution.x, 1.0);
float angle = -(u_angle * PI);
vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio);
vec2 rotatedUV = vec2(
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
);
float fmodResult = mod(floor(u_scale * rotatedUV.x) + floor(u_scale * rotatedUV.y), 2.0);
float fin = max(sign(fmodResult), 0.0);
out_color = vec4(
mix(in_color.r, u_color.r, fin * u_opacity),
mix(in_color.g, u_color.g, fin * u_opacity),
mix(in_color.b, u_color.b, fin * u_opacity),
in_color.a
);
}
`;
export const FX_checker = defineImageEffectorFx({
id: 'checker',
name: i18n.ts._imageEffector._fxs.checker,

View File

@ -0,0 +1,49 @@
#version 300 es
precision mediump float;
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
out vec4 out_color;
uniform float u_amount;
uniform float u_start;
uniform bool u_normalize;
void main() {
int samples = 64;
float r_strength = 1.0;
float g_strength = 1.5;
float b_strength = 2.0;
vec2 size = vec2(in_resolution.x, in_resolution.y);
vec4 accumulator = vec4(0.0);
float normalisedValue = length((in_uv - 0.5) * 2.0);
float strength = clamp((normalisedValue - u_start) * (1.0 / (1.0 - u_start)), 0.0, 1.0);
vec2 vector = (u_normalize ? normalize(in_uv - vec2(0.5)) : in_uv - vec2(0.5));
vec2 velocity = vector * strength * u_amount;
vec2 rOffset = -vector * strength * (u_amount * r_strength);
vec2 gOffset = -vector * strength * (u_amount * g_strength);
vec2 bOffset = -vector * strength * (u_amount * b_strength);
for (int i = 0; i < samples; i++) {
accumulator.r += texture(in_texture, in_uv + rOffset).r;
rOffset -= velocity / float(samples);
accumulator.g += texture(in_texture, in_uv + gOffset).g;
gOffset -= velocity / float(samples);
accumulator.b += texture(in_texture, in_uv + bOffset).b;
bOffset -= velocity / float(samples);
}
out_color = vec4(vec3(accumulator / float(samples)), 1.0);
}

View File

@ -4,53 +4,9 @@
*/
import { defineImageEffectorFx } from '../ImageEffector.js';
import shader from './chromaticAberration.glsl';
import { i18n } from '@/i18n.js';
const shader = `#version 300 es
precision mediump float;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
out vec4 out_color;
uniform float u_amount;
uniform float u_start;
uniform bool u_normalize;
void main() {
int samples = 64;
float r_strength = 1.0;
float g_strength = 1.5;
float b_strength = 2.0;
vec2 size = vec2(in_resolution.x, in_resolution.y);
vec4 accumulator = vec4(0.0);
float normalisedValue = length((in_uv - 0.5) * 2.0);
float strength = clamp((normalisedValue - u_start) * (1.0 / (1.0 - u_start)), 0.0, 1.0);
vec2 vector = (u_normalize ? normalize(in_uv - vec2(0.5)) : in_uv - vec2(0.5));
vec2 velocity = vector * strength * u_amount;
vec2 rOffset = -vector * strength * (u_amount * r_strength);
vec2 gOffset = -vector * strength * (u_amount * g_strength);
vec2 bOffset = -vector * strength * (u_amount * b_strength);
for (int i = 0; i < samples; i++) {
accumulator.r += texture(in_texture, in_uv + rOffset).r;
rOffset -= velocity / float(samples);
accumulator.g += texture(in_texture, in_uv + gOffset).g;
gOffset -= velocity / float(samples);
accumulator.b += texture(in_texture, in_uv + bOffset).b;
bOffset -= velocity / float(samples);
}
out_color = vec4(vec3(accumulator / float(samples)), 1.0);
}
`;
export const FX_chromaticAberration = defineImageEffectorFx({
id: 'chromaticAberration',
name: i18n.ts._imageEffector._fxs.chromaticAberration,

View File

@ -0,0 +1,82 @@
#version 300 es
precision mediump float;
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform float u_brightness;
uniform float u_contrast;
uniform float u_hue;
uniform float u_lightness;
uniform float u_saturation;
out vec4 out_color;
// RGB to HSL
vec3 rgb2hsl(vec3 c) {
float maxc = max(max(c.r, c.g), c.b);
float minc = min(min(c.r, c.g), c.b);
float l = (maxc + minc) * 0.5;
float s = 0.0;
float h = 0.0;
if (maxc != minc) {
float d = maxc - minc;
s = l > 0.5 ? d / (2.0 - maxc - minc) : d / (maxc + minc);
if (maxc == c.r) {
h = (c.g - c.b) / d + (c.g < c.b ? 6.0 : 0.0);
} else if (maxc == c.g) {
h = (c.b - c.r) / d + 2.0;
} else {
h = (c.r - c.g) / d + 4.0;
}
h /= 6.0;
}
return vec3(h, s, l);
}
// HSL to RGB
float hue2rgb(float p, float q, float t) {
if (t < 0.0) t += 1.0;
if (t > 1.0) t -= 1.0;
if (t < 1.0/6.0) return p + (q - p) * 6.0 * t;
if (t < 1.0/2.0) return q;
if (t < 2.0/3.0) return p + (q - p) * (2.0/3.0 - t) * 6.0;
return p;
}
vec3 hsl2rgb(vec3 hsl) {
float r, g, b;
float h = hsl.x;
float s = hsl.y;
float l = hsl.z;
if (s == 0.0) {
r = g = b = l;
} else {
float q = l < 0.5 ? l * (1.0 + s) : l + s - l * s;
float p = 2.0 * l - q;
r = hue2rgb(p, q, h + 1.0/3.0);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1.0/3.0);
}
return vec3(r, g, b);
}
void main() {
vec4 in_color = texture(in_texture, in_uv);
vec3 color = in_color.rgb;
color = color * u_brightness;
color += vec3(u_lightness);
color = (color - 0.5) * u_contrast + 0.5;
vec3 hsl = rgb2hsl(color);
hsl.x = mod(hsl.x + u_hue, 1.0);
hsl.y = clamp(hsl.y * u_saturation, 0.0, 1.0);
color = hsl2rgb(hsl);
out_color = vec4(color, in_color.a);
}

View File

@ -4,86 +4,9 @@
*/
import { defineImageEffectorFx } from '../ImageEffector.js';
import shader from './colorAdjust.glsl';
import { i18n } from '@/i18n.js';
const shader = `#version 300 es
precision mediump float;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform float u_brightness;
uniform float u_contrast;
uniform float u_hue;
uniform float u_lightness;
uniform float u_saturation;
out vec4 out_color;
// RGB to HSL
vec3 rgb2hsl(vec3 c) {
float maxc = max(max(c.r, c.g), c.b);
float minc = min(min(c.r, c.g), c.b);
float l = (maxc + minc) * 0.5;
float s = 0.0;
float h = 0.0;
if (maxc != minc) {
float d = maxc - minc;
s = l > 0.5 ? d / (2.0 - maxc - minc) : d / (maxc + minc);
if (maxc == c.r) {
h = (c.g - c.b) / d + (c.g < c.b ? 6.0 : 0.0);
} else if (maxc == c.g) {
h = (c.b - c.r) / d + 2.0;
} else {
h = (c.r - c.g) / d + 4.0;
}
h /= 6.0;
}
return vec3(h, s, l);
}
// HSL to RGB
float hue2rgb(float p, float q, float t) {
if (t < 0.0) t += 1.0;
if (t > 1.0) t -= 1.0;
if (t < 1.0/6.0) return p + (q - p) * 6.0 * t;
if (t < 1.0/2.0) return q;
if (t < 2.0/3.0) return p + (q - p) * (2.0/3.0 - t) * 6.0;
return p;
}
vec3 hsl2rgb(vec3 hsl) {
float r, g, b;
float h = hsl.x;
float s = hsl.y;
float l = hsl.z;
if (s == 0.0) {
r = g = b = l;
} else {
float q = l < 0.5 ? l * (1.0 + s) : l + s - l * s;
float p = 2.0 * l - q;
r = hue2rgb(p, q, h + 1.0/3.0);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1.0/3.0);
}
return vec3(r, g, b);
}
void main() {
vec4 in_color = texture(in_texture, in_uv);
vec3 color = in_color.rgb;
color = color * u_brightness;
color += vec3(u_lightness);
color = (color - 0.5) * u_contrast + 0.5;
vec3 hsl = rgb2hsl(color);
hsl.x = mod(hsl.x + u_hue, 1.0);
hsl.y = clamp(hsl.y * u_saturation, 0.0, 1.0);
color = hsl2rgb(hsl);
out_color = vec4(color, in_color.a);
}
`;
export const FX_colorAdjust = defineImageEffectorFx({
id: 'colorAdjust',
name: i18n.ts._imageEffector._fxs.colorAdjust,

View File

@ -0,0 +1,29 @@
#version 300 es
precision mediump float;
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
// colorClamp, colorClampAdvanced共通
// colorClampではmax, minがすべて同じ値となる
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform float u_rMax;
uniform float u_rMin;
uniform float u_gMax;
uniform float u_gMin;
uniform float u_bMax;
uniform float u_bMin;
out vec4 out_color;
void main() {
vec4 in_color = texture(in_texture, in_uv);
float r = min(max(in_color.r, u_rMin), u_rMax);
float g = min(max(in_color.g, u_gMin), u_gMax);
float b = min(max(in_color.b, u_bMin), u_bMax);
out_color = vec4(r, g, b, in_color.a);
}

View File

@ -4,32 +4,14 @@
*/
import { defineImageEffectorFx } from '../ImageEffector.js';
import shader from './colorClamp.glsl';
import { i18n } from '@/i18n.js';
const shader = `#version 300 es
precision mediump float;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform float u_max;
uniform float u_min;
out vec4 out_color;
void main() {
vec4 in_color = texture(in_texture, in_uv);
float r = min(max(in_color.r, u_min), u_max);
float g = min(max(in_color.g, u_min), u_max);
float b = min(max(in_color.b, u_min), u_max);
out_color = vec4(r, g, b, in_color.a);
}
`;
export const FX_colorClamp = defineImageEffectorFx({
id: 'colorClamp',
name: i18n.ts._imageEffector._fxs.colorClamp,
shader,
uniforms: ['max', 'min'] as const,
uniforms: ['rMax', 'rMin', 'gMax', 'gMin', 'bMax', 'bMin'] as const,
params: {
max: {
label: i18n.ts._imageEffector._fxProps.max,
@ -51,7 +33,11 @@ export const FX_colorClamp = defineImageEffectorFx({
},
},
main: ({ gl, u, params }) => {
gl.uniform1f(u.max, params.max);
gl.uniform1f(u.min, 1.0 + params.min);
gl.uniform1f(u.rMax, params.max);
gl.uniform1f(u.rMin, 1.0 + params.min);
gl.uniform1f(u.gMax, params.max);
gl.uniform1f(u.gMin, 1.0 + params.min);
gl.uniform1f(u.bMax, params.max);
gl.uniform1f(u.bMin, 1.0 + params.min);
},
});

View File

@ -4,31 +4,9 @@
*/
import { defineImageEffectorFx } from '../ImageEffector.js';
import shader from './colorClamp.glsl';
import { i18n } from '@/i18n.js';
const shader = `#version 300 es
precision mediump float;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform float u_rMax;
uniform float u_rMin;
uniform float u_gMax;
uniform float u_gMin;
uniform float u_bMax;
uniform float u_bMin;
out vec4 out_color;
void main() {
vec4 in_color = texture(in_texture, in_uv);
float r = min(max(in_color.r, u_rMin), u_rMax);
float g = min(max(in_color.g, u_gMin), u_gMax);
float b = min(max(in_color.b, u_bMin), u_bMax);
out_color = vec4(r, g, b, in_color.a);
}
`;
export const FX_colorClampAdvanced = defineImageEffectorFx({
id: 'colorClampAdvanced',
name: i18n.ts._imageEffector._fxs.colorClampAdvanced,

View File

@ -0,0 +1,30 @@
#version 300 es
precision mediump float;
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
const float PI = 3.141592653589793;
const float TWO_PI = 6.283185307179586;
const float HALF_PI = 1.5707963267948966;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform float u_phase;
uniform float u_frequency;
uniform float u_strength;
uniform int u_direction; // 0: vertical, 1: horizontal
out vec4 out_color;
void main() {
float v = u_direction == 0 ?
sin((HALF_PI + (u_phase * PI) - (u_frequency / 2.0)) + in_uv.y * u_frequency) * u_strength :
sin((HALF_PI + (u_phase * PI) - (u_frequency / 2.0)) + in_uv.x * u_frequency) * u_strength;
vec4 in_color = u_direction == 0 ?
texture(in_texture, vec2(in_uv.x + v, in_uv.y)) :
texture(in_texture, vec2(in_uv.x, in_uv.y + v));
out_color = in_color;
}

View File

@ -4,35 +4,9 @@
*/
import { defineImageEffectorFx } from '../ImageEffector.js';
import shader from './distort.glsl';
import { i18n } from '@/i18n.js';
const shader = `#version 300 es
precision mediump float;
const float PI = 3.141592653589793;
const float TWO_PI = 6.283185307179586;
const float HALF_PI = 1.5707963267948966;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform float u_phase;
uniform float u_frequency;
uniform float u_strength;
uniform int u_direction; // 0: vertical, 1: horizontal
out vec4 out_color;
void main() {
float v = u_direction == 0 ?
sin((HALF_PI + (u_phase * PI) - (u_frequency / 2.0)) + in_uv.y * u_frequency) * u_strength :
sin((HALF_PI + (u_phase * PI) - (u_frequency / 2.0)) + in_uv.x * u_frequency) * u_strength;
vec4 in_color = u_direction == 0 ?
texture(in_texture, vec2(in_uv.x + v, in_uv.y)) :
texture(in_texture, vec2(in_uv.x, in_uv.y + v));
out_color = in_color;
}
`;
export const FX_distort = defineImageEffectorFx({
id: 'distort',
name: i18n.ts._imageEffector._fxs.distort,

View File

@ -0,0 +1,50 @@
#version 300 es
precision mediump float;
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
const float PI = 3.141592653589793;
const float TWO_PI = 6.283185307179586;
const float HALF_PI = 1.5707963267948966;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform vec2 u_offset;
uniform vec2 u_scale;
uniform bool u_ellipse;
uniform float u_angle;
uniform vec3 u_color;
uniform float u_opacity;
out vec4 out_color;
void main() {
vec4 in_color = texture(in_texture, in_uv);
//float x_ratio = max(in_resolution.x / in_resolution.y, 1.0);
//float y_ratio = max(in_resolution.y / in_resolution.x, 1.0);
float angle = -(u_angle * PI);
vec2 centeredUv = in_uv - vec2(0.5, 0.5) - u_offset;
vec2 rotatedUV = vec2(
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
) + u_offset;
bool isInside = false;
if (u_ellipse) {
vec2 norm = (rotatedUV - u_offset) / u_scale;
isInside = dot(norm, norm) <= 1.0;
} else {
isInside = rotatedUV.x > u_offset.x - u_scale.x && rotatedUV.x < u_offset.x + u_scale.x && rotatedUV.y > u_offset.y - u_scale.y && rotatedUV.y < u_offset.y + u_scale.y;
}
out_color = isInside ? vec4(
mix(in_color.r, u_color.r, u_opacity),
mix(in_color.g, u_color.g, u_opacity),
mix(in_color.b, u_color.b, u_opacity),
in_color.a
) : in_color;
}

View File

@ -4,55 +4,9 @@
*/
import { defineImageEffectorFx } from '../ImageEffector.js';
import shader from './fill.glsl';
import { i18n } from '@/i18n.js';
const shader = `#version 300 es
precision mediump float;
const float PI = 3.141592653589793;
const float TWO_PI = 6.283185307179586;
const float HALF_PI = 1.5707963267948966;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform vec2 u_offset;
uniform vec2 u_scale;
uniform bool u_ellipse;
uniform float u_angle;
uniform vec3 u_color;
uniform float u_opacity;
out vec4 out_color;
void main() {
vec4 in_color = texture(in_texture, in_uv);
//float x_ratio = max(in_resolution.x / in_resolution.y, 1.0);
//float y_ratio = max(in_resolution.y / in_resolution.x, 1.0);
float angle = -(u_angle * PI);
vec2 centeredUv = in_uv - vec2(0.5, 0.5) - u_offset;
vec2 rotatedUV = vec2(
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
) + u_offset;
bool isInside = false;
if (u_ellipse) {
vec2 norm = (rotatedUV - u_offset) / u_scale;
isInside = dot(norm, norm) <= 1.0;
} else {
isInside = rotatedUV.x > u_offset.x - u_scale.x && rotatedUV.x < u_offset.x + u_scale.x && rotatedUV.y > u_offset.y - u_scale.y && rotatedUV.y < u_offset.y + u_scale.y;
}
out_color = isInside ? vec4(
mix(in_color.r, u_color.r, u_opacity),
mix(in_color.g, u_color.g, u_opacity),
mix(in_color.b, u_color.b, u_opacity),
in_color.a
) : in_color;
}
`;
export const FX_fill = defineImageEffectorFx({
id: 'fill',
name: i18n.ts._imageEffector._fxs.fill,

View File

@ -0,0 +1,22 @@
#version 300 es
precision mediump float;
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
out vec4 out_color;
float getBrightness(vec4 color) {
return (color.r + color.g + color.b) / 3.0;
}
void main() {
vec4 in_color = texture(in_texture, in_uv);
float brightness = getBrightness(in_color);
out_color = vec4(brightness, brightness, brightness, in_color.a);
}

View File

@ -4,27 +4,9 @@
*/
import { defineImageEffectorFx } from '../ImageEffector.js';
import shader from './grayscale.glsl';
import { i18n } from '@/i18n.js';
const shader = `#version 300 es
precision mediump float;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
out vec4 out_color;
float getBrightness(vec4 color) {
return (color.r + color.g + color.b) / 3.0;
}
void main() {
vec4 in_color = texture(in_texture, in_uv);
float brightness = getBrightness(in_color);
out_color = vec4(brightness, brightness, brightness, in_color.a);
}
`;
export const FX_grayscale = defineImageEffectorFx({
id: 'grayscale',
name: i18n.ts._imageEffector._fxs.grayscale,

View File

@ -0,0 +1,23 @@
#version 300 es
precision mediump float;
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform bool u_r;
uniform bool u_g;
uniform bool u_b;
out vec4 out_color;
void main() {
vec4 in_color = texture(in_texture, in_uv);
out_color.r = u_r ? 1.0 - in_color.r : in_color.r;
out_color.g = u_g ? 1.0 - in_color.g : in_color.g;
out_color.b = u_b ? 1.0 - in_color.b : in_color.b;
out_color.a = in_color.a;
}

View File

@ -4,28 +4,9 @@
*/
import { defineImageEffectorFx } from '../ImageEffector.js';
import shader from './invert.glsl';
import { i18n } from '@/i18n.js';
const shader = `#version 300 es
precision mediump float;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform bool u_r;
uniform bool u_g;
uniform bool u_b;
out vec4 out_color;
void main() {
vec4 in_color = texture(in_texture, in_uv);
out_color.r = u_r ? 1.0 - in_color.r : in_color.r;
out_color.g = u_g ? 1.0 - in_color.g : in_color.g;
out_color.b = u_b ? 1.0 - in_color.b : in_color.b;
out_color.a = in_color.a;
}
`;
export const FX_invert = defineImageEffectorFx({
id: 'invert',
name: i18n.ts._imageEffector._fxs.invert,

View File

@ -0,0 +1,26 @@
#version 300 es
precision mediump float;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform int u_h;
uniform int u_v;
out vec4 out_color;
void main() {
vec2 uv = in_uv;
if (u_h == -1 && in_uv.x > 0.5) {
uv.x = 1.0 - uv.x;
}
if (u_h == 1 && in_uv.x < 0.5) {
uv.x = 1.0 - uv.x;
}
if (u_v == -1 && in_uv.y > 0.5) {
uv.y = 1.0 - uv.y;
}
if (u_v == 1 && in_uv.y < 0.5) {
uv.y = 1.0 - uv.y;
}
out_color = texture(in_texture, uv);
}

View File

@ -4,36 +4,9 @@
*/
import { defineImageEffectorFx } from '../ImageEffector.js';
import shader from './mirror.glsl';
import { i18n } from '@/i18n.js';
const shader = `#version 300 es
precision mediump float;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform int u_h;
uniform int u_v;
out vec4 out_color;
void main() {
vec2 uv = in_uv;
if (u_h == -1 && in_uv.x > 0.5) {
uv.x = 1.0 - uv.x;
}
if (u_h == 1 && in_uv.x < 0.5) {
uv.x = 1.0 - uv.x;
}
if (u_v == -1 && in_uv.y > 0.5) {
uv.y = 1.0 - uv.y;
}
if (u_v == 1 && in_uv.y < 0.5) {
uv.y = 1.0 - uv.y;
}
out_color = texture(in_texture, uv);
}
`;
export const FX_mirror = defineImageEffectorFx({
id: 'mirror',
name: i18n.ts._imageEffector._fxs.mirror,

View File

@ -0,0 +1,68 @@
#version 300 es
precision mediump float;
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
const float PI = 3.141592653589793;
const float TWO_PI = 6.283185307179586;
const float HALF_PI = 1.5707963267948966;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform vec2 u_offset;
uniform vec2 u_scale;
uniform bool u_ellipse;
uniform float u_angle;
uniform int u_samples;
uniform float u_strength;
out vec4 out_color;
// TODO: pixelateの中心を画像中心ではなく範囲の中心にする
// TODO: 画像のアスペクト比に関わらず各画素は正方形にする
void main() {
if (u_strength <= 0.0) {
out_color = texture(in_texture, in_uv);
return;
}
float angle = -(u_angle * PI);
vec2 centeredUv = in_uv - vec2(0.5, 0.5) - u_offset;
vec2 rotatedUV = vec2(
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
) + u_offset;
bool isInside = false;
if (u_ellipse) {
vec2 norm = (rotatedUV - u_offset) / u_scale;
isInside = dot(norm, norm) <= 1.0;
} else {
isInside = rotatedUV.x > u_offset.x - u_scale.x && rotatedUV.x < u_offset.x + u_scale.x && rotatedUV.y > u_offset.y - u_scale.y && rotatedUV.y < u_offset.y + u_scale.y;
}
if (!isInside) {
out_color = texture(in_texture, in_uv);
return;
}
float dx = u_strength / 1.0;
float dy = u_strength / 1.0;
vec2 new_uv = vec2(
(dx * (floor((in_uv.x - 0.5 - (dx / 2.0)) / dx) + 0.5)),
(dy * (floor((in_uv.y - 0.5 - (dy / 2.0)) / dy) + 0.5))
) + vec2(0.5 + (dx / 2.0), 0.5 + (dy / 2.0));
vec4 result = vec4(0.0);
float totalSamples = 0.0;
// TODO: より多くのサンプリング
result += texture(in_texture, new_uv);
totalSamples += 1.0;
out_color = totalSamples > 0.0 ? result / totalSamples : texture(in_texture, in_uv);
}

View File

@ -4,73 +4,9 @@
*/
import { defineImageEffectorFx } from '../ImageEffector.js';
import shader from './pixelate.glsl';
import { i18n } from '@/i18n.js';
const shader = `#version 300 es
precision mediump float;
const float PI = 3.141592653589793;
const float TWO_PI = 6.283185307179586;
const float HALF_PI = 1.5707963267948966;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform vec2 u_offset;
uniform vec2 u_scale;
uniform bool u_ellipse;
uniform float u_angle;
uniform int u_samples;
uniform float u_strength;
out vec4 out_color;
// TODO: pixelateの中心を画像中心ではなく範囲の中心にする
// TODO: 画像のアスペクト比に関わらず各画素は正方形にする
void main() {
if (u_strength <= 0.0) {
out_color = texture(in_texture, in_uv);
return;
}
float angle = -(u_angle * PI);
vec2 centeredUv = in_uv - vec2(0.5, 0.5) - u_offset;
vec2 rotatedUV = vec2(
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
) + u_offset;
bool isInside = false;
if (u_ellipse) {
vec2 norm = (rotatedUV - u_offset) / u_scale;
isInside = dot(norm, norm) <= 1.0;
} else {
isInside = rotatedUV.x > u_offset.x - u_scale.x && rotatedUV.x < u_offset.x + u_scale.x && rotatedUV.y > u_offset.y - u_scale.y && rotatedUV.y < u_offset.y + u_scale.y;
}
if (!isInside) {
out_color = texture(in_texture, in_uv);
return;
}
float dx = u_strength / 1.0;
float dy = u_strength / 1.0;
vec2 new_uv = vec2(
(dx * (floor((in_uv.x - 0.5 - (dx / 2.0)) / dx) + 0.5)),
(dy * (floor((in_uv.y - 0.5 - (dy / 2.0)) / dy) + 0.5))
) + vec2(0.5 + (dx / 2.0), 0.5 + (dy / 2.0));
vec4 result = vec4(0.0);
float totalSamples = 0.0;
// TODO: より多くのサンプリング
result += texture(in_texture, new_uv);
totalSamples += 1.0;
out_color = totalSamples > 0.0 ? result / totalSamples : texture(in_texture, in_uv);
}
`;
export const FX_pixelate = defineImageEffectorFx({
id: 'pixelate',
name: i18n.ts._imageEffector._fxs.pixelate,

View File

@ -0,0 +1,75 @@
#version 300 es
precision mediump float;
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
const float PI = 3.141592653589793;
const float TWO_PI = 6.283185307179586;
const float HALF_PI = 1.5707963267948966;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform float u_angle;
uniform float u_scale;
uniform float u_major_radius;
uniform float u_major_opacity;
uniform float u_minor_divisions;
uniform float u_minor_radius;
uniform float u_minor_opacity;
uniform vec3 u_color;
out vec4 out_color;
void main() {
vec4 in_color = texture(in_texture, in_uv);
float x_ratio = max(in_resolution.x / in_resolution.y, 1.0);
float y_ratio = max(in_resolution.y / in_resolution.x, 1.0);
float angle = -(u_angle * PI);
vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio);
vec2 rotatedUV = vec2(
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
);
float major_modX = mod(rotatedUV.x, (1.0 / u_scale));
float major_modY = mod(rotatedUV.y, (1.0 / u_scale));
float major_threshold = ((u_major_radius / 2.0) / u_scale);
if (
length(vec2(major_modX, major_modY)) < major_threshold ||
length(vec2((1.0 / u_scale) - major_modX, major_modY)) < major_threshold ||
length(vec2(major_modX, (1.0 / u_scale) - major_modY)) < major_threshold ||
length(vec2((1.0 / u_scale) - major_modX, (1.0 / u_scale) - major_modY)) < major_threshold
) {
out_color = vec4(
mix(in_color.r, u_color.r, u_major_opacity),
mix(in_color.g, u_color.g, u_major_opacity),
mix(in_color.b, u_color.b, u_major_opacity),
in_color.a
);
return;
}
float minor_modX = mod(rotatedUV.x, (1.0 / u_scale / u_minor_divisions));
float minor_modY = mod(rotatedUV.y, (1.0 / u_scale / u_minor_divisions));
float minor_threshold = ((u_minor_radius / 2.0) / (u_minor_divisions * u_scale));
if (
length(vec2(minor_modX, minor_modY)) < minor_threshold ||
length(vec2((1.0 / u_scale / u_minor_divisions) - minor_modX, minor_modY)) < minor_threshold ||
length(vec2(minor_modX, (1.0 / u_scale / u_minor_divisions) - minor_modY)) < minor_threshold ||
length(vec2((1.0 / u_scale / u_minor_divisions) - minor_modX, (1.0 / u_scale / u_minor_divisions) - minor_modY)) < minor_threshold
) {
out_color = vec4(
mix(in_color.r, u_color.r, u_minor_opacity),
mix(in_color.g, u_color.g, u_minor_opacity),
mix(in_color.b, u_color.b, u_minor_opacity),
in_color.a
);
return;
}
out_color = in_color;
}

View File

@ -4,80 +4,9 @@
*/
import { defineImageEffectorFx } from '../ImageEffector.js';
import shader from './polkadot.glsl';
import { i18n } from '@/i18n.js';
const shader = `#version 300 es
precision mediump float;
const float PI = 3.141592653589793;
const float TWO_PI = 6.283185307179586;
const float HALF_PI = 1.5707963267948966;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform float u_angle;
uniform float u_scale;
uniform float u_major_radius;
uniform float u_major_opacity;
uniform float u_minor_divisions;
uniform float u_minor_radius;
uniform float u_minor_opacity;
uniform vec3 u_color;
out vec4 out_color;
void main() {
vec4 in_color = texture(in_texture, in_uv);
float x_ratio = max(in_resolution.x / in_resolution.y, 1.0);
float y_ratio = max(in_resolution.y / in_resolution.x, 1.0);
float angle = -(u_angle * PI);
vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio);
vec2 rotatedUV = vec2(
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
);
float major_modX = mod(rotatedUV.x, (1.0 / u_scale));
float major_modY = mod(rotatedUV.y, (1.0 / u_scale));
float major_threshold = ((u_major_radius / 2.0) / u_scale);
if (
length(vec2(major_modX, major_modY)) < major_threshold ||
length(vec2((1.0 / u_scale) - major_modX, major_modY)) < major_threshold ||
length(vec2(major_modX, (1.0 / u_scale) - major_modY)) < major_threshold ||
length(vec2((1.0 / u_scale) - major_modX, (1.0 / u_scale) - major_modY)) < major_threshold
) {
out_color = vec4(
mix(in_color.r, u_color.r, u_major_opacity),
mix(in_color.g, u_color.g, u_major_opacity),
mix(in_color.b, u_color.b, u_major_opacity),
in_color.a
);
return;
}
float minor_modX = mod(rotatedUV.x, (1.0 / u_scale / u_minor_divisions));
float minor_modY = mod(rotatedUV.y, (1.0 / u_scale / u_minor_divisions));
float minor_threshold = ((u_minor_radius / 2.0) / (u_minor_divisions * u_scale));
if (
length(vec2(minor_modX, minor_modY)) < minor_threshold ||
length(vec2((1.0 / u_scale / u_minor_divisions) - minor_modX, minor_modY)) < minor_threshold ||
length(vec2(minor_modX, (1.0 / u_scale / u_minor_divisions) - minor_modY)) < minor_threshold ||
length(vec2((1.0 / u_scale / u_minor_divisions) - minor_modX, (1.0 / u_scale / u_minor_divisions) - minor_modY)) < minor_threshold
) {
out_color = vec4(
mix(in_color.r, u_color.r, u_minor_opacity),
mix(in_color.g, u_color.g, u_minor_opacity),
mix(in_color.b, u_color.b, u_minor_opacity),
in_color.a
);
return;
}
out_color = in_color;
}
`;
// Primarily used for watermark
export const FX_polkadot = defineImageEffectorFx({
id: 'polkadot',

View File

@ -0,0 +1,45 @@
#version 300 es
precision mediump float;
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
const float PI = 3.141592653589793;
const float TWO_PI = 6.283185307179586;
const float HALF_PI = 1.5707963267948966;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform float u_angle;
uniform float u_frequency;
uniform float u_phase;
uniform float u_threshold;
uniform vec3 u_color;
uniform float u_opacity;
out vec4 out_color;
void main() {
vec4 in_color = texture(in_texture, in_uv);
float x_ratio = max(in_resolution.x / in_resolution.y, 1.0);
float y_ratio = max(in_resolution.y / in_resolution.x, 1.0);
float angle = -(u_angle * PI);
vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio);
vec2 rotatedUV = vec2(
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
);
float phase = u_phase * TWO_PI;
float value = (1.0 + sin((rotatedUV.x * u_frequency - HALF_PI) + phase)) / 2.0;
value = value < u_threshold ? 1.0 : 0.0;
out_color = vec4(
mix(in_color.r, u_color.r, value * u_opacity),
mix(in_color.g, u_color.g, value * u_opacity),
mix(in_color.b, u_color.b, value * u_opacity),
in_color.a
);
}

View File

@ -4,50 +4,9 @@
*/
import { defineImageEffectorFx } from '../ImageEffector.js';
import shader from './stripe.glsl';
import { i18n } from '@/i18n.js';
const shader = `#version 300 es
precision mediump float;
const float PI = 3.141592653589793;
const float TWO_PI = 6.283185307179586;
const float HALF_PI = 1.5707963267948966;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform float u_angle;
uniform float u_frequency;
uniform float u_phase;
uniform float u_threshold;
uniform vec3 u_color;
uniform float u_opacity;
out vec4 out_color;
void main() {
vec4 in_color = texture(in_texture, in_uv);
float x_ratio = max(in_resolution.x / in_resolution.y, 1.0);
float y_ratio = max(in_resolution.y / in_resolution.x, 1.0);
float angle = -(u_angle * PI);
vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio);
vec2 rotatedUV = vec2(
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
);
float phase = u_phase * TWO_PI;
float value = (1.0 + sin((rotatedUV.x * u_frequency - HALF_PI) + phase)) / 2.0;
value = value < u_threshold ? 1.0 : 0.0;
out_color = vec4(
mix(in_color.r, u_color.r, value * u_opacity),
mix(in_color.g, u_color.g, value * u_opacity),
mix(in_color.b, u_color.b, value * u_opacity),
in_color.a
);
}
`;
// Primarily used for watermark
export const FX_stripe = defineImageEffectorFx({
id: 'stripe',

View File

@ -0,0 +1,33 @@
#version 300 es
precision mediump float;
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform int u_amount;
uniform float u_shiftStrengths[128];
uniform float u_shiftOrigins[128];
uniform float u_shiftHeights[128];
uniform float u_channelShift;
out vec4 out_color;
void main() {
float v = 0.0;
for (int i = 0; i < u_amount; i++) {
if (in_uv.y > (u_shiftOrigins[i] - u_shiftHeights[i]) && in_uv.y < (u_shiftOrigins[i] + u_shiftHeights[i])) {
v += u_shiftStrengths[i];
}
}
float r = texture(in_texture, vec2(in_uv.x + (v * (1.0 + u_channelShift)), in_uv.y)).r;
float g = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).g;
float b = texture(in_texture, vec2(in_uv.x + (v * (1.0 + (u_channelShift / 2.0))), in_uv.y)).b;
float a = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).a;
out_color = vec4(r, g, b, a);
}

View File

@ -4,39 +4,10 @@
*/
import seedrandom from 'seedrandom';
import shader from './tearing.glsl';
import { defineImageEffectorFx } from '../ImageEffector.js';
import { i18n } from '@/i18n.js';
const shader = `#version 300 es
precision mediump float;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform int u_amount;
uniform float u_shiftStrengths[128];
uniform float u_shiftOrigins[128];
uniform float u_shiftHeights[128];
uniform float u_channelShift;
out vec4 out_color;
void main() {
float v = 0.0;
for (int i = 0; i < u_amount; i++) {
if (in_uv.y > (u_shiftOrigins[i] - u_shiftHeights[i]) && in_uv.y < (u_shiftOrigins[i] + u_shiftHeights[i])) {
v += u_shiftStrengths[i];
}
}
float r = texture(in_texture, vec2(in_uv.x + (v * (1.0 + u_channelShift)), in_uv.y)).r;
float g = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).g;
float b = texture(in_texture, vec2(in_uv.x + (v * (1.0 + (u_channelShift / 2.0))), in_uv.y)).b;
float a = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).a;
out_color = vec4(r, g, b, a);
}
`;
export const FX_tearing = defineImageEffectorFx({
id: 'tearing',
name: i18n.ts._imageEffector._fxs.glitch + ': ' + i18n.ts._imageEffector._fxs.tearing,

View File

@ -0,0 +1,23 @@
#version 300 es
precision mediump float;
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform float u_r;
uniform float u_g;
uniform float u_b;
out vec4 out_color;
void main() {
vec4 in_color = texture(in_texture, in_uv);
float r = in_color.r < u_r ? 0.0 : 1.0;
float g = in_color.g < u_g ? 0.0 : 1.0;
float b = in_color.b < u_b ? 0.0 : 1.0;
out_color = vec4(r, g, b, in_color.a);
}

View File

@ -4,28 +4,9 @@
*/
import { defineImageEffectorFx } from '../ImageEffector.js';
import shader from './threshold.glsl';
import { i18n } from '@/i18n.js';
const shader = `#version 300 es
precision mediump float;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform float u_r;
uniform float u_g;
uniform float u_b;
out vec4 out_color;
void main() {
vec4 in_color = texture(in_texture, in_uv);
float r = in_color.r < u_r ? 0.0 : 1.0;
float g = in_color.g < u_g ? 0.0 : 1.0;
float b = in_color.b < u_b ? 0.0 : 1.0;
out_color = vec4(r, g, b, in_color.a);
}
`;
export const FX_threshold = defineImageEffectorFx({
id: 'threshold',
name: i18n.ts._imageEffector._fxs.threshold,

View File

@ -0,0 +1,147 @@
#version 300 es
precision mediump float;
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
const float PI = 3.141592653589793;
in vec2 in_uv; // 0..1
uniform sampler2D in_texture; // 背景
uniform vec2 in_resolution; // 出力解像度(px)
uniform sampler2D u_watermark; // ウォーターマーク
uniform vec2 u_wmResolution; // ウォーターマーク元解像度(px)
uniform float u_opacity; // 0..1
uniform float u_scale; // watermarkのスケール
uniform float u_angle; // -1..1 (PI倍)
uniform bool u_cover; // cover基準 or fit基準
uniform bool u_repeat; // タイル敷き詰め
uniform int u_alignX; // 0:left 1:center 2:right
uniform int u_alignY; // 0:top 1:center 2:bottom
uniform float u_margin; // 余白(比率)
uniform float u_repeatMargin; // 敷き詰め時の余白(比率)
uniform bool u_noBBoxExpansion; // 回転時のBounding Box拡張を抑止
uniform bool u_wmEnabled; // watermark有効
out vec4 out_color;
mat2 rot(float a) {
float c = cos(a), s = sin(a);
return mat2(c, -s, s, c);
}
// cover/fitとscaleから、最終的なサイズ(px)を計算
vec2 computeWmSize(vec2 outSize, vec2 wmSize, bool cover, float scale) {
float wmAspect = wmSize.x / wmSize.y;
float outAspect = outSize.x / outSize.y;
vec2 size;
if (cover) {
if (wmAspect >= outAspect) {
size.y = outSize.y * scale;
size.x = size.y * wmAspect;
} else {
size.x = outSize.x * scale;
size.y = size.x / wmAspect;
}
} else {
if (wmAspect >= outAspect) {
size.x = outSize.x * scale;
size.y = size.x / wmAspect;
} else {
size.y = outSize.y * scale;
size.x = size.y * wmAspect;
}
}
return size;
}
void main() {
vec2 outSize = in_resolution;
vec2 p = in_uv * outSize; // 出力のピクセル座標
vec4 base = texture(in_texture, in_uv);
if (!u_wmEnabled) {
out_color = base;
return;
}
float theta = u_angle * PI; // ラジアン
vec2 wmSize = computeWmSize(outSize, u_wmResolution, u_cover, u_scale);
vec2 margin = u_repeat ? wmSize * u_repeatMargin : outSize * u_margin;
// アライメントに基づく回転中心を計算
float rotateX = 0.0;
float rotateY = 0.0;
if (abs(theta) > 1e-6 && !u_noBBoxExpansion) {
rotateX = abs(abs(wmSize.x * cos(theta)) + abs(wmSize.y * sin(theta)) - wmSize.x) * 0.5;
rotateY = abs(abs(wmSize.x * sin(theta)) + abs(wmSize.y * cos(theta)) - wmSize.y) * 0.5;
}
float x;
if (u_alignX == 1) {
x = (outSize.x - wmSize.x) * 0.5;
} else if (u_alignX == 0) {
x = rotateX + margin.x;
} else {
x = outSize.x - wmSize.x - margin.x - rotateX;
}
float y;
if (u_alignY == 1) {
y = (outSize.y - wmSize.y) * 0.5;
} else if (u_alignY == 0) {
y = rotateY + margin.y;
} else {
y = outSize.y - wmSize.y - margin.y - rotateY;
}
vec2 rectMin = vec2(x, y);
vec2 rectMax = rectMin + wmSize;
vec2 rectCenter = (rectMin + rectMax) * 0.5;
vec4 wmCol = vec4(0.0);
if (u_repeat) {
// アライメントに基づく中心で回転
vec2 q = rectCenter + rot(theta) * (p - rectCenter);
// タイルグリッドの原点をrectMinアライメント位置に設定
vec2 gridOrigin = rectMin - margin;
vec2 qFromOrigin = q - gridOrigin;
// タイルサイズ(ウォーターマーク + マージン)で正規化
vec2 tile = wmSize + margin * 2.0;
vec2 tileUv = qFromOrigin / tile;
// タイル内のローカル座標(0..1)を取得
vec2 localUv = fract(tileUv);
// ローカル座標をピクセル単位に変換
vec2 localPos = localUv * tile;
// マージン領域内かチェック
bool inMargin = any(lessThan(localPos, margin)) || any(greaterThanEqual(localPos, margin + wmSize));
if (!inMargin) {
// ウォーターマーク領域内: UV座標を計算
vec2 uvWm = (localPos - margin) / wmSize;
wmCol = texture(u_watermark, uvWm);
}
// マージン領域の場合は透明(wmCol = vec4(0.0))のまま
} else {
// アライメントと回転に従い一枚だけ描画
vec2 q = rectCenter + rot(theta) * (p - rectCenter);
bool inside = all(greaterThanEqual(q, rectMin)) && all(lessThan(q, rectMax));
if (inside) {
vec2 uvWm = (q - rectMin) / wmSize;
wmCol = texture(u_watermark, uvWm);
}
}
float a = clamp(wmCol.a * u_opacity, 0.0, 1.0);
out_color = mix(base, vec4(wmCol.rgb, 1.0), a);
}

View File

@ -4,150 +4,7 @@
*/
import { defineImageEffectorFx } from '../ImageEffector.js';
const shader = `#version 300 es
precision mediump float;
const float PI = 3.141592653589793;
in vec2 in_uv; // 0..1
uniform sampler2D in_texture; // 背景
uniform vec2 in_resolution; // 出力解像度(px)
uniform sampler2D u_watermark; // ウォーターマーク
uniform vec2 u_wmResolution; // ウォーターマーク元解像度(px)
uniform float u_opacity; // 0..1
uniform float u_scale; // watermarkのスケール
uniform float u_angle; // -1..1 (PI倍)
uniform bool u_cover; // cover基準 or fit基準
uniform bool u_repeat; // タイル敷き詰め
uniform int u_alignX; // 0:left 1:center 2:right
uniform int u_alignY; // 0:top 1:center 2:bottom
uniform float u_margin; // 余白(比率)
uniform float u_repeatMargin; // 敷き詰め時の余白(比率)
uniform bool u_noBBoxExpansion; // 回転時のBounding Box拡張を抑止
uniform bool u_wmEnabled; // watermark有効
out vec4 out_color;
mat2 rot(float a) {
float c = cos(a), s = sin(a);
return mat2(c, -s, s, c);
}
// cover/fitとscaleから、最終的なサイズ(px)を計算
vec2 computeWmSize(vec2 outSize, vec2 wmSize, bool cover, float scale) {
float wmAspect = wmSize.x / wmSize.y;
float outAspect = outSize.x / outSize.y;
vec2 size;
if (cover) {
if (wmAspect >= outAspect) {
size.y = outSize.y * scale;
size.x = size.y * wmAspect;
} else {
size.x = outSize.x * scale;
size.y = size.x / wmAspect;
}
} else {
if (wmAspect >= outAspect) {
size.x = outSize.x * scale;
size.y = size.x / wmAspect;
} else {
size.y = outSize.y * scale;
size.x = size.y * wmAspect;
}
}
return size;
}
void main() {
vec2 outSize = in_resolution;
vec2 p = in_uv * outSize; // 出力のピクセル座標
vec4 base = texture(in_texture, in_uv);
if (!u_wmEnabled) {
out_color = base;
return;
}
float theta = u_angle * PI; // ラジアン
vec2 wmSize = computeWmSize(outSize, u_wmResolution, u_cover, u_scale);
vec2 margin = u_repeat ? wmSize * u_repeatMargin : outSize * u_margin;
// アライメントに基づく回転中心を計算
float rotateX = 0.0;
float rotateY = 0.0;
if (abs(theta) > 1e-6 && !u_noBBoxExpansion) {
rotateX = abs(abs(wmSize.x * cos(theta)) + abs(wmSize.y * sin(theta)) - wmSize.x) * 0.5;
rotateY = abs(abs(wmSize.x * sin(theta)) + abs(wmSize.y * cos(theta)) - wmSize.y) * 0.5;
}
float x;
if (u_alignX == 1) {
x = (outSize.x - wmSize.x) * 0.5;
} else if (u_alignX == 0) {
x = rotateX + margin.x;
} else {
x = outSize.x - wmSize.x - margin.x - rotateX;
}
float y;
if (u_alignY == 1) {
y = (outSize.y - wmSize.y) * 0.5;
} else if (u_alignY == 0) {
y = rotateY + margin.y;
} else {
y = outSize.y - wmSize.y - margin.y - rotateY;
}
vec2 rectMin = vec2(x, y);
vec2 rectMax = rectMin + wmSize;
vec2 rectCenter = (rectMin + rectMax) * 0.5;
vec4 wmCol = vec4(0.0);
if (u_repeat) {
// アライメントに基づく中心で回転
vec2 q = rectCenter + rot(theta) * (p - rectCenter);
// タイルグリッドの原点をrectMinアライメント位置に設定
vec2 gridOrigin = rectMin - margin;
vec2 qFromOrigin = q - gridOrigin;
// タイルサイズ(ウォーターマーク + マージン)で正規化
vec2 tile = wmSize + margin * 2.0;
vec2 tileUv = qFromOrigin / tile;
// タイル内のローカル座標(0..1)を取得
vec2 localUv = fract(tileUv);
// ローカル座標をピクセル単位に変換
vec2 localPos = localUv * tile;
// マージン領域内かチェック
bool inMargin = any(lessThan(localPos, margin)) || any(greaterThanEqual(localPos, margin + wmSize));
if (!inMargin) {
// ウォーターマーク領域内: UV座標を計算
vec2 uvWm = (localPos - margin) / wmSize;
wmCol = texture(u_watermark, uvWm);
}
// マージン領域の場合は透明(wmCol = vec4(0.0))のまま
} else {
// アライメントと回転に従い一枚だけ描画
vec2 q = rectCenter + rot(theta) * (p - rectCenter);
bool inside = all(greaterThanEqual(q, rectMin)) && all(lessThan(q, rectMax));
if (inside) {
vec2 uvWm = (q - rectMin) / wmSize;
wmCol = texture(u_watermark, uvWm);
}
}
float a = clamp(wmCol.a * u_opacity, 0.0, 1.0);
out_color = mix(base, vec4(wmCol.rgb, 1.0), a);
}
`;
import shader from './watermarkPlacement.glsl';
export const FX_watermarkPlacement = defineImageEffectorFx({
id: 'watermarkPlacement',

View File

@ -0,0 +1,48 @@
#version 300 es
precision mediump float;
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
// エイリアスを解決してくれないので、プロジェクトルートからの絶対パスにする必要がある
#include /src/shaders/snoise;
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform vec2 u_pos;
uniform float u_frequency;
uniform bool u_thresholdEnabled;
uniform float u_threshold;
uniform float u_maskSize;
uniform bool u_black;
out vec4 out_color;
void main() {
vec4 in_color = texture(in_texture, in_uv);
vec2 centeredUv = (in_uv - vec2(0.5, 0.5));
vec2 uv = centeredUv;
float seed = 1.0;
float time = 0.0;
vec2 noiseUV = (uv - u_pos) / distance((uv - u_pos), vec2(0.0));
float noiseX = (noiseUV.x + seed) * u_frequency;
float noiseY = (noiseUV.y + seed) * u_frequency;
float noise = (1.0 + snoise(vec3(noiseX, noiseY, time))) / 2.0;
float t = noise;
if (u_thresholdEnabled) t = t < u_threshold ? 1.0 : 0.0;
// TODO: マスクの形自体も揺らぎを与える
float d = distance(uv * vec2(2.0, 2.0), u_pos * vec2(2.0, 2.0));
float mask = d < u_maskSize ? 0.0 : ((d - u_maskSize) * (1.0 + (u_maskSize * 2.0)));
out_color = vec4(
mix(in_color.r, u_black ? 0.0 : 1.0, t * mask),
mix(in_color.g, u_black ? 0.0 : 1.0, t * mask),
mix(in_color.b, u_black ? 0.0 : 1.0, t * mask),
in_color.a
);
}

View File

@ -4,53 +4,9 @@
*/
import { defineImageEffectorFx } from '../ImageEffector.js';
import { GLSL_LIB_SNOISE } from '@/utility/webgl.js';
import shader from './zoomLines.glsl';
import { i18n } from '@/i18n.js';
const shader = `#version 300 es
precision mediump float;
${GLSL_LIB_SNOISE}
in vec2 in_uv;
uniform sampler2D in_texture;
uniform vec2 in_resolution;
uniform vec2 u_pos;
uniform float u_frequency;
uniform bool u_thresholdEnabled;
uniform float u_threshold;
uniform float u_maskSize;
uniform bool u_black;
out vec4 out_color;
void main() {
vec4 in_color = texture(in_texture, in_uv);
vec2 centeredUv = (in_uv - vec2(0.5, 0.5));
vec2 uv = centeredUv;
float seed = 1.0;
float time = 0.0;
vec2 noiseUV = (uv - u_pos) / distance((uv - u_pos), vec2(0.0));
float noiseX = (noiseUV.x + seed) * u_frequency;
float noiseY = (noiseUV.y + seed) * u_frequency;
float noise = (1.0 + snoise(vec3(noiseX, noiseY, time))) / 2.0;
float t = noise;
if (u_thresholdEnabled) t = t < u_threshold ? 1.0 : 0.0;
// TODO: マスクの形自体も揺らぎを与える
float d = distance(uv * vec2(2.0, 2.0), u_pos * vec2(2.0, 2.0));
float mask = d < u_maskSize ? 0.0 : ((d - u_maskSize) * (1.0 + (u_maskSize * 2.0)));
out_color = vec4(
mix(in_color.r, u_black ? 0.0 : 1.0, t * mask),
mix(in_color.g, u_black ? 0.0 : 1.0, t * mask),
mix(in_color.b, u_black ? 0.0 : 1.0, t * mask),
in_color.a
);
}
`;
export const FX_zoomLines = defineImageEffectorFx({
id: 'zoomLines',
name: i18n.ts._imageEffector._fxs.zoomLines,

View File

@ -38,91 +38,3 @@ export function initShaderProgram(gl: WebGL2RenderingContext, vsSource: string,
return shaderProgram;
}
export const GLSL_LIB_SNOISE = `
// Description : Array and textureless GLSL 2D/3D/4D simplex
// noise functions.
// Author : Ian McEwan, Ashima Arts.
// Maintainer : stegu
// Lastmod : 20201014 (stegu)
// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
// Distributed under the MIT License. See LICENSE file.
// https://github.com/ashima/webgl-noise
// https://github.com/stegu/webgl-noise
vec3 mod289(vec3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 mod289(vec4 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 permute(vec4 x) {
return mod289(((x * 34.0) + 10.0) * x);
}
vec4 taylorInvSqrt(vec4 r) {
return 1.79284291400159 - 0.85373472095314 * r;
}
float snoise(vec3 v) {
const vec2 C = vec2(1.0/6.0, 1.0/3.0);
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
vec3 i = floor(v + dot(v, C.yyy));
vec3 x0 = v - i + dot(i, C.xxx);
vec3 g = step(x0.yzx, x0.xyz);
vec3 l = 1.0 - g;
vec3 i1 = min(g.xyz, l.zxy);
vec3 i2 = max(g.xyz, l.zxy);
vec3 x1 = x0 - i1 + C.xxx;
vec3 x2 = x0 - i2 + C.yyy;
vec3 x3 = x0 - D.yyy;
i = mod289(i);
vec4 p = permute(permute(permute(
i.z + vec4(0.0, i1.z, i2.z, 1.0))
+ i.y + vec4(0.0, i1.y, i2.y, 1.0))
+ i.x + vec4(0.0, i1.x, i2.x, 1.0));
float n_ = 0.142857142857;
vec3 ns = n_ * D.wyz - D.xzx;
vec4 j = p - 49.0 * floor(p * ns.z * ns.z);
vec4 x_ = floor(j * ns.z);
vec4 y_ = floor(j - 7.0 * x_);
vec4 x = x_ * ns.x + ns.yyyy;
vec4 y = y_ * ns.x + ns.yyyy;
vec4 h = 1.0 - abs(x) - abs(y);
vec4 b0 = vec4(x.xy, y.xy);
vec4 b1 = vec4(x.zw, y.zw);
vec4 s0 = floor(b0) * 2.0 + 1.0;
vec4 s1 = floor(b1) * 2.0 + 1.0;
vec4 sh = -step(h, vec4(0.0));
vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;
vec3 p0 = vec3(a0.xy, h.x);
vec3 p1 = vec3(a0.zw, h.y);
vec3 p2 = vec3(a1.xy, h.z);
vec3 p3 = vec3(a1.zw, h.w);
vec4 norm = taylorInvSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));
p0 *= norm.x;
p1 *= norm.y;
p2 *= norm.z;
p3 *= norm.w;
vec4 m = max(0.5 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0);
m = m * m;
return 105.0 * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3)));
}
`;

View File

@ -36,6 +36,7 @@
],
"types": [
"vite/client",
"vite-plugin-glsl/ext",
"vitest/importMeta",
],
"lib": [

View File

@ -1,6 +1,7 @@
import path from 'path';
import pluginReplace from '@rollup/plugin-replace';
import pluginVue from '@vitejs/plugin-vue';
import pluginGlsl from 'vite-plugin-glsl';
import { defineConfig } from 'vite';
import type { UserConfig } from 'vite';
import * as yaml from 'js-yaml';
@ -117,6 +118,7 @@ export function getConfig(): UserConfig {
pluginRemoveUnrefI18n(),
pluginUnwindCssModuleClassName(),
pluginJson5(),
pluginGlsl({ minify: true }),
...process.env.NODE_ENV === 'production'
? [
pluginReplace({

View File

@ -1074,6 +1074,9 @@ importers:
tsx:
specifier: 4.20.6
version: 4.20.6
vite-plugin-glsl:
specifier: 1.5.4
version: 1.5.4(@rollup/pluginutils@5.3.0(rollup@4.52.3))(esbuild@0.25.10)(vite@7.1.7(@types/node@22.18.8)(sass@1.93.2)(terser@5.44.0)(tsx@4.20.6))
vite-plugin-turbosnap:
specifier: 1.0.3
version: 1.0.3
@ -10726,6 +10729,19 @@ packages:
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
hasBin: true
vite-plugin-glsl@1.5.4:
resolution: {integrity: sha512-EUmwL+IDK+dGDAlaKm89++k8aJ4qmHjLQxrngww3GLOOAQ4aZ48o9YR1ie7XPe08iDWlG+9Uh5V7oiZcXTUbyA==}
engines: {node: '>= 20.17.0', npm: '>= 10.8.3'}
peerDependencies:
'@rollup/pluginutils': ^5.x
esbuild: '>= 0.25'
vite: '>= 3.x'
peerDependenciesMeta:
'@rollup/pluginutils':
optional: true
esbuild:
optional: true
vite-plugin-turbosnap@1.0.3:
resolution: {integrity: sha512-p4D8CFVhZS412SyQX125qxyzOgIFouwOcvjZWk6bQbNPR1wtaEzFT6jZxAjf1dejlGqa6fqHcuCvQea6EWUkUA==}
@ -22336,6 +22352,13 @@ snapshots:
- tsx
- yaml
vite-plugin-glsl@1.5.4(@rollup/pluginutils@5.3.0(rollup@4.52.3))(esbuild@0.25.10)(vite@7.1.7(@types/node@22.18.8)(sass@1.93.2)(terser@5.44.0)(tsx@4.20.6)):
dependencies:
vite: 7.1.7(@types/node@22.18.8)(sass@1.93.2)(terser@5.44.0)(tsx@4.20.6)
optionalDependencies:
'@rollup/pluginutils': 5.3.0(rollup@4.52.3)
esbuild: 0.25.10
vite-plugin-turbosnap@1.0.3: {}
vite@7.1.7(@types/node@22.18.8)(sass@1.93.2)(terser@5.44.0)(tsx@4.20.6):