GLSL Sierpiński Glitch Texture #3
const vert = `#version 300 es
layout(location = 0) in vec3 position;
out vec2 uv;
void main(void) {
uv = position.xy * 0.5 + 0.5;
gl_Position = vec4(position, 1.0);
}
`;
const frag1 = `#version 300 es
precision highp float;
uniform float time;
uniform float dx;
uniform float dy;
float w2 = 1.0 / float(${innerWidth * 2});
float w10 = 1.0 / (float(${innerWidth * 2}) * 100.);
float convert = 3.141592653589 / 180.;
float sn;
float cs;
out vec4 fragColor;
void main(void) {
vec2 uv = gl_FragCoord.xy / vec2(float(${innerWidth * 2}), float(${innerHeight * 2}));
float xp = uv.x * float(${innerWidth * 2});
float yp = (1. - uv.y) * float(${innerHeight * 2});
int x = 10 | 2;
int xp2 = int(xp) << 1;
float t = mod(float(int(yp) | int(xp + yp * .1) ) * (xp + dx) * (w10), 6.283185307179586);
if (t < 0.) {
sn = 1.27323954 * t + .405284735 * t * t;
} else {
sn = 1.27323954 * t - 0.405284735 * t * t;
}
t = mod(float( (xp2 | int(yp + xp * .1 + dy) )) * convert, 6.283185307179586);
t += 1.57079632;
if (t > 3.14159265) {
t -= 6.28318531;
}
if (t < 0.) {
cs = 1.27323954 * t + 0.405284735 * t * t;
} else {
cs = 1.27323954 * t - 0.405284735 * t * t;
}
float c1 = 30. * (sn - cs);
if (c1 < 0.) c1 = 255. - c1;
c1 = float((int(c1) << 4 | int(c1)) & 255) / 255.;
fragColor = vec4(c1, c1, c1, 1.0);
}
`;
const frag2 = `#version 300 es
precision highp float;
in vec2 uv;
// The max kernel size (impacts performance)
#define maxKernel 1.0
// The max offset (doesn't impact performance)
#define maxOffset 34.0
uniform sampler2D uTexture;
// https://www.shadertoy.com/view/mdGcRh
vec3 fastBlur(vec2 uv, vec2 texel, vec2 kd)
{
float r = kd.x * kd.y;
float rr = 1.0/r;
vec3 col = vec3(0.0);
float a = 1.0;
for (float x = -r; x <= r; x += kd.y) {
for (float y = -r; y <= r; y += kd.y) {
a++;
vec2 c = uv + vec2(x,y) * texel;
col += texture(uTexture, c + fract(sin(dot(c, vec2(12.9898, 78.233))) * 43758.5453) * texel * kd.y * 2.0 - kd.yy * texel).rgb * (2.0 - distance(vec2(x,y) * rr, vec2(0.0)));
}
}
return col / a;
}
out vec4 fragColor;
void main(void) {
vec4 color = texture(uTexture, uv);
vec4 colorB = texture(uTexture, vec2(uv.x, 1. - uv.y));
vec3 result = (color.rgb - colorB.rgb) * 1.2;
float amt = .4;
vec2 texel = vec2(1.0)/ vec2(float(${innerWidth * 2}), float(${innerHeight * 2}));
vec2 kd = round(vec2(amt * maxKernel + 1.0, amt * maxOffset + 1.0));
vec3 blur = fastBlur(uv, texel, kd);
fragColor = vec4(result, color.a);
}
`;
const frag3 = `#version 300 es
precision highp float;
in vec2 uv;
// The max kernel size (impacts performance)
#define maxKernel 4.0
// The max offset (doesn't impact performance)
#define maxOffset 34.0
uniform sampler2D uTexture;
// https://www.shadertoy.com/view/mdGcRh
vec3 fastBlur(vec2 uv, vec2 texel, vec2 kd)
{
float r = kd.x * kd.y;
float rr = 1.0/r;
vec3 col = vec3(0.0);
float a = 1.0;
for (float x = -r; x <= r; x += kd.y) {
for (float y = -r; y <= r; y += kd.y) {
a++;
vec2 c = uv + vec2(x,y) * texel;
col += texture(
uTexture,
c
+ fract(sin(dot(c, vec2(2.9898, 78.233))) * 13758.5453) * texel * kd.y * 2.4
- kd.yy * texel
).rgb * (2.0 - distance(vec2(x,y) * rr, vec2(0.0)));
}
}
return col / a;
}
out vec4 fragColor;
void main(void) {
vec4 color = texture(uTexture, uv);
float amt = .4;
vec2 texel = vec2(1.0)/ vec2(float(${innerWidth * 2}), float(${innerHeight * 2}));
vec2 kd = round(vec2(amt * maxKernel + 1.0, amt * maxOffset + 1.0));
vec4 blur = vec4(fastBlur(uv, texel, kd), 1.);
//1-(1-A)*(1-B)
vec3 f = 1. - (1. - color.rgb) * (1. - blur.rgb);
fragColor = vec4(f.rgb, 1.);
}
`;
document.body.style.background = '#000';
const gl = document.body
.appendChild(document.createElement('canvas'))
.getContext('webgl2');
Object.assign(gl.canvas.style, {
position: 'absolute',
left: 0,
top: 0
});
const s = 1;
const verts = new Float32Array([
-s, -s, 0,
s, -s, 0,
-s, s, 0,
s, s, 0,
]);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, verts, gl.STATIC_DRAW);
function createShaderProgram(vertexSource, fragmentSource) {
const vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, vertexSource);
gl.compileShader(vs);
const fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, fragmentSource);
gl.compileShader(fs);
const program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error('Could not link program:', gl.getProgramInfoLog(program));
}
return program;
}
const program1 = createShaderProgram(vert, frag1);
const program2 = createShaderProgram(vert, frag2);
const program3 = createShaderProgram(vert, frag3);
const framebuffer1 = gl.createFramebuffer();
const framebuffer2 = gl.createFramebuffer();
const texture1 = gl.createTexture();
const texture2 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, innerWidth, innerHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.bindTexture(gl.TEXTURE_2D, texture2);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, innerWidth, innerHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer1);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture1, 0);
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer2);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture2, 0);
const onResize = () => {
gl.canvas.width = innerWidth * 2;
gl.canvas.height = innerHeight * 2;
gl.canvas.style.width = innerWidth + 'px'
gl.canvas.style.height = innerHeight + 'px'
gl.viewport(0, 0, innerWidth * 2, innerHeight * 2);
gl.bindTexture(gl.TEXTURE_2D, texture1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, innerWidth * 2, innerHeight * 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.bindTexture(gl.TEXTURE_2D, texture2);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, innerWidth * 2, innerHeight * 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
};
window.onresize = onResize;
onResize();
gl.disable(gl.DEPTH_TEST);
let mx = 0;
let my = 0;
let dx = 0;
let dy = 0;
window.onpointermove = e => {
mx = e.clientX;
my = e.clientY;
};
const loop = () => {
dx += (mx * 2 - (innerWidth) - dx) / 8;
dy += (my * 2 - dy) / 8;
// first pass
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer1);
gl.useProgram(program1);
const mxUniform = gl.getUniformLocation(program1, 'dx');
gl.uniform1f(mxUniform, dx);
const myUniform = gl.getUniformLocation(program1, 'dy');
gl.uniform1f(myUniform, dy);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
const pos1 = gl.getAttribLocation(program1, 'position');
gl.enableVertexAttribArray(pos1);
gl.vertexAttribPointer(pos1, 3, gl.FLOAT, false, 0, 0);
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
// second pass
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer2);
gl.useProgram(program2);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
const pos2 = gl.getAttribLocation(program2, 'position');
gl.enableVertexAttribArray(pos2);
gl.vertexAttribPointer(pos2, 3, gl.FLOAT, false, 0, 0);
const uTexture = gl.getUniformLocation(program2, 'uTexture');
gl.uniform1i(uTexture, 0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture1);
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
// third pass
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.useProgram(program3);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
const pos3 = gl.getAttribLocation(program3, 'position');
gl.enableVertexAttribArray(pos3);
gl.vertexAttribPointer(pos3, 3, gl.FLOAT, false, 0, 0);
const u2Texture = gl.getUniformLocation(program3, 'uTexture');
gl.uniform1i(u2Texture, 0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture2);
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
requestAnimationFrame(loop);
};
loop();
this old thing was tricky to port to glsl, canvas port was easy (codepen here) – used gpt a bit for glsl version… got it eventually: take a look