add pfp thingo
This commit is contained in:
parent
f26c50a2d4
commit
9b2b05c416
2 changed files with 335 additions and 0 deletions
335
-~-/pfp/index.html
Normal file
335
-~-/pfp/index.html
Normal file
|
@ -0,0 +1,335 @@
|
|||
<!DOCTYPE html>
|
||||
<title>noe pfp generator</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<script
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/3.4.2/gl-matrix-min.js"
|
||||
referrerpolicy="no-referrer"
|
||||
></script>
|
||||
<style>
|
||||
:root {
|
||||
font-family: "Atkinson Hyperlegible", sans-serif;
|
||||
background-color: black;
|
||||
color: #efefef;
|
||||
}
|
||||
|
||||
a {
|
||||
color: gold;
|
||||
}
|
||||
|
||||
section {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
#error {
|
||||
color: pink;
|
||||
}
|
||||
|
||||
#draw {
|
||||
border: 3px solid grey;
|
||||
}
|
||||
|
||||
.num {
|
||||
width: 4em;
|
||||
}
|
||||
</style>
|
||||
|
||||
<main>
|
||||
<p id="error"></p>
|
||||
<noscript>this tool uses webgl, so js must be enabled. sorry!</noscript>
|
||||
<section>
|
||||
albedo <input type="file" id="albedo" accept="image/*" /><br />
|
||||
x power
|
||||
<input type="number" class="num" id="x-pow" value="1" step="0.1" /> y power
|
||||
<input type="number" class="num" id="y-pow" value="1" step="0.1" /><br />
|
||||
<button id="run-frame">Run Frame</button>
|
||||
</section>
|
||||
<section>
|
||||
<canvas width="256" height="256" id="draw" />
|
||||
</section>
|
||||
<section>
|
||||
<p>This tool is what it uses to generate its profile pictures.</p>
|
||||
<p>
|
||||
In short, it takes the "albedo" texture that you upload, applies the "<a
|
||||
href="/-~-/pfp/noegram.png"
|
||||
>noegram </a
|
||||
>" pattern over the top, where the overlay switches to a random UV offset
|
||||
per line, causing a glitch-like effect.
|
||||
</p>
|
||||
<p>
|
||||
<img
|
||||
src="/-~-/pfp/noegram.png"
|
||||
id="noegram"
|
||||
width="256"
|
||||
height="256"
|
||||
alt="noegram"
|
||||
/>
|
||||
</p>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<script type="text/x-vertex-shader" id="vertexShader">
|
||||
in vec4 a_vertex;
|
||||
in vec2 a_uv0;
|
||||
|
||||
uniform mat4 u_model_view;
|
||||
uniform mat4 u_projection;
|
||||
|
||||
out vec2 uv0;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * u_model_view * a_vertex;
|
||||
uv0 = a_uv0;
|
||||
}
|
||||
</script>
|
||||
<script type="text/x-fragment-shader" id="fragmentShader">
|
||||
uniform vec2 u_noe_power;
|
||||
uniform vec2 u_noise_offset;
|
||||
|
||||
uniform sampler2D u_texture_0; // albedo
|
||||
uniform sampler2D u_texture_1; // noegram
|
||||
uniform sampler2D u_texture_2; // noise
|
||||
|
||||
in vec2 uv0;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
vec4 noegram = texture(u_texture_1, uv0);
|
||||
|
||||
vec4 albedo = texture(u_texture_0, uv0 + (noegram.r * 0.5) / 2.0);
|
||||
|
||||
fragColor = vec4(albedo.rgb, 1.0);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script defer async>
|
||||
(() => {
|
||||
const { mat4, vec2 } = glMatrix;
|
||||
|
||||
const xPowEl = document.querySelector("#x-pow");
|
||||
const yPowEl = document.querySelector("#y-pow");
|
||||
|
||||
const getPower = () => {
|
||||
return [xPowEl.value, yPowEl.value];
|
||||
};
|
||||
|
||||
const canvasEl = document.querySelector("#draw");
|
||||
const albedoEl = document.querySelector("#albedo");
|
||||
const renderEl = document.querySelector("#run-frame");
|
||||
|
||||
const gl = canvasEl.getContext("webgl2");
|
||||
if (gl === null) {
|
||||
document.querySelector("#error").innerHTML = "WebGL2 context failed.";
|
||||
}
|
||||
|
||||
const makeTexture = async (blob, texture) => {
|
||||
const image = await createImageBitmap(blob, {
|
||||
imageOrientation: "flipY",
|
||||
});
|
||||
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||
gl.texImage2D(
|
||||
gl.TEXTURE_2D,
|
||||
0,
|
||||
gl.RGBA,
|
||||
image.width,
|
||||
image.height,
|
||||
0,
|
||||
gl.RGBA,
|
||||
gl.UNSIGNED_BYTE,
|
||||
image
|
||||
);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); // configurable?
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||
};
|
||||
|
||||
const albedoTex = gl.createTexture();
|
||||
|
||||
let noegramOk = false;
|
||||
const noegramEl = document.querySelector("#noegram");
|
||||
const noegramTex = gl.createTexture();
|
||||
noegramEl.onload = async () => {
|
||||
await makeTexture(noegramEl, noegramTex);
|
||||
noegramOk = true;
|
||||
};
|
||||
|
||||
gl.getExtension("EXT_texture_filter_anisotropic");
|
||||
|
||||
const vao = gl.createVertexArray();
|
||||
gl.bindVertexArray(vao);
|
||||
|
||||
const projectionMatrix = mat4.create();
|
||||
mat4.perspective(projectionMatrix, 45, 1, 0.1, 100);
|
||||
|
||||
const modelViewMatrix = mat4.create();
|
||||
mat4.translate(modelViewMatrix, modelViewMatrix, [0, 0, -1.79]);
|
||||
|
||||
const clear = () => {
|
||||
gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
|
||||
gl.clearDepth(1.0); // Clear everything
|
||||
gl.enable(gl.DEPTH_TEST); // Enable depth testing
|
||||
gl.depthFunc(gl.LEQUAL); // Near things obscure far things
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
};
|
||||
|
||||
const initBuffer = (array) => {
|
||||
const buffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW);
|
||||
|
||||
return buffer;
|
||||
};
|
||||
|
||||
// Plane
|
||||
const vertexPositions = initBuffer(
|
||||
new Float32Array([-1.0, -1.0, +1.0, -1.0, -1.0, +1.0, +1.0, +1.0])
|
||||
);
|
||||
const textureCoords = initBuffer(
|
||||
new Float32Array([0, 0, 1, 0, 0, 1, 1, 1])
|
||||
);
|
||||
|
||||
// Shaders
|
||||
const program = gl.createProgram();
|
||||
|
||||
const addShader = (type, source) => {
|
||||
const shader = gl.createShader(type);
|
||||
gl.shaderSource(shader, source);
|
||||
gl.compileShader(shader);
|
||||
|
||||
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
||||
throw new Error(
|
||||
"An error occurred compiling the shaders: " +
|
||||
gl.getShaderInfoLog(shader)
|
||||
);
|
||||
}
|
||||
|
||||
gl.attachShader(program, shader);
|
||||
};
|
||||
|
||||
addShader(
|
||||
gl.VERTEX_SHADER,
|
||||
`#version 300 es\nprecision highp float;\n${
|
||||
document.querySelector("#vertexShader").innerHTML
|
||||
}`
|
||||
);
|
||||
addShader(
|
||||
gl.FRAGMENT_SHADER,
|
||||
`#version 300 es\nprecision highp float;\n${
|
||||
document.querySelector("#fragmentShader").innerHTML
|
||||
}`
|
||||
);
|
||||
|
||||
gl.linkProgram(program);
|
||||
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
||||
throw new Error(
|
||||
"Unable to initialize the shader program: " +
|
||||
gl.getProgramInfoLog(program)
|
||||
);
|
||||
}
|
||||
|
||||
const bindAttrib = (buffer, attribute) => {
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
||||
gl.vertexAttribPointer(
|
||||
gl.getAttribLocation(program, attribute),
|
||||
2,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
0,
|
||||
0
|
||||
);
|
||||
gl.enableVertexAttribArray(gl.getAttribLocation(program, attribute));
|
||||
};
|
||||
|
||||
bindAttrib(vertexPositions, "a_vertex");
|
||||
bindAttrib(textureCoords, "a_uv0");
|
||||
|
||||
const renderFrame = () => {
|
||||
clear();
|
||||
|
||||
gl.bindVertexArray(vao);
|
||||
|
||||
// Shader activation
|
||||
gl.useProgram(program);
|
||||
gl.uniformMatrix4fv(
|
||||
gl.getUniformLocation(program, "u_model_view"),
|
||||
false,
|
||||
modelViewMatrix
|
||||
);
|
||||
gl.uniformMatrix4fv(
|
||||
gl.getUniformLocation(program, "u_projection"),
|
||||
false,
|
||||
projectionMatrix
|
||||
);
|
||||
|
||||
// Verts and UVs
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositions);
|
||||
gl.vertexAttribPointer(
|
||||
gl.getAttribLocation(program, "a_vertex"),
|
||||
2,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
0,
|
||||
0
|
||||
);
|
||||
gl.enableVertexAttribArray(gl.getAttribLocation(program, "a_vertex"));
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, textureCoords);
|
||||
gl.vertexAttribPointer(
|
||||
gl.getAttribLocation(program, "a_uv0"),
|
||||
2,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
0,
|
||||
0
|
||||
);
|
||||
gl.enableVertexAttribArray(gl.getAttribLocation(program, "a_uv0"));
|
||||
|
||||
// Textures
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, albedoTex);
|
||||
gl.uniform1i(gl.getUniformLocation(program, "u_texture_0"), 0);
|
||||
|
||||
gl.activeTexture(gl.TEXTURE1);
|
||||
gl.bindTexture(gl.TEXTURE_2D, noegramTex);
|
||||
gl.uniform1i(gl.getUniformLocation(program, "u_texture_1"), 1);
|
||||
|
||||
gl.activeTexture(gl.TEXTURE2);
|
||||
gl.bindTexture(gl.TEXTURE_2D, noegramTex); // TODO: replace with noise
|
||||
gl.uniform1i(gl.getUniformLocation(program, "u_texture_2"), 2);
|
||||
|
||||
// draw!
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositions);
|
||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
const err = gl.getError();
|
||||
if (err !== 0) {
|
||||
console.log({ err });
|
||||
throw new Error(`webgl failure: ${err}`);
|
||||
}
|
||||
};
|
||||
|
||||
renderEl.addEventListener("click", async () => {
|
||||
if (albedoEl.files.length === 0) {
|
||||
console.warn("cannot render, albedo not loaded yet");
|
||||
return;
|
||||
}
|
||||
|
||||
await makeTexture(albedoEl.files[0], albedoTex);
|
||||
|
||||
if (!noegramOk) {
|
||||
console.warn("cannot render, noegram.png not loaded yet");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("running frame");
|
||||
renderFrame();
|
||||
});
|
||||
})();
|
||||
</script>
|
BIN
-~-/pfp/noegram.png
Normal file
BIN
-~-/pfp/noegram.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
Loading…
Add table
Reference in a new issue