More cleanup

This commit is contained in:
Rezmason
2020-01-22 13:02:08 -08:00
parent cadd769b63
commit 05933a5dda
6 changed files with 113 additions and 130 deletions

View File

@@ -42,7 +42,7 @@
import { import {
loadImages, loadImages,
makeFullScreenQuad, makeFullScreenQuad,
makePalette make1DTexture
} from "./js/utils.js"; } from "./js/utils.js";
import makeConfig from "./js/config.js"; import makeConfig from "./js/config.js";
import makeMatrixRenderer from "./js/renderer.js"; import makeMatrixRenderer from "./js/renderer.js";
@@ -67,7 +67,7 @@
}); });
const [config, uniforms] = makeConfig(window.location.search, data => const [config, uniforms] = makeConfig(window.location.search, data =>
makePalette(regl, data) make1DTexture(regl, data)
); );
const resize = () => { const resize = () => {

View File

@@ -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. // The bloom pass is basically an added high-pass blur.
@@ -11,32 +11,30 @@ const levelStrengths = Array(pyramidHeight)
.reverse(); .reverse();
export default (regl, config, input) => { export default (regl, config, input) => {
if (config.effect === "none") { if (!config.performBloom) {
return { return makePass(input, null, null);
output: input,
resize: () => {},
render: () => {}
};
} }
const highPassPyramid = makePyramid(regl, pyramidHeight); const highPassPyramid = makePyramid(regl, pyramidHeight);
const horizontalBlurPyramid = makePyramid(regl, pyramidHeight); const hBlurPyramid = makePyramid(regl, pyramidHeight);
const verticalBlurPyramid = makePyramid(regl, pyramidHeight); const vBlurPyramid = makePyramid(regl, pyramidHeight);
const output = makePassFBO(regl); const output = makePassFBO(regl);
// The high pass restricts the blur to bright things in our input texture. // The high pass restricts the blur to bright things in our input texture.
const highPass = regl({ const highPass = regl({
frag: ` frag: `
#define lumaMag vec3(0.2126, 0.7152, 0.0722)
precision mediump float; precision mediump float;
varying vec2 vUV; varying vec2 vUV;
uniform sampler2D tex; uniform sampler2D tex;
uniform float highPassThreshold; uniform float highPassThreshold;
void main() { void main() {
float value = texture2D(tex, vUV).r; vec3 lumaColor = texture2D(tex, vUV).rgb * lumaMag;
if (value < highPassThreshold) { float luma = lumaColor.r + lumaColor.g + lumaColor.b;
value = 0.; if (luma < highPassThreshold) {
luma = 0.;
} }
gl_FragColor = vec4(vec3(value), 1.0); gl_FragColor = vec4(vec3(luma), 1.0);
} }
`, `,
uniforms: { uniforms: {
@@ -79,70 +77,51 @@ export default (regl, config, input) => {
frag: ` frag: `
precision mediump float; precision mediump float;
varying vec2 vUV; varying vec2 vUV;
${verticalBlurPyramid ${vBlurPyramid
.map((_, index) => `uniform sampler2D tex_${index};`) .map((_, index) => `uniform sampler2D pyr_${index};`)
.join("\n")} .join("\n")}
uniform sampler2D tex; uniform sampler2D tex;
uniform float bloomStrength; uniform float bloomStrength;
void main() { void main() {
vec4 total = vec4(0.); vec4 total = vec4(0.);
${verticalBlurPyramid ${vBlurPyramid
.map( .map(
(_, index) => (_, index) =>
`total += texture2D(tex_${index}, vUV) * ${levelStrengths[index]};` `total += texture2D(pyr_${index}, vUV) * ${levelStrengths[index]};`
) )
.join("\n")} .join("\n")}
gl_FragColor = total * bloomStrength + texture2D(tex, vUV); gl_FragColor = total * bloomStrength + texture2D(tex, vUV);
} }
`, `,
uniforms: Object.assign( uniforms: {
{ tex: input,
tex: input ...Object.fromEntries(
}, vBlurPyramid.map((fbo, index) => [`pyr_${index}`, fbo])
Object.fromEntries(
verticalBlurPyramid.map((fbo, index) => [`tex_${index}`, fbo])
) )
), },
framebuffer: output framebuffer: output
}); });
return { const scale = config.bloomSize;
return makePass(
output, 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 })); highPassPyramid.forEach(fbo => highPass({ fbo, tex: input }));
horizontalBlurPyramid.forEach((fbo, index) => hBlurPyramid.forEach((fbo, index) =>
blur({ fbo, tex: highPassPyramid[index], direction: [1, 0] }) blur({ fbo, tex: highPassPyramid[index], direction: [1, 0] })
); );
verticalBlurPyramid.forEach((fbo, index) => vBlurPyramid.forEach((fbo, index) =>
blur({ blur({ fbo, tex: hBlurPyramid[index], direction: [0, 1] })
fbo,
tex: horizontalBlurPyramid[index],
direction: [0, 1]
})
); );
combineBloom(); 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);
} }
}; );
}; };

