diff --git a/index.html b/index.html
index da93878..c549116 100644
--- a/index.html
+++ b/index.html
@@ -42,7 +42,7 @@
import {
loadImages,
makeFullScreenQuad,
- makePalette
+ make1DTexture
} from "./js/utils.js";
import makeConfig from "./js/config.js";
import makeMatrixRenderer from "./js/renderer.js";
@@ -67,7 +67,7 @@
});
const [config, uniforms] = makeConfig(window.location.search, data =>
- makePalette(regl, data)
+ make1DTexture(regl, data)
);
const resize = () => {
diff --git a/js/bloomPass.js b/js/bloomPass.js
index f88a799..0913a63 100644
--- a/js/bloomPass.js
+++ b/js/bloomPass.js
@@ -1,4 +1,4 @@
-import { makePassFBO, makePyramid, resizePyramid } from "./utils.js";
+import { makePassFBO, makePyramid, resizePyramid, makePass } from "./utils.js";
// The bloom pass is basically an added high-pass blur.
@@ -11,32 +11,30 @@ const levelStrengths = Array(pyramidHeight)
.reverse();
export default (regl, config, input) => {
- if (config.effect === "none") {
- return {
- output: input,
- resize: () => {},
- render: () => {}
- };
+ if (!config.performBloom) {
+ return makePass(input, null, null);
}
const highPassPyramid = makePyramid(regl, pyramidHeight);
- const horizontalBlurPyramid = makePyramid(regl, pyramidHeight);
- const verticalBlurPyramid = makePyramid(regl, pyramidHeight);
+ const hBlurPyramid = makePyramid(regl, pyramidHeight);
+ const vBlurPyramid = makePyramid(regl, pyramidHeight);
const output = makePassFBO(regl);
// The high pass restricts the blur to bright things in our input texture.
const highPass = regl({
frag: `
+ #define lumaMag vec3(0.2126, 0.7152, 0.0722)
precision mediump float;
varying vec2 vUV;
uniform sampler2D tex;
uniform float highPassThreshold;
void main() {
- float value = texture2D(tex, vUV).r;
- if (value < highPassThreshold) {
- value = 0.;
+ vec3 lumaColor = texture2D(tex, vUV).rgb * lumaMag;
+ float luma = lumaColor.r + lumaColor.g + lumaColor.b;
+ if (luma < highPassThreshold) {
+ luma = 0.;
}
- gl_FragColor = vec4(vec3(value), 1.0);
+ gl_FragColor = vec4(vec3(luma), 1.0);
}
`,
uniforms: {
@@ -79,70 +77,51 @@ export default (regl, config, input) => {
frag: `
precision mediump float;
varying vec2 vUV;
- ${verticalBlurPyramid
- .map((_, index) => `uniform sampler2D tex_${index};`)
+ ${vBlurPyramid
+ .map((_, index) => `uniform sampler2D pyr_${index};`)
.join("\n")}
uniform sampler2D tex;
uniform float bloomStrength;
void main() {
vec4 total = vec4(0.);
- ${verticalBlurPyramid
+ ${vBlurPyramid
.map(
(_, index) =>
- `total += texture2D(tex_${index}, vUV) * ${levelStrengths[index]};`
+ `total += texture2D(pyr_${index}, vUV) * ${levelStrengths[index]};`
)
.join("\n")}
gl_FragColor = total * bloomStrength + texture2D(tex, vUV);
}
`,
- uniforms: Object.assign(
- {
- tex: input
- },
- Object.fromEntries(
- verticalBlurPyramid.map((fbo, index) => [`tex_${index}`, fbo])
+ uniforms: {
+ tex: input,
+ ...Object.fromEntries(
+ vBlurPyramid.map((fbo, index) => [`pyr_${index}`, fbo])
)
- ),
+ },
framebuffer: output
});
- return {
+ const scale = config.bloomSize;
+
+ return makePass(
output,
- resize: (viewportWidth, viewportHeight) => {
- // The blur pyramids can be lower resolution than the screen.
- resizePyramid(
- highPassPyramid,
- viewportWidth,
- viewportHeight,
- config.bloomSize
- );
- resizePyramid(
- horizontalBlurPyramid,
- viewportWidth,
- viewportHeight,
- config.bloomSize
- );
- resizePyramid(
- verticalBlurPyramid,
- viewportWidth,
- viewportHeight,
- config.bloomSize
- );
- output.resize(viewportWidth, viewportHeight);
- },
- render: () => {
+ () => {
highPassPyramid.forEach(fbo => highPass({ fbo, tex: input }));
- horizontalBlurPyramid.forEach((fbo, index) =>
+ hBlurPyramid.forEach((fbo, index) =>
blur({ fbo, tex: highPassPyramid[index], direction: [1, 0] })
);
- verticalBlurPyramid.forEach((fbo, index) =>
- blur({
- fbo,
- tex: horizontalBlurPyramid[index],
- direction: [0, 1]
- })
+ vBlurPyramid.forEach((fbo, index) =>
+ blur({ fbo, tex: hBlurPyramid[index], direction: [0, 1] })
);
combineBloom();
+ },
+ (w, h) => {
+ // The blur pyramids can be lower resolution than the screen.
+ resizePyramid(highPassPyramid, w, h, scale);
+ resizePyramid(hBlurPyramid, w, h, scale);
+ resizePyramid(vBlurPyramid, w, h, scale);
+ output.resize(w, h);
}
- };
+ );
};
diff --git a/js/colorPass.js b/js/colorPass.js
index c82213e..e121371 100644
--- a/js/colorPass.js
+++ b/js/colorPass.js
@@ -1,19 +1,18 @@
-import { makePassFBO } from "./utils.js";
+import { makePassFBO, makePass } from "./utils.js";
-// rendered texture's values are mapped to colors in a palette texture.
-// A little noise is introduced, to hide the banding that appears
-// in subtle gradients. The noise is also time-driven, so its grain
-// won't persist across subsequent frames. This is a safe trick
-// in screen space.
-
-const colorizeByPalette = regl =>
+const colorizeByPalette = (regl, uniforms, framebuffer) =>
+ // The rendered texture's values are mapped to colors in a palette texture.
+ // A little noise is introduced, to hide the banding that appears
+ // in subtle gradients. The noise is also time-driven, so its grain
+ // won't persist across subsequent frames. This is a safe trick
+ // in screen space.
regl({
frag: `
precision mediump float;
#define PI 3.14159265359
uniform sampler2D tex;
- uniform sampler2D paletteColorData;
+ uniform sampler2D palette;
uniform float ditherMagnitude;
uniform float time;
varying vec2 vUV;
@@ -25,23 +24,26 @@ const colorizeByPalette = regl =>
}
void main() {
- gl_FragColor = texture2D( paletteColorData, vec2( texture2D( tex, vUV ).r - rand( gl_FragCoord.xy, time ) * ditherMagnitude, 0.0 ) );
+ float at = texture2D( tex, vUV ).r - rand( gl_FragCoord.xy, time ) * ditherMagnitude;
+ gl_FragColor = texture2D( palette, vec2(at, 0.0));
}
`,
uniforms: {
+ ...uniforms,
ditherMagnitude: 0.05
- }
+ },
+ framebuffer
});
-const colorizeByStripes = regl =>
+const colorizeByStripes = (regl, uniforms, framebuffer) =>
regl({
frag: `
precision mediump float;
#define PI 3.14159265359
uniform sampler2D tex;
- uniform sampler2D stripeColorData;
+ uniform sampler2D stripes;
uniform float ditherMagnitude;
varying vec2 vUV;
@@ -52,18 +54,20 @@ const colorizeByStripes = regl =>
}
void main() {
- float value = texture2D(tex, vUV).r;
- vec3 value2 = texture2D(stripeColorData, vUV).rgb - rand( gl_FragCoord.xy ) * ditherMagnitude;
- gl_FragColor = vec4(value2 * value, 1.0);
+ vec3 color = texture2D(stripes, vUV).rgb - rand( gl_FragCoord.xy ) * ditherMagnitude;
+ float brightness = texture2D(tex, vUV).r;
+ gl_FragColor = vec4(color * brightness, 1.0);
}
`,
uniforms: {
+ ...uniforms,
ditherMagnitude: 0.1
- }
+ },
+ framebuffer
});
-const colorizeByImage = (regl, bgTex) =>
+const colorizeByImage = (regl, uniforms, framebuffer) =>
regl({
frag: `
precision mediump float;
@@ -72,12 +76,13 @@ const colorizeByImage = (regl, bgTex) =>
varying vec2 vUV;
void main() {
- gl_FragColor = vec4(texture2D(bgTex, vUV).rgb * (pow(texture2D(tex, vUV).r, 1.5) * 0.995 + 0.005), 1.0);
+ vec3 bgColor = texture2D(bgTex, vUV).rgb;
+ float brightness = pow(texture2D(tex, vUV).r, 1.5);
+ gl_FragColor = vec4(bgColor * brightness, 1.0);
}
`,
- uniforms: {
- bgTex
- }
+ uniforms,
+ framebuffer
});
const colorizersByEffect = {
@@ -89,36 +94,19 @@ const colorizersByEffect = {
export default (regl, config, { bgTex }, input) => {
if (config.effect === "none") {
- return {
- output: input,
- resize: () => {},
- render: () => {}
- };
+ return makePass(input, null, null);
+ }
+
+ if (bgTex == null) {
+ bgTex = 0;
}
const output = makePassFBO(regl);
- const colorize = regl({
- uniforms: {
- tex: regl.prop("tex")
- },
- framebuffer: output
- });
-
- const colorizer = (config.effect in colorizersByEffect
- ? colorizersByEffect[config.effect]
- : colorizeByPalette)(regl, bgTex);
-
- return {
+ return makePass(
output,
- resize: output.resize,
- render: resources => {
- colorize(
- {
- tex: input
- },
- () => colorizer(resources)
- );
- }
- };
+ (config.effect in colorizersByEffect
+ ? colorizersByEffect[config.effect]
+ : colorizeByPalette)(regl, { bgTex, tex: input }, output)
+ );
};
diff --git a/js/config.js b/js/config.js
index 6078ca6..43cc399 100644
--- a/js/config.js
+++ b/js/config.js
@@ -38,7 +38,7 @@ const versions = {
rippleScale: 30,
rippleSpeed: 0.1,
numColumns: 30,
- palette: [
+ paletteEntries: [
{ rgb: [0.0, 0.0, 0.0], at: 0.0 },
{ rgb: [0.52, 0.17, 0.05], at: 0.4 },
{ rgb: [0.82, 0.37, 0.12], at: 0.7 },
@@ -69,7 +69,7 @@ const versions = {
rippleScale: 30,
rippleSpeed: 0.2,
numColumns: 60,
- palette: [
+ paletteEntries: [
{ rgb: [0.0, 0.0, 0.0], at: 0.0 },
{ rgb: [0.32, 0.06, 0.0], at: 0.2 },
{ rgb: [0.82, 0.06, 0.05], at: 0.4 },
@@ -100,7 +100,7 @@ const versions = {
rippleScale: 30,
rippleSpeed: 0.2,
numColumns: 80,
- palette: [
+ paletteEntries: [
{ rgb: [0 / 255, 0 / 255, 0 / 255], at: 0 / 16 },
{ rgb: [6 / 255, 16 / 255, 8 / 255], at: 1 / 16 },
{ rgb: [11 / 255, 28 / 255, 15 / 255], at: 2 / 16 },
@@ -143,7 +143,7 @@ const versions = {
rippleScale: 30,
rippleSpeed: 0.2,
numColumns: 108,
- palette: [
+ paletteEntries: [
{ rgb: [0.0, 0.0, 0.0], at: 0.0 },
{ rgb: [0.18, 0.9, 0.35], at: 0.6 },
{ rgb: [0.9, 1.0, 0.9], at: 1.0 }
@@ -155,7 +155,7 @@ const versions = {
versions.throwback = versions.operator;
versions["1999"] = versions.classic;
-export default (searchString, makePaletteTexture) => {
+export default (searchString, make1DTexture) => {
const urlParams = new URLSearchParams(searchString);
const getParam = (keyOrKeys, defaultValue) => {
if (Array.isArray(keyOrKeys)) {
@@ -215,6 +215,11 @@ export default (searchString, makePaletteTexture) => {
.split(",")
.map(parseFloat);
config.showComputationTexture = config.effect === "none";
+ config.performBloom =
+ config.effect !== "none" &&
+ config.bloomSize > 0 &&
+ config.bloomStrength > 0;
+ console.log(config.effect, config.bloomSize, config.bloomStrength);
switch (config.cycleStyleName) {
case "cycleFasterWhenDimmed":
@@ -239,7 +244,7 @@ export default (searchString, makePaletteTexture) => {
const PALETTE_SIZE = 2048;
const paletteColors = Array(PALETTE_SIZE);
- const sortedEntries = version.palette
+ const sortedEntries = version.paletteEntries
.slice()
.sort((e1, e2) => e1.at - e2.at)
.map(entry => ({
@@ -269,9 +274,7 @@ export default (searchString, makePaletteTexture) => {
}
});
- config.paletteColorData = makePaletteTexture(
- paletteColors.flat().map(i => i * 0xff)
- );
+ config.palette = make1DTexture(paletteColors.flat().map(i => i * 0xff));
let stripeColors = [0, 0, 0];
@@ -292,9 +295,7 @@ export default (searchString, makePaletteTexture) => {
stripeColors = config.customStripes.slice(0, numFlagColors * 3);
}
- config.stripeColorData = makePaletteTexture(
- stripeColors.map(f => Math.floor(f * 0xff))
- );
+ config.stripes = make1DTexture(stripeColors.map(f => Math.floor(f * 0xff)));
const uniforms = Object.fromEntries(
Object.entries(config).filter(([key, value]) => {
diff --git a/js/renderer.js b/js/renderer.js
index 476bdb9..b3e9ce4 100644
--- a/js/renderer.js
+++ b/js/renderer.js
@@ -1,4 +1,4 @@
-import { makePassFBO, makeDoubleBuffer } from "./utils.js";
+import { makePassFBO, makeDoubleBuffer, makePass } from "./utils.js";
export default (regl, config, { msdfTex }) => {
// These two framebuffers are used to compute the raining code.
@@ -292,12 +292,8 @@ export default (regl, config, { msdfTex }) => {
framebuffer: output
});
- return {
- resize: output.resize,
- output,
- render: resources => {
- update();
- render(resources);
- }
- };
+ return makePass(output, resources => {
+ update();
+ render(resources);
+ });
};
diff --git a/js/utils.js b/js/utils.js
index 7b60316..5380184 100644
--- a/js/utils.js
+++ b/js/utils.js
@@ -99,7 +99,7 @@ const makeFullScreenQuad = (regl, uniforms = {}, context = {}) =>
count: 3
});
-const makePalette = (regl, data) =>
+const make1DTexture = (regl, data) =>
regl.texture({
data,
width: data.length / 3,
@@ -109,6 +109,24 @@ const makePalette = (regl, data) =>
min: "linear"
});
+const makePass = (output, render, resize) => {
+ if (render == null) {
+ render = () => {};
+ }
+ if (resize === undefined) {
+ // "default" resize function is on the FBO
+ resize = (w, h) => output.resize(w, h);
+ }
+ if (resize == null) {
+ resize = () => {};
+ }
+ return {
+ output,
+ render,
+ resize
+ };
+};
+
export {
makePassTexture,
makePassFBO,
@@ -118,5 +136,6 @@ export {
loadImage,
loadImages,
makeFullScreenQuad,
- makePalette
+ make1DTexture,
+ makePass
};