mirror of
https://github.com/Rezmason/matrix.git
synced 2026-04-18 22:29:28 -07:00
Unifying the interfaces of regl and webgpu makePass and makePipeline.
This commit is contained in:
@@ -9,7 +9,7 @@ const levelStrengths = Array(pyramidHeight)
|
|||||||
.map((_, index) => Math.pow(index / (pyramidHeight * 2) + 0.5, 1 / 3).toPrecision(5))
|
.map((_, index) => Math.pow(index / (pyramidHeight * 2) + 0.5, 1 / 3).toPrecision(5))
|
||||||
.reverse();
|
.reverse();
|
||||||
|
|
||||||
export default (regl, config, inputs) => {
|
export default ({ regl, config }, inputs) => {
|
||||||
const { bloomStrength, bloomSize, highPassThreshold } = config;
|
const { bloomStrength, bloomSize, highPassThreshold } = config;
|
||||||
const enabled = bloomSize > 0 && bloomStrength > 0;
|
const enabled = bloomSize > 0 && bloomStrength > 0;
|
||||||
|
|
||||||
@@ -80,6 +80,14 @@ export default (regl, config, inputs) => {
|
|||||||
primary: inputs.primary,
|
primary: inputs.primary,
|
||||||
bloom: output,
|
bloom: output,
|
||||||
},
|
},
|
||||||
|
Promise.all([highPassFrag.loaded, blurFrag.loaded]),
|
||||||
|
(w, h) => {
|
||||||
|
// The blur pyramids can be lower resolution than the screen.
|
||||||
|
resizePyramid(highPassPyramid, w, h, bloomSize);
|
||||||
|
resizePyramid(hBlurPyramid, w, h, bloomSize);
|
||||||
|
resizePyramid(vBlurPyramid, w, h, bloomSize);
|
||||||
|
output.resize(w, h);
|
||||||
|
},
|
||||||
() => {
|
() => {
|
||||||
for (let i = 0; i < pyramidHeight; i++) {
|
for (let i = 0; i < pyramidHeight; i++) {
|
||||||
const highPassFBO = highPassPyramid[i];
|
const highPassFBO = highPassPyramid[i];
|
||||||
@@ -91,14 +99,6 @@ export default (regl, config, inputs) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sumPyramid();
|
sumPyramid();
|
||||||
},
|
}
|
||||||
(w, h) => {
|
|
||||||
// The blur pyramids can be lower resolution than the screen.
|
|
||||||
resizePyramid(highPassPyramid, w, h, bloomSize);
|
|
||||||
resizePyramid(hBlurPyramid, w, h, bloomSize);
|
|
||||||
resizePyramid(vBlurPyramid, w, h, bloomSize);
|
|
||||||
output.resize(w, h);
|
|
||||||
},
|
|
||||||
[highPassFrag.loaded, blurFrag.loaded]
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { loadImage, loadText, makePassFBO, makePass } from "./utils.js";
|
|||||||
|
|
||||||
const defaultBGURL = "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Flammarion_Colored.jpg/917px-Flammarion_Colored.jpg";
|
const defaultBGURL = "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Flammarion_Colored.jpg/917px-Flammarion_Colored.jpg";
|
||||||
|
|
||||||
export default (regl, config, inputs) => {
|
export default ({ regl, config }, inputs) => {
|
||||||
const output = makePassFBO(regl, config.useHalfFloat);
|
const output = makePassFBO(regl, config.useHalfFloat);
|
||||||
const bgURL = "bgURL" in config ? config.bgURL : defaultBGURL;
|
const bgURL = "bgURL" in config ? config.bgURL : defaultBGURL;
|
||||||
const background = loadImage(regl, bgURL);
|
const background = loadImage(regl, bgURL);
|
||||||
@@ -22,8 +22,8 @@ export default (regl, config, inputs) => {
|
|||||||
{
|
{
|
||||||
primary: output,
|
primary: output,
|
||||||
},
|
},
|
||||||
() => render({ frag: imagePassFrag.text() }),
|
Promise.all([background.loaded, imagePassFrag.loaded]),
|
||||||
null,
|
(w, h) => output.resize(w, h),
|
||||||
[background.loaded, imagePassFrag.loaded]
|
() => render({ frag: imagePassFrag.text() })
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export default async (canvas, config) => {
|
|||||||
// All this takes place in a full screen quad.
|
// All this takes place in a full screen quad.
|
||||||
const fullScreenQuad = makeFullScreenQuad(regl);
|
const fullScreenQuad = makeFullScreenQuad(regl);
|
||||||
const effectName = config.effect in effects ? config.effect : "plain";
|
const effectName = config.effect in effects ? config.effect : "plain";
|
||||||
const pipeline = makePipeline([makeRain, makeBloomPass, effects[effectName]], (p) => p.outputs, regl, config);
|
const pipeline = makePipeline({ regl, config }, [makeRain, makeBloomPass, effects[effectName]]);
|
||||||
const screenUniforms = { tex: pipeline[pipeline.length - 1].outputs.primary };
|
const screenUniforms = { tex: pipeline[pipeline.length - 1].outputs.primary };
|
||||||
const drawToScreen = regl({ uniforms: screenUniforms });
|
const drawToScreen = regl({ uniforms: screenUniforms });
|
||||||
await Promise.all(pipeline.map((step) => step.ready));
|
await Promise.all(pipeline.map((step) => step.ready));
|
||||||
@@ -50,12 +50,12 @@ export default async (canvas, config) => {
|
|||||||
dimensions.width = viewportWidth;
|
dimensions.width = viewportWidth;
|
||||||
dimensions.height = viewportHeight;
|
dimensions.height = viewportHeight;
|
||||||
for (const step of pipeline) {
|
for (const step of pipeline) {
|
||||||
step.resize(viewportWidth, viewportHeight);
|
step.setSize(viewportWidth, viewportHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fullScreenQuad(() => {
|
fullScreenQuad(() => {
|
||||||
for (const step of pipeline) {
|
for (const step of pipeline) {
|
||||||
step.render();
|
step.execute();
|
||||||
}
|
}
|
||||||
drawToScreen();
|
drawToScreen();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ const makePalette = (regl, entries) => {
|
|||||||
// won't persist across subsequent frames. This is a safe trick
|
// won't persist across subsequent frames. This is a safe trick
|
||||||
// in screen space.
|
// in screen space.
|
||||||
|
|
||||||
export default (regl, config, inputs) => {
|
export default ({ regl, config }, inputs) => {
|
||||||
const output = makePassFBO(regl, config.useHalfFloat);
|
const output = makePassFBO(regl, config.useHalfFloat);
|
||||||
const palette = makePalette(regl, config.paletteEntries);
|
const palette = makePalette(regl, config.paletteEntries);
|
||||||
const { backgroundColor } = config;
|
const { backgroundColor } = config;
|
||||||
@@ -86,8 +86,8 @@ export default (regl, config, inputs) => {
|
|||||||
{
|
{
|
||||||
primary: output,
|
primary: output,
|
||||||
},
|
},
|
||||||
() => render({ frag: palettePassFrag.text() }),
|
palettePassFrag.loaded,
|
||||||
null,
|
(w, h) => output.resize(w, h),
|
||||||
palettePassFrag.loaded
|
() => render({ frag: palettePassFrag.text() })
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const blVert = [1, 0];
|
|||||||
const brVert = [1, 1];
|
const brVert = [1, 1];
|
||||||
const quadVertices = [tlVert, trVert, brVert, tlVert, brVert, blVert];
|
const quadVertices = [tlVert, trVert, brVert, tlVert, brVert, blVert];
|
||||||
|
|
||||||
export default (regl, config) => {
|
export default ({ regl, config }) => {
|
||||||
// The volumetric mode multiplies the number of columns
|
// The volumetric mode multiplies the number of columns
|
||||||
// to reach the desired density, and then overlaps them
|
// to reach the desired density, and then overlaps them
|
||||||
const volumetric = config.volumetric;
|
const volumetric = config.volumetric;
|
||||||
@@ -170,15 +170,7 @@ export default (regl, config) => {
|
|||||||
{
|
{
|
||||||
primary: output,
|
primary: output,
|
||||||
},
|
},
|
||||||
() => {
|
Promise.all([msdf.loaded, rainPassCompute.loaded, rainPassVert.loaded, rainPassFrag.loaded]),
|
||||||
compute({ frag: rainPassCompute.text() });
|
|
||||||
regl.clear({
|
|
||||||
depth: 1,
|
|
||||||
color: [0, 0, 0, 1],
|
|
||||||
framebuffer: output,
|
|
||||||
});
|
|
||||||
render({ camera, transform, screenSize, vert: rainPassVert.text(), frag: rainPassFrag.text() });
|
|
||||||
},
|
|
||||||
(w, h) => {
|
(w, h) => {
|
||||||
output.resize(w, h);
|
output.resize(w, h);
|
||||||
const aspectRatio = w / h;
|
const aspectRatio = w / h;
|
||||||
@@ -193,6 +185,14 @@ export default (regl, config) => {
|
|||||||
}
|
}
|
||||||
[screenSize[0], screenSize[1]] = aspectRatio > 1 ? [1, aspectRatio] : [1 / aspectRatio, 1];
|
[screenSize[0], screenSize[1]] = aspectRatio > 1 ? [1, aspectRatio] : [1 / aspectRatio, 1];
|
||||||
},
|
},
|
||||||
[msdf.loaded, rainPassCompute.loaded, rainPassVert.loaded, rainPassFrag.loaded]
|
() => {
|
||||||
|
compute({ frag: rainPassCompute.text() });
|
||||||
|
regl.clear({
|
||||||
|
depth: 1,
|
||||||
|
color: [0, 0, 0, 1],
|
||||||
|
framebuffer: output,
|
||||||
|
});
|
||||||
|
render({ camera, transform, screenSize, vert: rainPassVert.text(), frag: rainPassFrag.text() });
|
||||||
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { loadText, make1DTexture, makePassFBO, makePass } from "./utils.js";
|
|||||||
// Downward-flowing glyphs should be tinted slightly blue on top and golden on the bottom
|
// Downward-flowing glyphs should be tinted slightly blue on top and golden on the bottom
|
||||||
// Cheat a lens blur, interpolating between the texture and bloom at the edges
|
// Cheat a lens blur, interpolating between the texture and bloom at the edges
|
||||||
|
|
||||||
export default (regl, config, inputs) => {
|
export default ({ regl, config }, inputs) => {
|
||||||
const output = makePassFBO(regl, config.useHalfFloat);
|
const output = makePassFBO(regl, config.useHalfFloat);
|
||||||
const { backgroundColor } = config;
|
const { backgroundColor } = config;
|
||||||
const resurrectionPassFrag = loadText("shaders/glsl/resurrectionPass.frag.glsl");
|
const resurrectionPassFrag = loadText("shaders/glsl/resurrectionPass.frag.glsl");
|
||||||
@@ -29,8 +29,8 @@ export default (regl, config, inputs) => {
|
|||||||
{
|
{
|
||||||
primary: output,
|
primary: output,
|
||||||
},
|
},
|
||||||
() => render({ frag: resurrectionPassFrag.text() }),
|
resurrectionPassFrag.loaded,
|
||||||
null,
|
(w, h) => output.resize(w, h),
|
||||||
resurrectionPassFrag.loaded
|
() => render({ frag: resurrectionPassFrag.text() })
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ const prideStripeColors = [
|
|||||||
[0.8, 0, 1],
|
[0.8, 0, 1],
|
||||||
].flat();
|
].flat();
|
||||||
|
|
||||||
export default (regl, config, inputs) => {
|
export default ({ regl, config }, inputs) => {
|
||||||
const output = makePassFBO(regl, config.useHalfFloat);
|
const output = makePassFBO(regl, config.useHalfFloat);
|
||||||
|
|
||||||
const { backgroundColor } = config;
|
const { backgroundColor } = config;
|
||||||
@@ -61,8 +61,8 @@ export default (regl, config, inputs) => {
|
|||||||
{
|
{
|
||||||
primary: output,
|
primary: output,
|
||||||
},
|
},
|
||||||
() => render({ frag: stripePassFrag.text() }),
|
stripePassFrag.loaded,
|
||||||
null,
|
(w, h) => output.resize(w, h),
|
||||||
stripePassFrag.loaded
|
() => render({ frag: stripePassFrag.text() })
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -129,28 +129,15 @@ const make1DTexture = (regl, data) =>
|
|||||||
min: "linear",
|
min: "linear",
|
||||||
});
|
});
|
||||||
|
|
||||||
const makePass = (outputs, render, resize, ready) => {
|
const makePass = (outputs, ready, setSize, execute) => ({
|
||||||
if (render == null) {
|
outputs: outputs ?? {},
|
||||||
render = () => {};
|
ready: ready ?? Promise.resolve(),
|
||||||
}
|
setSize: setSize ?? (() => {}),
|
||||||
if (resize == null) {
|
execute: execute ?? (() => {}),
|
||||||
resize = (w, h) => Object.values(outputs).forEach((output) => output.resize(w, h));
|
});
|
||||||
}
|
|
||||||
if (ready == null) {
|
|
||||||
ready = Promise.resolve();
|
|
||||||
} else if (ready instanceof Array) {
|
|
||||||
ready = Promise.all(ready);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
outputs,
|
|
||||||
render,
|
|
||||||
resize,
|
|
||||||
ready,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const makePipeline = (steps, getInputs, ...params) =>
|
const makePipeline = (context, steps) =>
|
||||||
steps.filter((f) => f != null).reduce((pipeline, f, i) => [...pipeline, f(...params, i == 0 ? null : getInputs(pipeline[i - 1]))], []);
|
steps.filter((f) => f != null).reduce((pipeline, f, i) => [...pipeline, f(context, i == 0 ? null : pipeline[i - 1].outputs)], []);
|
||||||
|
|
||||||
export {
|
export {
|
||||||
makePassTexture,
|
makePassTexture,
|
||||||
|
|||||||
@@ -76,5 +76,5 @@ export default (context, getInputs) => {
|
|||||||
renderPass.endPass();
|
renderPass.endPass();
|
||||||
};
|
};
|
||||||
|
|
||||||
return makePass(ready, setSize, getOutputs, execute);
|
return makePass(getOutputs, ready, setSize, execute);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -161,5 +161,5 @@ export default (context, getInputs) => {
|
|||||||
renderPass.endPass();
|
renderPass.endPass();
|
||||||
};
|
};
|
||||||
|
|
||||||
return makePass(ready, setSize, getOutputs, execute);
|
return makePass(getOutputs, ready, setSize, execute);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -193,5 +193,5 @@ export default (context, getInputs) => {
|
|||||||
renderPass.endPass();
|
renderPass.endPass();
|
||||||
};
|
};
|
||||||
|
|
||||||
return makePass(ready, setSize, getOutputs, execute);
|
return makePass(getOutputs, ready, setSize, execute);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -83,5 +83,5 @@ export default (context, getInputs) => {
|
|||||||
renderPass.endPass();
|
renderPass.endPass();
|
||||||
};
|
};
|
||||||
|
|
||||||
return makePass(ready, setSize, getOutputs, execute);
|
return makePass(getOutputs, ready, setSize, execute);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -125,5 +125,5 @@ export default (context, getInputs) => {
|
|||||||
renderPass.endPass();
|
renderPass.endPass();
|
||||||
};
|
};
|
||||||
|
|
||||||
return makePass(ready, setSize, getOutputs, execute);
|
return makePass(getOutputs, ready, setSize, execute);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -80,10 +80,10 @@ const makeBindGroup = (device, pipeline, index, entries) =>
|
|||||||
})),
|
})),
|
||||||
});
|
});
|
||||||
|
|
||||||
const makePass = (ready, setSize, getOutputs, execute) => ({
|
const makePass = (getOutputs, ready, setSize, execute) => ({
|
||||||
|
getOutputs: getOutputs ?? (() => ({})),
|
||||||
ready: ready ?? Promise.resolve(),
|
ready: ready ?? Promise.resolve(),
|
||||||
setSize: setSize ?? (() => {}),
|
setSize: setSize ?? (() => {}),
|
||||||
getOutputs: getOutputs ?? (() => ({})),
|
|
||||||
execute: execute ?? (() => {}),
|
execute: execute ?? (() => {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user