More cleanup

This commit is contained in:
Rezmason
2020-01-22 08:31:13 -08:00
parent 1d629a20c4
commit cadd769b63
6 changed files with 75 additions and 71 deletions

View File

@@ -70,17 +70,6 @@
makePalette(regl, data)
);
// All this takes place in a full screen quad.
const fullScreenQuad = makeFullScreenQuad(regl, uniforms);
const renderer = makeMatrixRenderer(regl, config);
const bloomPass = makeBloomPass(regl, config, renderer.fbo);
const colorPass = makeColorPass(regl, config, bloomPass.fbo);
const drawToScreen = regl({
uniforms: {
tex: colorPass.fbo
}
});
const resize = () => {
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
@@ -88,27 +77,29 @@
window.onresize = resize;
resize();
fullScreenQuad(renderer.update);
document.body.onload = async () => {
const resources = await loadImages(regl, {
const images = await loadImages(regl, {
msdfTex: config.glyphTexURL,
backgroundTex:
config.effect === "image" ? config.backgroundImage : null
bgTex: config.effect === "image" ? config.bgURL : null
});
const loop = regl.frame(({ viewportWidth, viewportHeight }) => {
// All the FBOs except the compute FBOs need to be sized to the window.
renderer.resize(viewportWidth, viewportHeight);
bloomPass.resize(viewportWidth, viewportHeight);
colorPass.resize(viewportWidth, viewportHeight);
// All this takes place in a full screen quad.
const fullScreenQuad = makeFullScreenQuad(regl, uniforms);
const renderer = makeMatrixRenderer(regl, config, images);
const bloomPass = makeBloomPass(regl, config, renderer.output);
const colorPass = makeColorPass(regl, config, images, bloomPass.output);
const drawToScreen = regl({
uniforms: {
tex: colorPass.output
}
});
// And here is the full draw sequence.
const passes = [renderer, bloomPass, colorPass];
const loop = regl.frame(({ viewportWidth, viewportHeight }) => {
passes.forEach(pass => pass.resize(viewportWidth, viewportHeight));
fullScreenQuad(() => {
renderer.update();
renderer.render(resources);
bloomPass.render();
colorPass.render(resources);
passes.forEach(pass => pass.render());
drawToScreen();
});
});

View File

@@ -13,7 +13,7 @@ const levelStrengths = Array(pyramidHeight)
export default (regl, config, input) => {
if (config.effect === "none") {
return {
fbo: input,
output: input,
resize: () => {},
render: () => {}
};
@@ -22,7 +22,7 @@ export default (regl, config, input) => {
const highPassPyramid = makePyramid(regl, pyramidHeight);
const horizontalBlurPyramid = makePyramid(regl, pyramidHeight);
const verticalBlurPyramid = makePyramid(regl, pyramidHeight);
const fbo = makePassFBO(regl);
const output = makePassFBO(regl);
// The high pass restricts the blur to bright things in our input texture.
const highPass = regl({
@@ -103,11 +103,11 @@ export default (regl, config, input) => {
verticalBlurPyramid.map((fbo, index) => [`tex_${index}`, fbo])
)
),
framebuffer: fbo
framebuffer: output
});
return {
fbo,
output,
resize: (viewportWidth, viewportHeight) => {
// The blur pyramids can be lower resolution than the screen.
resizePyramid(
@@ -128,7 +128,7 @@ export default (regl, config, input) => {
viewportHeight,
config.bloomSize
);
fbo.resize(viewportWidth, viewportHeight);
output.resize(viewportWidth, viewportHeight);
},
render: () => {
highPassPyramid.forEach(fbo => highPass({ fbo, tex: input }));

View File

@@ -63,20 +63,20 @@ const colorizeByStripes = regl =>
}
});
const colorizeByImage = regl =>
const colorizeByImage = (regl, bgTex) =>
regl({
frag: `
precision mediump float;
uniform sampler2D tex;
uniform sampler2D backgroundTex;
uniform sampler2D bgTex;
varying vec2 vUV;
void main() {
gl_FragColor = vec4(texture2D(backgroundTex, vUV).rgb * (pow(texture2D(tex, vUV).r, 1.5) * 0.995 + 0.005), 1.0);
gl_FragColor = vec4(texture2D(bgTex, vUV).rgb * (pow(texture2D(tex, vUV).r, 1.5) * 0.995 + 0.005), 1.0);
}
`,
uniforms: {
backgroundTex: regl.prop("backgroundTex")
bgTex
}
});
@@ -87,35 +87,35 @@ const colorizersByEffect = {
image: colorizeByImage
};
export default (regl, config, inputFBO) => {
const fbo = makePassFBO(regl);
export default (regl, config, { bgTex }, input) => {
if (config.effect === "none") {
return {
fbo: inputFBO,
output: input,
resize: () => {},
render: () => {}
};
}
const output = makePassFBO(regl);
const colorize = regl({
uniforms: {
tex: regl.prop("tex")
},
framebuffer: fbo
framebuffer: output
});
const colorizer = (config.effect in colorizersByEffect
? colorizersByEffect[config.effect]
: colorizeByPalette)(regl);
: colorizeByPalette)(regl, bgTex);
return {
fbo,
resize: fbo.resize,
output,
resize: output.resize,
render: resources => {
colorize(
{
tex: inputFBO
tex: input
},
() => colorizer(resources)
);

View File

@@ -204,7 +204,7 @@ export default (searchString, makePaletteTexture) => {
config.animationSpeed * config.fallSpeed == 0
? 1
: Math.min(1, Math.abs(config.animationSpeed * config.fallSpeed));
config.backgroundImage = getParam(
config.bgURL = getParam(
"url",
"https://upload.wikimedia.org/wikipedia/commons/0/0a/Flammarion_Colored.jpg"
);

View File

@@ -1,27 +1,20 @@
import { makePassFBO } from "./utils.js";
import { makePassFBO, makeDoubleBuffer } from "./utils.js";
export default (regl, config) => {
export default (regl, config, { msdfTex }) => {
// These two framebuffers are used to compute the raining code.
// they take turns being the source and destination of the "compute" shader.
// The half float data type is crucial! It lets us store almost any real number,
// whereas the default type limits us to integers between 0 and 255.
// These FBOs are smaller than the screen, because their pixels correspond
// This double buffer is smaller than the screen, because its pixels correspond
// with glyphs in the final image, and the glyphs are much larger than a pixel.
const state = Array(2)
.fill()
.map(() =>
regl.framebuffer({
color: regl.texture({
radius: config.numColumns,
wrapT: "clamp",
type: "half float"
}),
depthStencil: false
})
);
const doubleBuffer = makeDoubleBuffer(regl, {
radius: config.numColumns,
wrapT: "clamp",
type: "half float"
});
const fbo = makePassFBO(regl);
const output = makePassFBO(regl);
const update = regl({
frag: `
@@ -195,10 +188,10 @@ export default (regl, config) => {
`,
uniforms: {
lastState: ({ tick }) => state[tick % 2]
lastState: doubleBuffer.back
},
framebuffer: ({ tick }) => state[(tick + 1) % 2] // The crucial state FBO alternator
framebuffer: doubleBuffer.front
});
// We render the code into an FBO using MSDFs: https://github.com/Chlumsky/msdfgen
@@ -290,19 +283,21 @@ export default (regl, config) => {
`,
uniforms: {
msdfTex: regl.prop("msdfTex"),
msdfTex,
height: regl.context("viewportWidth"),
width: regl.context("viewportHeight"),
lastState: ({ tick }) => state[tick % 2]
lastState: doubleBuffer.front
},
framebuffer: fbo
framebuffer: output
});
return {
resize: fbo.resize,
fbo,
update,
render
resize: output.resize,
output,
render: resources => {
update();
render(resources);
}
};
};

View File

@@ -17,6 +17,21 @@ const makePyramid = (regl, height) =>
.fill()
.map(_ => makePassFBO(regl));
const makeDoubleBuffer = (regl, props) => {
const state = Array(2)
.fill()
.map(() =>
regl.framebuffer({
color: regl.texture(props),
depthStencil: false
})
);
return {
front: ({ tick }) => state[tick % 2],
back: ({ tick }) => state[(tick + 1) % 2]
};
};
const resizePyramid = (pyramid, vw, vh, scale) =>
pyramid.forEach((fbo, index) =>
fbo.resize(
@@ -48,7 +63,7 @@ const loadImage = async (regl, url) => {
});
};
const makeFullScreenQuad = (regl, uniforms) =>
const makeFullScreenQuad = (regl, uniforms = {}, context = {}) =>
regl({
vert: `
precision mediump float;
@@ -78,6 +93,8 @@ const makeFullScreenQuad = (regl, uniforms) =>
time: regl.context("time")
},
context,
depth: { enable: false },
count: 3
});
@@ -95,6 +112,7 @@ const makePalette = (regl, data) =>
export {
makePassTexture,
makePassFBO,
makeDoubleBuffer,
makePyramid,
resizePyramid,
loadImage,