mirror of
https://github.com/Rezmason/matrix.git
synced 2026-04-14 12:29:30 -07:00
More cleanup
This commit is contained in:
43
index.html
43
index.html
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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 }));
|
||||
|
||||
@@ -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)
|
||||
);
|
||||
|
||||
@@ -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"
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
20
js/utils.js
20
js/utils.js
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user