wip
This commit is contained in:
parent
bd8d0d78bf
commit
9fb0f7357a
|
@ -4,16 +4,28 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
-->
|
||||
|
||||
<template>
|
||||
<div :class="$style.root" class="_gaps">
|
||||
<div v-for="[k, v] in Object.entries(fx.params)" :key="k">
|
||||
<MkSwitch v-if="v.type === 'boolean'" v-model="layer.params[k]">
|
||||
<template #label>{{ k }}</template>
|
||||
</MkSwitch>
|
||||
<MkRange v-else-if="v.type === 'number'" v-model="layer.params[k]" continuousUpdate :min="v.min" :max="v.max" :step="v.step">
|
||||
<template #label>{{ k }}</template>
|
||||
</MkRange>
|
||||
<MkFolder :defaultOpen="true">
|
||||
<template #label>{{ fx.id }}</template>
|
||||
<template #footer>
|
||||
<MkButton @click="emit('del')">{{ i18n.ts.remove }}</MkButton>
|
||||
</template>
|
||||
|
||||
<div :class="$style.root" class="_gaps">
|
||||
<div v-for="[k, v] in Object.entries(fx.params)" :key="k">
|
||||
<MkSwitch v-if="v.type === 'boolean'" v-model="layer.params[k]">
|
||||
<template #label>{{ k }}</template>
|
||||
</MkSwitch>
|
||||
<MkRange v-else-if="v.type === 'number'" v-model="layer.params[k]" continuousUpdate :min="v.min" :max="v.max" :step="v.step">
|
||||
<template #label>{{ k }}</template>
|
||||
</MkRange>
|
||||
<div v-else-if="v.type === 'seed'">
|
||||
<MkRange v-model="layer.params[k]" continuousUpdate type="number" :min="0" :max="10000" :step="1">
|
||||
<template #label>{{ k }}</template>
|
||||
</MkRange>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</MkFolder>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -22,7 +34,7 @@ import { v4 as uuid } from 'uuid';
|
|||
import type { ImageEffectorLayer } from '@/utility/image-effector/ImageEffector.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { FXS, ImageEffector } from '@/utility/image-effector/ImageEffector.js';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
|
@ -40,6 +52,9 @@ if (fx == null) {
|
|||
throw new Error(`Unrecognized effect: ${layer.value.fxId}`);
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'del'): void;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style module>
|
||||
|
|
|
@ -31,6 +31,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
v-for="(layer, i) in layers"
|
||||
:key="layer.id"
|
||||
v-model:layer="layers[i]"
|
||||
@del="onLayerDelete(layer)"
|
||||
></XLayer>
|
||||
|
||||
<MkButton rounded primary @click="addEffect"><i class="ti ti-plus"></i></MkButton>
|
||||
|
@ -81,7 +82,7 @@ watch(layers, async () => {
|
|||
}, { deep: true });
|
||||
|
||||
function addEffect(ev: MouseEvent) {
|
||||
os.popupMenu(FXS.map((fx) => ({
|
||||
os.popupMenu(FXS.filter(fx => fx.id !== 'watermarkPlacement').map((fx) => ({
|
||||
text: fx.id,
|
||||
action: () => {
|
||||
layers.push({
|
||||
|
@ -93,6 +94,13 @@ function addEffect(ev: MouseEvent) {
|
|||
})), ev.currentTarget ?? ev.target);
|
||||
}
|
||||
|
||||
function onLayerDelete(layer: ImageEffectorLayer) {
|
||||
const index = layers.indexOf(layer);
|
||||
if (index !== -1) {
|
||||
layers.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
const canvasEl = useTemplateRef('canvasEl');
|
||||
|
||||
let renderer: ImageEffector | null = null;
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
|
||||
import { getProxiedImageUrl } from '../media-proxy.js';
|
||||
import { FX_chromaticAberration } from './fxs/chromaticAberration.js';
|
||||
import { FX_glitch } from './fxs/glitch.js';
|
||||
import { FX_watermarkPlacement } from './fxs/watermarkPlacement.js';
|
||||
|
||||
type ParamTypeToPrimitive = {
|
||||
'number': number;
|
||||
'boolean': boolean;
|
||||
'align': { x: 'left' | 'center' | 'right'; y: 'top' | 'center' | 'bottom'; };
|
||||
'seed': number;
|
||||
};
|
||||
|
||||
type ImageEffectorFxParamDefs = Record<string, {
|
||||
|
@ -46,6 +48,7 @@ export type ImageEffectorFx<ID extends string, P extends ImageEffectorFxParamDef
|
|||
export const FXS = [
|
||||
FX_watermarkPlacement,
|
||||
FX_chromaticAberration,
|
||||
FX_glitch,
|
||||
] as const satisfies ImageEffectorFx<string, any>[];
|
||||
|
||||
export type ImageEffectorLayerOf<
|
||||
|
|
|
@ -28,24 +28,14 @@ void main() {
|
|||
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 = normalize((in_uv - (size / 2.0)) / size);
|
||||
//vec2 vector = in_uv;
|
||||
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 * 1.0);
|
||||
//vec2 gOffset = -vector * strength * (u_amount * 1.5);
|
||||
//vec2 bOffset = -vector * strength * (u_amount * 2.0);
|
||||
|
||||
//vec2 rOffset = -vector * strength * (u_amount * 0.5);
|
||||
//vec2 gOffset = -vector * strength * (u_amount * 1.0);
|
||||
//vec2 bOffset = -vector * strength * (u_amount * 2.0);
|
||||
|
||||
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++) {
|
||||
for (int i = 0; i < samples; i++) {
|
||||
accumulator.r += texture(u_texture, in_uv + rOffset).r;
|
||||
rOffset -= velocity / float(samples);
|
||||
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import seedrandom from 'seedrandom';
|
||||
import { defineImageEffectorFx } from '../ImageEffector.js';
|
||||
|
||||
const shader = `#version 300 es
|
||||
precision highp float;
|
||||
|
||||
in vec2 in_uv;
|
||||
uniform sampler2D u_texture;
|
||||
uniform vec2 u_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(u_texture, vec2(in_uv.x + (v * (1.0 + u_channelShift)), in_uv.y)).r;
|
||||
float g = texture(u_texture, vec2(in_uv.x + v, in_uv.y)).g;
|
||||
float b = texture(u_texture, vec2(in_uv.x + (v * (1.0 + (u_channelShift / 2.0))), in_uv.y)).b;
|
||||
float a = texture(u_texture, vec2(in_uv.x + v, in_uv.y)).a;
|
||||
out_color = vec4(r, g, b, a);
|
||||
}
|
||||
`;
|
||||
|
||||
export const FX_glitch = defineImageEffectorFx({
|
||||
id: 'glitch' as const,
|
||||
shader,
|
||||
params: {
|
||||
amount: {
|
||||
type: 'number' as const,
|
||||
default: 3,
|
||||
min: 1,
|
||||
max: 100,
|
||||
step: 1,
|
||||
},
|
||||
strength: {
|
||||
type: 'number' as const,
|
||||
default: 5,
|
||||
min: -100,
|
||||
max: 100,
|
||||
step: 0.01,
|
||||
},
|
||||
size: {
|
||||
type: 'number' as const,
|
||||
default: 20,
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 0.01,
|
||||
},
|
||||
channelShift: {
|
||||
type: 'number' as const,
|
||||
default: 0.5,
|
||||
min: 0,
|
||||
max: 10,
|
||||
step: 0.01,
|
||||
},
|
||||
seed: {
|
||||
type: 'seed' as const,
|
||||
default: 100,
|
||||
},
|
||||
},
|
||||
main: ({ gl, program, params, preTexture }) => {
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, preTexture);
|
||||
const u_texture = gl.getUniformLocation(program, 'u_texture');
|
||||
gl.uniform1i(u_texture, 0);
|
||||
|
||||
const u_amount = gl.getUniformLocation(program, 'u_amount');
|
||||
gl.uniform1i(u_amount, params.amount);
|
||||
|
||||
const u_channelShift = gl.getUniformLocation(program, 'u_channelShift');
|
||||
gl.uniform1f(u_channelShift, params.channelShift);
|
||||
|
||||
const rnd = seedrandom(params.seed.toString());
|
||||
|
||||
for (let i = 0; i < params.amount; i++) {
|
||||
const o = gl.getUniformLocation(program, `u_shiftOrigins[${i.toString()}]`);
|
||||
gl.uniform1f(o, rnd());
|
||||
|
||||
const s = gl.getUniformLocation(program, `u_shiftStrengths[${i.toString()}]`);
|
||||
gl.uniform1f(s, (1 - (rnd() * 2)) * (params.strength / 100));
|
||||
|
||||
const h = gl.getUniformLocation(program, `u_shiftHeights[${i.toString()}]`);
|
||||
gl.uniform1f(h, rnd() * (params.size / 100));
|
||||
}
|
||||
},
|
||||
});
|
Loading…
Reference in New Issue