View File

@@ -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. const colorizeByPalette = (regl, uniforms, framebuffer) =>
// A little noise is introduced, to hide the banding that appears // The rendered texture's values are mapped to colors in a palette texture.
// in subtle gradients. The noise is also time-driven, so its grain // A little noise is introduced, to hide the banding that appears
// won't persist across subsequent frames. This is a safe trick // in subtle gradients. The noise is also time-driven, so its grain
// in screen space. // won't persist across subsequent frames. This is a safe trick
// in screen space.
const colorizeByPalette = regl =>
regl({ regl({
frag: ` frag: `
precision mediump float; precision mediump float;
#define PI 3.14159265359 #define PI 3.14159265359
uniform sampler2D tex; uniform sampler2D tex;
uniform sampler2D paletteColorData; uniform sampler2D palette;
uniform float ditherMagnitude; uniform float ditherMagnitude;
uniform float time; uniform float time;
varying vec2 vUV; varying vec2 vUV;
@@ -25,23 +24,26 @@ const colorizeByPalette = regl =>
} }
void main() { 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: {
...uniforms,
ditherMagnitude: 0.05 ditherMagnitude: 0.05
} },
framebuffer
}); });
const colorizeByStripes = regl => const colorizeByStripes = (regl, uniforms, framebuffer) =>
regl({ regl({
frag: ` frag: `
precision mediump float; precision mediump float;
#define PI 3.14159265359 #define PI 3.14159265359
uniform sampler2D tex; uniform sampler2D tex;
uniform sampler2D stripeColorData; uniform sampler2D stripes;
uniform float ditherMagnitude; uniform float ditherMagnitude;
varying vec2 vUV; varying vec2 vUV;
@@ -52,18 +54,20 @@ const colorizeByStripes = regl =>
} }
void main() { void main() {
float value = texture2D(tex, vUV).r; vec3 color = texture2D(stripes, vUV).rgb - rand( gl_FragCoord.xy ) * ditherMagnitude;
vec3 value2 = texture2D(stripeColorData, vUV).rgb - rand( gl_FragCoord.xy ) * ditherMagnitude; float brightness = texture2D(tex, vUV).r;
gl_FragColor = vec4(value2 * value, 1.0); gl_FragColor = vec4(color * brightness, 1.0);
} }
`, `,
uniforms: { uniforms: {
...uniforms,
ditherMagnitude: 0.1 ditherMagnitude: 0.1
} },
framebuffer
}); });
const colorizeByImage = (regl, bgTex) => const colorizeByImage = (regl, uniforms, framebuffer) =>
regl({ regl({
frag: ` frag: `
precision mediump float; precision mediump float;
@@ -72,12 +76,13 @@ const colorizeByImage = (regl, bgTex) =>
varying vec2 vUV; varying vec2 vUV;
void main() { 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: { uniforms,
bgTex framebuffer
}
}); });
const colorizersByEffect = { const colorizersByEffect = {
@@ -89,36 +94,19 @@ const colorizersByEffect = {
export default (regl, config, { bgTex }, input) => { export default (regl, config, { bgTex }, input) => {
if (config.effect === "none") { if (config.effect === "none") {
return { return makePass(input, null, null);
output: input, }
resize: () => {},
render: () => {} if (bgTex == null) {
}; bgTex = 0;
} }
const output = makePassFBO(regl); const output = makePassFBO(regl);
const colorize = regl({ return makePass(
uniforms: {
tex: regl.prop("tex")
},
framebuffer: output
});
const colorizer = (config.effect in colorizersByEffect
? colorizersByEffect[config.effect]
: colorizeByPalette)(regl, bgTex);
return {
output, output,
resize: output.resize, (config.effect in colorizersByEffect
render: resources => { ? colorizersByEffect[config.effect]
colorize( : colorizeByPalette)(regl, { bgTex, tex: input }, output)
{ );
tex: input
},
() => colorizer(resources)
);
}
};
}; };

View File

@@ -38,7 +38,7 @@ const versions = {
rippleScale: 30, rippleScale: 30,
rippleSpeed: 0.1, rippleSpeed: 0.1,
numColumns: 30, numColumns: 30,
palette: [ paletteEntries: [
{ rgb: [0.0, 0.0, 0.0], at: 0.0 }, { rgb: [0.0, 0.0, 0.0], at: 0.0 },
{ rgb: [0.52, 0.17, 0.05], at: 0.4 }, { rgb: [0.52, 0.17, 0.05], at: 0.4 },
{ rgb: [0.82, 0.37, 0.12], at: 0.7 }, { rgb: [0.82, 0.37, 0.12], at: 0.7 },
@@ -69,7 +69,7 @@ const versions = {
rippleScale: 30, rippleScale: 30,
rippleSpeed: 0.2, rippleSpeed: 0.2,
numColumns: 60, numColumns: 60,
palette: [ paletteEntries: [
{ rgb: [0.0, 0.0, 0.0], at: 0.0 }, { rgb: [0.0, 0.0, 0.0], at: 0.0 },
{ rgb: [0.32, 0.06, 0.0], at: 0.2 }, { rgb: [0.32, 0.06, 0.0], at: 0.2 },
{ rgb: [0.82, 0.06, 0.05], at: 0.4 }, { rgb: [0.82, 0.06, 0.05], at: 0.4 },
@@ -100,7 +100,7 @@ const versions = {
rippleScale: 30, rippleScale: 30,
rippleSpeed: 0.2, rippleSpeed: 0.2,
numColumns: 80, numColumns: 80,
palette: [ paletteEntries: [
{ rgb: [0 / 255, 0 / 255, 0 / 255], at: 0 / 16 }, { rgb: [0 / 255, 0 / 255, 0 / 255], at: 0 / 16 },
{ rgb: [6 / 255, 16 / 255, 8 / 255], at: 1 / 16 }, { rgb: [6 / 255, 16 / 255, 8 / 255], at: 1 / 16 },
{ rgb: [11 / 255, 28 / 255, 15 / 255], at: 2 / 16 }, { rgb: [11 / 255, 28 / 255, 15 / 255], at: 2 / 16 },
@@ -143,7 +143,7 @@ const versions = {
rippleScale: 30, rippleScale: 30,
rippleSpeed: 0.2, rippleSpeed: 0.2,
numColumns: 108, numColumns: 108,
palette: [ paletteEntries: [
{ rgb: [0.0, 0.0, 0.0], at: 0.0 }, { rgb: [0.0, 0.0, 0.0], at: 0.0 },
{ rgb: [0.18, 0.9, 0.35], at: 0.6 }, { rgb: [0.18, 0.9, 0.35], at: 0.6 },
{ rgb: [0.9, 1.0, 0.9], at: 1.0 } { rgb: [0.9, 1.0, 0.9], at: 1.0 }
@@ -155,7 +155,7 @@ const versions = {
versions.throwback = versions.operator; versions.throwback = versions.operator;
versions["1999"] = versions.classic; versions["1999"] = versions.classic;
export default (searchString, makePaletteTexture) => { export default (searchString, make1DTexture) => {
const urlParams = new URLSearchParams(searchString); const urlParams = new URLSearchParams(searchString);
const getParam = (keyOrKeys, defaultValue) => { const getParam = (keyOrKeys, defaultValue) => {
if (Array.isArray(keyOrKeys)) { if (Array.isArray(keyOrKeys)) {
@@ -215,6 +215,11 @@ export default (searchString, makePaletteTexture) => {
.split(",") .split(",")
.map(parseFloat); .map(parseFloat);
config.showComputationTexture = config.effect === "none"; 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) { switch (config.cycleStyleName) {
case "cycleFasterWhenDimmed": case "cycleFasterWhenDimmed":
@@ -239,7 +244,7 @@ export default (searchString, makePaletteTexture) => {
const PALETTE_SIZE = 2048; const PALETTE_SIZE = 2048;
const paletteColors = Array(PALETTE_SIZE); const paletteColors = Array(PALETTE_SIZE);
const sortedEntries = version.palette const sortedEntries = version.paletteEntries
.slice() .slice()
.sort((e1, e2) => e1.at - e2.at) .sort((e1, e2) => e1.at - e2.at)
.map(entry => ({ .map(entry => ({
@@ -269,9 +274,7 @@ export default (searchString, makePaletteTexture) => {
} }
}); });
config.paletteColorData = makePaletteTexture( config.palette = make1DTexture(paletteColors.flat().map(i => i * 0xff));
paletteColors.flat().map(i => i * 0xff)
);
let stripeColors = [0, 0, 0]; let stripeColors = [0, 0, 0];
@@ -292,9 +295,7 @@ export default (searchString, makePaletteTexture) => {
stripeColors = config.customStripes.slice(0, numFlagColors * 3); stripeColors = config.customStripes.slice(0, numFlagColors * 3);
} }
config.stripeColorData = makePaletteTexture( config.stripes = make1DTexture(stripeColors.map(f => Math.floor(f * 0xff)));
stripeColors.map(f => Math.floor(f * 0xff))
);
const uniforms = Object.fromEntries( const uniforms = Object.fromEntries(
Object.entries(config).filter(([key, value]) => { Object.entries(config).filter(([key, value]) => {

View File

@@ -1,4 +1,4 @@
import { makePassFBO, makeDoubleBuffer } from "./utils.js"; import { makePassFBO, makeDoubleBuffer, makePass } from "./utils.js";
export default (regl, config, { msdfTex }) => { export default (regl, config, { msdfTex }) => {
// These two framebuffers are used to compute the raining code. // These two framebuffers are used to compute the raining code.
@@ -292,12 +292,8 @@ export default (regl, config, { msdfTex }) => {
framebuffer: output framebuffer: output
}); });
return { return makePass(output, resources => {
resize: output.resize, update();
output, render(resources);
render: resources => { });
update();
render(resources);
}
};
}; };

View File

@@ -99,7 +99,7 @@ const makeFullScreenQuad = (regl, uniforms = {}, context = {}) =>
count: 3 count: 3
}); });
const makePalette = (regl, data) => const make1DTexture = (regl, data) =>
regl.texture({ regl.texture({
data, data,
width: data.length / 3, width: data.length / 3,
@@ -109,6 +109,24 @@ const makePalette = (regl, data) =>
min: "linear" 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 { export {
makePassTexture, makePassTexture,
makePassFBO, makePassFBO,
@@ -118,5 +136,6 @@ export {
loadImage, loadImage,
loadImages, loadImages,
makeFullScreenQuad, makeFullScreenQuad,
makePalette make1DTexture,
makePass
}; };