mirror of
https://github.com/Rezmason/matrix.git
synced 2026-04-21 15:29:30 -07:00
Ran the format script
This commit is contained in:
@@ -123,11 +123,9 @@ export const Matrix = memo((props) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
matrix.current.appendChild(canvasRef.current);
|
matrix.current.appendChild(canvasRef.current);
|
||||||
const gl = canvasRef.current.getContext("webgl");
|
const gl = canvasRef.current.getContext("webgl");
|
||||||
createRain(canvasRef.current, makeConfig({ ...rest }), gl).then(
|
createRain(canvasRef.current, makeConfig({ ...rest }), gl).then((handles) => {
|
||||||
(handles) => {
|
|
||||||
rainRef.current = handles;
|
rainRef.current = handles;
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (rainRef.current) {
|
if (rainRef.current) {
|
||||||
|
|||||||
@@ -7,7 +7,11 @@ document.addEventListener("touchmove", (e) => e.preventDefault(), {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const supportsWebGPU = async () => {
|
const supportsWebGPU = async () => {
|
||||||
return window.GPUQueue != null && navigator.gpu != null && navigator.gpu.getPreferredCanvasFormat != null;
|
return (
|
||||||
|
window.GPUQueue != null &&
|
||||||
|
navigator.gpu != null &&
|
||||||
|
navigator.gpu.getPreferredCanvasFormat != null
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const isRunningSwiftShader = () => {
|
const isRunningSwiftShader = () => {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { makePassFBO, makePass } from "./utils";
|
import { makePassFBO, makePass } from "./utils";
|
||||||
import highPassFrag from '../../shaders/glsl/bloomPass.highPass.frag.glsl';
|
import highPassFrag from "../../shaders/glsl/bloomPass.highPass.frag.glsl";
|
||||||
import blurFrag from '../../shaders/glsl/bloomPass.blur.frag.glsl';
|
import blurFrag from "../../shaders/glsl/bloomPass.blur.frag.glsl";
|
||||||
import combineFrag from '../../shaders/glsl/bloomPass.combine.frag.glsl';
|
import combineFrag from "../../shaders/glsl/bloomPass.combine.frag.glsl";
|
||||||
|
|
||||||
// The bloom pass is basically an added high-pass blur.
|
// The bloom pass is basically an added high-pass blur.
|
||||||
// The blur approximation is the sum of a pyramid of downscaled, blurred textures.
|
// The blur approximation is the sum of a pyramid of downscaled, blurred textures.
|
||||||
@@ -16,7 +16,9 @@ const makePyramid = (regl, height, halfFloat) =>
|
|||||||
.map((_) => makePassFBO(regl, halfFloat));
|
.map((_) => makePassFBO(regl, halfFloat));
|
||||||
|
|
||||||
const resizePyramid = (pyramid, vw, vh, scale) =>
|
const resizePyramid = (pyramid, vw, vh, scale) =>
|
||||||
pyramid.forEach((fbo, index) => fbo.resize(Math.floor((vw * scale) / 2 ** index), Math.floor((vh * scale) / 2 ** index)));
|
pyramid.forEach((fbo, index) =>
|
||||||
|
fbo.resize(Math.floor((vw * scale) / 2 ** index), Math.floor((vh * scale) / 2 ** index)),
|
||||||
|
);
|
||||||
|
|
||||||
export default ({ regl, config }, inputs) => {
|
export default ({ regl, config }, inputs) => {
|
||||||
const { bloomStrength, bloomSize, highPassThreshold } = config;
|
const { bloomStrength, bloomSize, highPassThreshold } = config;
|
||||||
@@ -94,12 +96,16 @@ export default ({ regl, config }, inputs) => {
|
|||||||
const highPassFBO = highPassPyramid[i];
|
const highPassFBO = highPassPyramid[i];
|
||||||
const hBlurFBO = hBlurPyramid[i];
|
const hBlurFBO = hBlurPyramid[i];
|
||||||
const vBlurFBO = vBlurPyramid[i];
|
const vBlurFBO = vBlurPyramid[i];
|
||||||
highPass({ fbo: highPassFBO, frag: highPassFrag, tex: i === 0 ? inputs.primary : highPassPyramid[i - 1] });
|
highPass({
|
||||||
|
fbo: highPassFBO,
|
||||||
|
frag: highPassFrag,
|
||||||
|
tex: i === 0 ? inputs.primary : highPassPyramid[i - 1],
|
||||||
|
});
|
||||||
blur({ fbo: hBlurFBO, frag: blurFrag, tex: highPassFBO, direction: [1, 0] });
|
blur({ fbo: hBlurFBO, frag: blurFrag, tex: highPassFBO, direction: [1, 0] });
|
||||||
blur({ fbo: vBlurFBO, frag: blurFrag, tex: hBlurFBO, direction: [0, 1] });
|
blur({ fbo: vBlurFBO, frag: blurFrag, tex: hBlurFBO, direction: [0, 1] });
|
||||||
}
|
}
|
||||||
|
|
||||||
combine({ frag: combineFrag });
|
combine({ frag: combineFrag });
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import imagePassFrag from "../../shaders/glsl/imagePass.frag.glsl";
|
|||||||
|
|
||||||
// Multiplies the rendered rain and bloom by a loaded in image
|
// Multiplies the rendered rain and bloom by a loaded in image
|
||||||
|
|
||||||
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);
|
||||||
@@ -28,6 +29,6 @@ export default ({ regl, config }, inputs) => {
|
|||||||
if (shouldRender) {
|
if (shouldRender) {
|
||||||
render({ frag: imagePassFrag });
|
render({ frag: imagePassFrag });
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -45,14 +45,11 @@ const interpretDevice = (device) => {
|
|||||||
const calibration = Object.fromEntries(
|
const calibration = Object.fromEntries(
|
||||||
Object.entries(device.calibration)
|
Object.entries(device.calibration)
|
||||||
.map(([key, value]) => [key, value.value])
|
.map(([key, value]) => [key, value.value])
|
||||||
.filter(([key, value]) => value != null)
|
.filter(([key, value]) => value != null),
|
||||||
);
|
);
|
||||||
|
|
||||||
const screenInches = calibration.screenW / calibration.DPI;
|
const screenInches = calibration.screenW / calibration.DPI;
|
||||||
const pitch =
|
const pitch = calibration.pitch * screenInches * Math.cos(Math.atan(1.0 / calibration.slope));
|
||||||
calibration.pitch *
|
|
||||||
screenInches *
|
|
||||||
Math.cos(Math.atan(1.0 / calibration.slope));
|
|
||||||
const tilt =
|
const tilt =
|
||||||
(calibration.screenH / (calibration.screenW * calibration.slope)) *
|
(calibration.screenH / (calibration.screenW * calibration.slope)) *
|
||||||
-(calibration.flipImageX * 2 - 1);
|
-(calibration.flipImageX * 2 - 1);
|
||||||
@@ -61,11 +58,9 @@ const interpretDevice = (device) => {
|
|||||||
const defaultQuilt = device.defaultQuilt;
|
const defaultQuilt = device.defaultQuilt;
|
||||||
|
|
||||||
const quiltViewPortion = [
|
const quiltViewPortion = [
|
||||||
(Math.floor(defaultQuilt.quiltX / defaultQuilt.tileX) *
|
(Math.floor(defaultQuilt.quiltX / defaultQuilt.tileX) * defaultQuilt.tileX) /
|
||||||
defaultQuilt.tileX) /
|
|
||||||
defaultQuilt.quiltX,
|
defaultQuilt.quiltX,
|
||||||
(Math.floor(defaultQuilt.quiltY / defaultQuilt.tileY) *
|
(Math.floor(defaultQuilt.quiltY / defaultQuilt.tileY) * defaultQuilt.tileY) /
|
||||||
defaultQuilt.tileY) /
|
|
||||||
defaultQuilt.quiltY,
|
defaultQuilt.quiltY,
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -91,8 +86,8 @@ export default async (useHoloplay = false, useRecordedDevice = false) => {
|
|||||||
(resolve, reject) =>
|
(resolve, reject) =>
|
||||||
new HoloPlayCore.Client(
|
new HoloPlayCore.Client(
|
||||||
(data) => resolve(data.devices?.[0]),
|
(data) => resolve(data.devices?.[0]),
|
||||||
(error) => resolve(null)
|
(error) => resolve(null),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
if (device == null && useRecordedDevice) {
|
if (device == null && useRecordedDevice) {
|
||||||
return interpretDevice(recordedDevice);
|
return interpretDevice(recordedDevice);
|
||||||
|
|||||||
@@ -7,11 +7,7 @@ import makeStripePass from "./stripePass.js";
|
|||||||
import makeImagePass from "./imagePass.js";
|
import makeImagePass from "./imagePass.js";
|
||||||
import makeQuiltPass from "./quiltPass.js";
|
import makeQuiltPass from "./quiltPass.js";
|
||||||
import makeMirrorPass from "./mirrorPass.js";
|
import makeMirrorPass from "./mirrorPass.js";
|
||||||
import {
|
import { setupCamera, cameraCanvas, cameraAspectRatio } from "../utils/camera.js";
|
||||||
setupCamera,
|
|
||||||
cameraCanvas,
|
|
||||||
cameraAspectRatio,
|
|
||||||
} from "../utils/camera.js";
|
|
||||||
import getLKG from "./lkgHelper.js";
|
import getLKG from "./lkgHelper.js";
|
||||||
|
|
||||||
const effects = {
|
const effects = {
|
||||||
@@ -67,10 +63,7 @@ export const createRain = async (canvas, config, gl) => {
|
|||||||
await setupCamera();
|
await setupCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
const extensions = [
|
const extensions = ["OES_texture_half_float", "OES_texture_half_float_linear"];
|
||||||
"OES_texture_half_float",
|
|
||||||
"OES_texture_half_float_linear",
|
|
||||||
];
|
|
||||||
// These extensions are also needed, but Safari misreports that they are missing
|
// These extensions are also needed, but Safari misreports that they are missing
|
||||||
const optionalExtensions = [
|
const optionalExtensions = [
|
||||||
"EXT_color_buffer_half_float",
|
"EXT_color_buffer_half_float",
|
||||||
@@ -131,9 +124,7 @@ export const createRain = async (canvas, config, gl) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const shouldRender =
|
const shouldRender =
|
||||||
config.fps >= 60 ||
|
config.fps >= 60 || now - last >= targetFrameTimeMilliseconds || config.once == true;
|
||||||
now - last >= targetFrameTimeMilliseconds ||
|
|
||||||
config.once == true;
|
|
||||||
|
|
||||||
if (shouldRender) {
|
if (shouldRender) {
|
||||||
while (now - targetFrameTimeMilliseconds > last) {
|
while (now - targetFrameTimeMilliseconds > last) {
|
||||||
@@ -144,10 +135,7 @@ export const createRain = async (canvas, config, gl) => {
|
|||||||
if (config.useCamera) {
|
if (config.useCamera) {
|
||||||
cameraTex(cameraCanvas);
|
cameraTex(cameraCanvas);
|
||||||
}
|
}
|
||||||
if (
|
if (dimensions.width !== viewportWidth || dimensions.height !== viewportHeight) {
|
||||||
dimensions.width !== viewportWidth ||
|
|
||||||
dimensions.height !== viewportHeight
|
|
||||||
) {
|
|
||||||
dimensions.width = viewportWidth;
|
dimensions.width = viewportWidth;
|
||||||
dimensions.height = viewportHeight;
|
dimensions.height = viewportHeight;
|
||||||
for (const step of pipeline) {
|
for (const step of pipeline) {
|
||||||
|
|||||||
@@ -45,6 +45,6 @@ export default ({ regl, config, cameraTex, cameraAspectRatio }, inputs) => {
|
|||||||
if (shouldRender) {
|
if (shouldRender) {
|
||||||
render({ frag: mirrorPassFrag });
|
render({ frag: mirrorPassFrag });
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,9 +17,7 @@ const makePalette = (regl, entries) => {
|
|||||||
.sort((e1, e2) => e1.at - e2.at)
|
.sort((e1, e2) => e1.at - e2.at)
|
||||||
.map((entry) => ({
|
.map((entry) => ({
|
||||||
rgb: colorToRGB(entry.color),
|
rgb: colorToRGB(entry.color),
|
||||||
arrayIndex: Math.floor(
|
arrayIndex: Math.floor(Math.max(Math.min(1, entry.at), 0) * (PALETTE_SIZE - 1)),
|
||||||
Math.max(Math.min(1, entry.at), 0) * (PALETTE_SIZE - 1)
|
|
||||||
),
|
|
||||||
}));
|
}));
|
||||||
sortedEntries.unshift({ rgb: sortedEntries[0].rgb, arrayIndex: 0 });
|
sortedEntries.unshift({ rgb: sortedEntries[0].rgb, arrayIndex: 0 });
|
||||||
sortedEntries.push({
|
sortedEntries.push({
|
||||||
@@ -47,7 +45,7 @@ const makePalette = (regl, entries) => {
|
|||||||
|
|
||||||
return make1DTexture(
|
return make1DTexture(
|
||||||
regl,
|
regl,
|
||||||
paletteColors.map((rgb) => [...rgb, 1])
|
paletteColors.map((rgb) => [...rgb, 1]),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -96,6 +94,6 @@ export default ({ regl, config }, inputs) => {
|
|||||||
if (shouldRender) {
|
if (shouldRender) {
|
||||||
render({ frag: palettePassFrag });
|
render({ frag: palettePassFrag });
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,6 +30,6 @@ export default ({ regl, config, lkg }, inputs) => {
|
|||||||
if (shouldRender) {
|
if (shouldRender) {
|
||||||
render({ frag: quiltPassFrag });
|
render({ frag: quiltPassFrag });
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import {
|
import { loadImage, makePassFBO, makeDoubleBuffer, makePass } from "./utils.js";
|
||||||
loadImage,
|
|
||||||
makePassFBO,
|
|
||||||
makeDoubleBuffer,
|
|
||||||
makePass,
|
|
||||||
} from "./utils.js";
|
|
||||||
import { mat4, vec3 } from "gl-matrix";
|
import { mat4, vec3 } from "gl-matrix";
|
||||||
import rainPassIntro from "../../shaders/glsl/rainPass.intro.frag.glsl";
|
import rainPassIntro from "../../shaders/glsl/rainPass.intro.frag.glsl";
|
||||||
import rainPassRaindrop from "../../shaders/glsl/rainPass.raindrop.frag.glsl";
|
import rainPassRaindrop from "../../shaders/glsl/rainPass.raindrop.frag.glsl";
|
||||||
@@ -13,9 +8,7 @@ import rainPassVert from "../../shaders/glsl/rainPass.vert.glsl";
|
|||||||
import rainPassFrag from "../../shaders/glsl/rainPass.frag.glsl";
|
import rainPassFrag from "../../shaders/glsl/rainPass.frag.glsl";
|
||||||
|
|
||||||
const extractEntries = (src, keys) =>
|
const extractEntries = (src, keys) =>
|
||||||
Object.fromEntries(
|
Object.fromEntries(Array.from(Object.entries(src)).filter(([key]) => keys.includes(key)));
|
||||||
Array.from(Object.entries(src)).filter(([key]) => keys.includes(key))
|
|
||||||
);
|
|
||||||
|
|
||||||
const rippleTypes = {
|
const rippleTypes = {
|
||||||
box: 0,
|
box: 0,
|
||||||
@@ -49,27 +42,18 @@ export default ({ regl, config, lkg }) => {
|
|||||||
// 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;
|
||||||
const density = volumetric && config.effect !== "none" ? config.density : 1;
|
const density = volumetric && config.effect !== "none" ? config.density : 1;
|
||||||
const [numRows, numColumns] = [
|
const [numRows, numColumns] = [config.numColumns, Math.floor(config.numColumns * density)];
|
||||||
config.numColumns,
|
|
||||||
Math.floor(config.numColumns * density),
|
|
||||||
];
|
|
||||||
|
|
||||||
// The volumetric mode requires us to create a grid of quads,
|
// The volumetric mode requires us to create a grid of quads,
|
||||||
// rather than a single quad for our geometry
|
// rather than a single quad for our geometry
|
||||||
const [numQuadRows, numQuadColumns] = volumetric
|
const [numQuadRows, numQuadColumns] = volumetric ? [numRows, numColumns] : [1, 1];
|
||||||
? [numRows, numColumns]
|
|
||||||
: [1, 1];
|
|
||||||
const numQuads = numQuadRows * numQuadColumns;
|
const numQuads = numQuadRows * numQuadColumns;
|
||||||
const quadSize = [1 / numQuadColumns, 1 / numQuadRows];
|
const quadSize = [1 / numQuadColumns, 1 / numQuadRows];
|
||||||
|
|
||||||
// Various effect-related values
|
// Various effect-related values
|
||||||
const rippleType =
|
const rippleType = config.rippleTypeName in rippleTypes ? rippleTypes[config.rippleTypeName] : -1;
|
||||||
config.rippleTypeName in rippleTypes
|
|
||||||
? rippleTypes[config.rippleTypeName]
|
|
||||||
: -1;
|
|
||||||
const slantVec = [Math.cos(config.slant), Math.sin(config.slant)];
|
const slantVec = [Math.cos(config.slant), Math.sin(config.slant)];
|
||||||
const slantScale =
|
const slantScale = 1 / (Math.abs(Math.sin(2 * config.slant)) * (Math.sqrt(2) - 1) + 1);
|
||||||
1 / (Math.abs(Math.sin(2 * config.slant)) * (Math.sqrt(2) - 1) + 1);
|
|
||||||
const showDebugView = config.effect === "none";
|
const showDebugView = config.effect === "none";
|
||||||
|
|
||||||
const commonUniforms = {
|
const commonUniforms = {
|
||||||
@@ -100,11 +84,7 @@ export default ({ regl, config, lkg }) => {
|
|||||||
framebuffer: introDoubleBuffer.front,
|
framebuffer: introDoubleBuffer.front,
|
||||||
});
|
});
|
||||||
|
|
||||||
const raindropDoubleBuffer = makeComputeDoubleBuffer(
|
const raindropDoubleBuffer = makeComputeDoubleBuffer(regl, numRows, numColumns);
|
||||||
regl,
|
|
||||||
numRows,
|
|
||||||
numColumns
|
|
||||||
);
|
|
||||||
|
|
||||||
const raindropUniforms = {
|
const raindropUniforms = {
|
||||||
...commonUniforms,
|
...commonUniforms,
|
||||||
@@ -173,7 +153,7 @@ export default ({ regl, config, lkg }) => {
|
|||||||
.map((_, y) =>
|
.map((_, y) =>
|
||||||
Array(numQuadColumns)
|
Array(numQuadColumns)
|
||||||
.fill()
|
.fill()
|
||||||
.map((_, x) => Array(numVerticesPerQuad).fill([x, y]))
|
.map((_, x) => Array(numVerticesPerQuad).fill([x, y])),
|
||||||
);
|
);
|
||||||
|
|
||||||
// We render the code into an FBO using MSDFs: https://github.com/Chlumsky/msdfgen
|
// We render the code into an FBO using MSDFs: https://github.com/Chlumsky/msdfgen
|
||||||
@@ -231,7 +211,7 @@ export default ({ regl, config, lkg }) => {
|
|||||||
glintMSDF: glintMSDF.texture,
|
glintMSDF: glintMSDF.texture,
|
||||||
baseTexture: baseTexture.texture,
|
baseTexture: baseTexture.texture,
|
||||||
glintTexture: glintTexture.texture,
|
glintTexture: glintTexture.texture,
|
||||||
glyphTransform: regl.prop('glyphTransform'),
|
glyphTransform: regl.prop("glyphTransform"),
|
||||||
|
|
||||||
msdfPxRange: 4.0,
|
msdfPxRange: 4.0,
|
||||||
glyphMSDFSize: () => [glyphMSDF.width(), glyphMSDF.height()],
|
glyphMSDFSize: () => [glyphMSDF.width(), glyphMSDF.height()],
|
||||||
@@ -277,12 +257,7 @@ export default ({ regl, config, lkg }) => {
|
|||||||
{
|
{
|
||||||
primary: output,
|
primary: output,
|
||||||
},
|
},
|
||||||
Promise.all([
|
Promise.all([glyphMSDF.loaded, glintMSDF.loaded, baseTexture.loaded, glintTexture.loaded]),
|
||||||
glyphMSDF.loaded,
|
|
||||||
glintMSDF.loaded,
|
|
||||||
baseTexture.loaded,
|
|
||||||
glintTexture.loaded,
|
|
||||||
]),
|
|
||||||
(w, h) => {
|
(w, h) => {
|
||||||
output.resize(w, h);
|
output.resize(w, h);
|
||||||
const aspectRatio = w / h;
|
const aspectRatio = w / h;
|
||||||
@@ -299,40 +274,16 @@ export default ({ regl, config, lkg }) => {
|
|||||||
|
|
||||||
if (volumetric && config.isometric) {
|
if (volumetric && config.isometric) {
|
||||||
if (aspectRatio > 1) {
|
if (aspectRatio > 1) {
|
||||||
mat4.ortho(
|
mat4.ortho(camera, -1.5 * aspectRatio, 1.5 * aspectRatio, -1.5, 1.5, -1000, 1000);
|
||||||
camera,
|
|
||||||
-1.5 * aspectRatio,
|
|
||||||
1.5 * aspectRatio,
|
|
||||||
-1.5,
|
|
||||||
1.5,
|
|
||||||
-1000,
|
|
||||||
1000
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
mat4.ortho(
|
mat4.ortho(camera, -1.5, 1.5, -1.5 / aspectRatio, 1.5 / aspectRatio, -1000, 1000);
|
||||||
camera,
|
|
||||||
-1.5,
|
|
||||||
1.5,
|
|
||||||
-1.5 / aspectRatio,
|
|
||||||
1.5 / aspectRatio,
|
|
||||||
-1000,
|
|
||||||
1000
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else if (lkg.enabled) {
|
} else if (lkg.enabled) {
|
||||||
mat4.perspective(
|
mat4.perspective(camera, (Math.PI / 180) * lkg.fov, lkg.quiltAspect, 0.0001, 1000);
|
||||||
camera,
|
|
||||||
(Math.PI / 180) * lkg.fov,
|
|
||||||
lkg.quiltAspect,
|
|
||||||
0.0001,
|
|
||||||
1000
|
|
||||||
);
|
|
||||||
|
|
||||||
const distanceToTarget = -1; // TODO: Get from somewhere else
|
const distanceToTarget = -1; // TODO: Get from somewhere else
|
||||||
let vantagePointAngle =
|
let vantagePointAngle =
|
||||||
(Math.PI / 180) *
|
(Math.PI / 180) * lkg.viewCone * (index / (numVantagePoints - 1) - 0.5);
|
||||||
lkg.viewCone *
|
|
||||||
(index / (numVantagePoints - 1) - 0.5);
|
|
||||||
if (isNaN(vantagePointAngle)) {
|
if (isNaN(vantagePointAngle)) {
|
||||||
vantagePointAngle = 0;
|
vantagePointAngle = 0;
|
||||||
}
|
}
|
||||||
@@ -342,17 +293,9 @@ export default ({ regl, config, lkg }) => {
|
|||||||
|
|
||||||
camera[8] =
|
camera[8] =
|
||||||
-xOffset /
|
-xOffset /
|
||||||
(distanceToTarget *
|
(distanceToTarget * Math.tan((Math.PI / 180) * 0.5 * lkg.fov) * lkg.quiltAspect); // Is this right??
|
||||||
Math.tan((Math.PI / 180) * 0.5 * lkg.fov) *
|
|
||||||
lkg.quiltAspect); // Is this right??
|
|
||||||
} else {
|
} else {
|
||||||
mat4.perspective(
|
mat4.perspective(camera, (Math.PI / 180) * 90, aspectRatio, 0.0001, 1000);
|
||||||
camera,
|
|
||||||
(Math.PI / 180) * 90,
|
|
||||||
aspectRatio,
|
|
||||||
0.0001,
|
|
||||||
1000
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const viewport = {
|
const viewport = {
|
||||||
@@ -364,8 +307,7 @@ export default ({ regl, config, lkg }) => {
|
|||||||
vantagePoints.push({ camera, viewport });
|
vantagePoints.push({ camera, viewport });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[screenSize[0], screenSize[1]] =
|
[screenSize[0], screenSize[1]] = aspectRatio > 1 ? [1, aspectRatio] : [1 / aspectRatio, 1];
|
||||||
aspectRatio > 1 ? [1, aspectRatio] : [1 / aspectRatio, 1];
|
|
||||||
},
|
},
|
||||||
(shouldRender) => {
|
(shouldRender) => {
|
||||||
intro({ frag: rainPassIntro });
|
intro({ frag: rainPassIntro });
|
||||||
@@ -387,10 +329,10 @@ export default ({ regl, config, lkg }) => {
|
|||||||
screenSize,
|
screenSize,
|
||||||
vert: rainPassVert,
|
vert: rainPassVert,
|
||||||
frag: rainPassFrag,
|
frag: rainPassFrag,
|
||||||
glyphTransform: [1, 0, 0, 1]
|
glyphTransform: [1, 0, 0, 1],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export default ({ regl, config }, inputs) => {
|
|||||||
: transPrideStripeColors;
|
: transPrideStripeColors;
|
||||||
const stripeTex = make1DTexture(
|
const stripeTex = make1DTexture(
|
||||||
regl,
|
regl,
|
||||||
stripeColors.map((color) => [...colorToRGB(color), 1])
|
stripeColors.map((color) => [...colorToRGB(color), 1]),
|
||||||
);
|
);
|
||||||
|
|
||||||
const render = regl({
|
const render = regl({
|
||||||
@@ -79,6 +79,6 @@ export default ({ regl, config }, inputs) => {
|
|||||||
if (shouldRender) {
|
if (shouldRender) {
|
||||||
render({ frag: stripePassFrag });
|
render({ frag: stripePassFrag });
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ const makePassTexture = (regl, halfFloat) =>
|
|||||||
mag: "linear",
|
mag: "linear",
|
||||||
});
|
});
|
||||||
|
|
||||||
const makePassFBO = (regl, halfFloat) => regl.framebuffer({ color: makePassTexture(regl, halfFloat) });
|
const makePassFBO = (regl, halfFloat) =>
|
||||||
|
regl.framebuffer({ color: makePassTexture(regl, halfFloat) });
|
||||||
|
|
||||||
const makeDoubleBuffer = (regl, props) => {
|
const makeDoubleBuffer = (regl, props) => {
|
||||||
const state = Array(2)
|
const state = Array(2)
|
||||||
@@ -17,7 +18,7 @@ const makeDoubleBuffer = (regl, props) => {
|
|||||||
regl.framebuffer({
|
regl.framebuffer({
|
||||||
color: regl.texture(props),
|
color: regl.texture(props),
|
||||||
depthStencil: false,
|
depthStencil: false,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
front: ({ tick }) => state[tick % 2],
|
front: ({ tick }) => state[tick % 2],
|
||||||
@@ -149,6 +150,21 @@ const makePass = (outputs, ready, setSize, execute) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const makePipeline = (context, steps) =>
|
const makePipeline = (context, steps) =>
|
||||||
steps.filter((f) => f != null).reduce((pipeline, f, i) => [...pipeline, f(context, i == 0 ? null : pipeline[i - 1].outputs)], []);
|
steps
|
||||||
|
.filter((f) => f != null)
|
||||||
|
.reduce(
|
||||||
|
(pipeline, f, i) => [...pipeline, f(context, i == 0 ? null : pipeline[i - 1].outputs)],
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
export { makePassTexture, makePassFBO, makeDoubleBuffer, loadImage, loadText, makeFullScreenQuad, make1DTexture, makePass, makePipeline };
|
export {
|
||||||
|
makePassTexture,
|
||||||
|
makePassFBO,
|
||||||
|
makeDoubleBuffer,
|
||||||
|
loadImage,
|
||||||
|
loadText,
|
||||||
|
makeFullScreenQuad,
|
||||||
|
make1DTexture,
|
||||||
|
makePass,
|
||||||
|
makePipeline,
|
||||||
|
};
|
||||||
|
|||||||
@@ -419,8 +419,7 @@ versions["1999"] = versions.operator;
|
|||||||
versions["2003"] = versions.classic;
|
versions["2003"] = versions.classic;
|
||||||
versions["2021"] = versions.resurrections;
|
versions["2021"] = versions.resurrections;
|
||||||
|
|
||||||
const range = (f, min = -Infinity, max = Infinity) =>
|
const range = (f, min = -Infinity, max = Infinity) => Math.max(min, Math.min(max, f));
|
||||||
Math.max(min, Math.min(max, f));
|
|
||||||
const nullNaN = (f) => (isNaN(f) ? null : f);
|
const nullNaN = (f) => (isNaN(f) ? null : f);
|
||||||
const isTrue = (s) => s.toLowerCase().includes("true");
|
const isTrue = (s) => s.toLowerCase().includes("true");
|
||||||
|
|
||||||
@@ -549,11 +548,8 @@ export default (urlParams) => {
|
|||||||
const validParams = Object.fromEntries(
|
const validParams = Object.fromEntries(
|
||||||
Object.entries(urlParams)
|
Object.entries(urlParams)
|
||||||
.filter(([key]) => key in paramMapping)
|
.filter(([key]) => key in paramMapping)
|
||||||
.map(([key, value]) => [
|
.map(([key, value]) => [paramMapping[key].key, paramMapping[key].parser(value)])
|
||||||
paramMapping[key].key,
|
.filter(([_, value]) => value != null),
|
||||||
paramMapping[key].parser(value),
|
|
||||||
])
|
|
||||||
.filter(([_, value]) => value != null)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (validParams.effect != null) {
|
if (validParams.effect != null) {
|
||||||
@@ -575,27 +571,15 @@ export default (urlParams) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const version =
|
const version =
|
||||||
validParams.version in versions
|
validParams.version in versions ? versions[validParams.version] : versions.classic;
|
||||||
? versions[validParams.version]
|
const fontName = [validParams.font, version.font, defaults.font].find((name) => name in fonts);
|
||||||
: versions.classic;
|
|
||||||
const fontName = [validParams.font, version.font, defaults.font].find(
|
|
||||||
(name) => name in fonts
|
|
||||||
);
|
|
||||||
const font = fonts[fontName];
|
const font = fonts[fontName];
|
||||||
|
|
||||||
const baseTextureURL =
|
const baseTextureURL =
|
||||||
textureURLs[
|
textureURLs[[version.baseTexture, defaults.baseTexture].find((name) => name in textureURLs)];
|
||||||
[version.baseTexture, defaults.baseTexture].find(
|
|
||||||
(name) => name in textureURLs
|
|
||||||
)
|
|
||||||
];
|
|
||||||
const hasBaseTexture = baseTextureURL != null;
|
const hasBaseTexture = baseTextureURL != null;
|
||||||
const glintTextureURL =
|
const glintTextureURL =
|
||||||
textureURLs[
|
textureURLs[[version.glintTexture, defaults.glintTexture].find((name) => name in textureURLs)];
|
||||||
[version.glintTexture, defaults.glintTexture].find(
|
|
||||||
(name) => name in textureURLs
|
|
||||||
)
|
|
||||||
];
|
|
||||||
const hasGlintTexture = glintTextureURL != null;
|
const hasGlintTexture = glintTextureURL != null;
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
import { structs } from "../../lib/gpu-buffer.js";
|
import { structs } from "../../lib/gpu-buffer.js";
|
||||||
import { makeComputeTarget, loadShader, makeUniformBuffer, makeBindGroup, makePass } from "./utils.js";
|
import {
|
||||||
|
makeComputeTarget,
|
||||||
|
loadShader,
|
||||||
|
makeUniformBuffer,
|
||||||
|
makeBindGroup,
|
||||||
|
makePass,
|
||||||
|
} from "./utils.js";
|
||||||
|
|
||||||
// const makePyramid = makeComputeTarget;
|
// const makePyramid = makeComputeTarget;
|
||||||
|
|
||||||
@@ -20,8 +26,8 @@ const makePyramid = (device, size, pyramidHeight) =>
|
|||||||
.map((_, index) =>
|
.map((_, index) =>
|
||||||
makeComputeTarget(
|
makeComputeTarget(
|
||||||
device,
|
device,
|
||||||
size.map((x) => Math.floor(x * 2 ** -index))
|
size.map((x) => Math.floor(x * 2 ** -index)),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
const destroyPyramid = (pyramid) => pyramid?.forEach((texture) => texture.destroy());
|
const destroyPyramid = (pyramid) => pyramid?.forEach((texture) => texture.destroy());
|
||||||
@@ -47,7 +53,10 @@ export default ({ config, device }) => {
|
|||||||
return makePass("No Bloom", null, (size, inputs) => ({ ...inputs, bloom: emptyTexture }));
|
return makePass("No Bloom", null, (size, inputs) => ({ ...inputs, bloom: emptyTexture }));
|
||||||
}
|
}
|
||||||
|
|
||||||
const assets = [loadShader(device, "shaders/wgsl/bloomBlur.wgsl"), loadShader(device, "shaders/wgsl/bloomCombine.wgsl")];
|
const assets = [
|
||||||
|
loadShader(device, "shaders/wgsl/bloomBlur.wgsl"),
|
||||||
|
loadShader(device, "shaders/wgsl/bloomCombine.wgsl"),
|
||||||
|
];
|
||||||
|
|
||||||
const linearSampler = device.createSampler({
|
const linearSampler = device.createSampler({
|
||||||
magFilter: "linear",
|
magFilter: "linear",
|
||||||
@@ -122,12 +131,27 @@ export default ({ config, device }) => {
|
|||||||
for (let i = 0; i < pyramidHeight; i++) {
|
for (let i = 0; i < pyramidHeight; i++) {
|
||||||
const hBlurPyramidView = makePyramidLevelView(hBlurPyramid, i);
|
const hBlurPyramidView = makePyramidLevelView(hBlurPyramid, i);
|
||||||
const vBlurPyramidView = makePyramidLevelView(vBlurPyramid, i);
|
const vBlurPyramidView = makePyramidLevelView(vBlurPyramid, i);
|
||||||
hBlurBindGroups[i] = makeBindGroup(device, blurPipeline, 0, [hBlurBuffer, linearSampler, srcView, hBlurPyramidView]);
|
hBlurBindGroups[i] = makeBindGroup(device, blurPipeline, 0, [
|
||||||
vBlurBindGroups[i] = makeBindGroup(device, blurPipeline, 0, [vBlurBuffer, linearSampler, hBlurPyramidView, vBlurPyramidView]);
|
hBlurBuffer,
|
||||||
|
linearSampler,
|
||||||
|
srcView,
|
||||||
|
hBlurPyramidView,
|
||||||
|
]);
|
||||||
|
vBlurBindGroups[i] = makeBindGroup(device, blurPipeline, 0, [
|
||||||
|
vBlurBuffer,
|
||||||
|
linearSampler,
|
||||||
|
hBlurPyramidView,
|
||||||
|
vBlurPyramidView,
|
||||||
|
]);
|
||||||
srcView = hBlurPyramidView;
|
srcView = hBlurPyramidView;
|
||||||
}
|
}
|
||||||
|
|
||||||
combineBindGroup = makeBindGroup(device, combinePipeline, 0, [combineBuffer, linearSampler, ...makePyramidViews(vBlurPyramid), output.createView()]);
|
combineBindGroup = makeBindGroup(device, combinePipeline, 0, [
|
||||||
|
combineBuffer,
|
||||||
|
linearSampler,
|
||||||
|
...makePyramidViews(vBlurPyramid),
|
||||||
|
output.createView(),
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...inputs,
|
...inputs,
|
||||||
@@ -144,7 +168,11 @@ export default ({ config, device }) => {
|
|||||||
|
|
||||||
computePass.setPipeline(blurPipeline);
|
computePass.setPipeline(blurPipeline);
|
||||||
for (let i = 0; i < pyramidHeight; i++) {
|
for (let i = 0; i < pyramidHeight; i++) {
|
||||||
const dispatchSize = [Math.ceil(Math.floor(scaledScreenSize[0] * 2 ** -i) / 32), Math.floor(Math.floor(scaledScreenSize[1] * 2 ** -i)), 1];
|
const dispatchSize = [
|
||||||
|
Math.ceil(Math.floor(scaledScreenSize[0] * 2 ** -i) / 32),
|
||||||
|
Math.floor(Math.floor(scaledScreenSize[1] * 2 ** -i)),
|
||||||
|
1,
|
||||||
|
];
|
||||||
computePass.setBindGroup(0, hBlurBindGroups[i]);
|
computePass.setBindGroup(0, hBlurBindGroups[i]);
|
||||||
computePass.dispatchWorkgroups(...dispatchSize);
|
computePass.dispatchWorkgroups(...dispatchSize);
|
||||||
computePass.setBindGroup(0, vBlurBindGroups[i]);
|
computePass.setBindGroup(0, vBlurBindGroups[i]);
|
||||||
|
|||||||
@@ -45,7 +45,10 @@ export default ({ device, canvasFormat, canvasContext }) => {
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
const build = (size, inputs) => {
|
const build = (size, inputs) => {
|
||||||
renderBindGroup = makeBindGroup(device, renderPipeline, 0, [nearestSampler, inputs.primary.createView()]);
|
renderBindGroup = makeBindGroup(device, renderPipeline, 0, [
|
||||||
|
nearestSampler,
|
||||||
|
inputs.primary.createView(),
|
||||||
|
]);
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
import { structs } from "../../lib/gpu-buffer.js";
|
import { structs } from "../../lib/gpu-buffer.js";
|
||||||
import { makeComputeTarget, makeUniformBuffer, loadTexture, loadShader, makeBindGroup, makePass } from "./utils.js";
|
import {
|
||||||
|
makeComputeTarget,
|
||||||
|
makeUniformBuffer,
|
||||||
|
loadTexture,
|
||||||
|
loadShader,
|
||||||
|
makeBindGroup,
|
||||||
|
makePass,
|
||||||
|
} from "./utils.js";
|
||||||
|
|
||||||
// Multiplies the rendered rain and bloom by a loaded in image
|
// Multiplies the rendered rain and bloom by a loaded in image
|
||||||
|
|
||||||
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 ({ config, device }) => {
|
export default ({ config, device }) => {
|
||||||
const bgURL = "bgURL" in config ? config.bgURL : defaultBGURL;
|
const bgURL = "bgURL" in config ? config.bgURL : defaultBGURL;
|
||||||
|
|||||||
@@ -74,7 +74,10 @@ export default async (canvas, config) => {
|
|||||||
const cameraTex = device.createTexture({
|
const cameraTex = device.createTexture({
|
||||||
size: cameraSize,
|
size: cameraSize,
|
||||||
format: "rgba8unorm",
|
format: "rgba8unorm",
|
||||||
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
|
usage:
|
||||||
|
GPUTextureUsage.TEXTURE_BINDING |
|
||||||
|
GPUTextureUsage.COPY_DST |
|
||||||
|
GPUTextureUsage.RENDER_ATTACHMENT,
|
||||||
});
|
});
|
||||||
|
|
||||||
const context = {
|
const context = {
|
||||||
@@ -90,7 +93,12 @@ export default async (canvas, config) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const effectName = config.effect in effects ? config.effect : "palette";
|
const effectName = config.effect in effects ? config.effect : "palette";
|
||||||
const pipeline = await makePipeline(context, [makeRain, makeBloomPass, effects[effectName], makeEndPass]);
|
const pipeline = await makePipeline(context, [
|
||||||
|
makeRain,
|
||||||
|
makeBloomPass,
|
||||||
|
effects[effectName],
|
||||||
|
makeEndPass,
|
||||||
|
]);
|
||||||
|
|
||||||
const targetFrameTimeMilliseconds = 1000 / config.fps;
|
const targetFrameTimeMilliseconds = 1000 / config.fps;
|
||||||
let frames = 0;
|
let frames = 0;
|
||||||
@@ -107,7 +115,8 @@ export default async (canvas, config) => {
|
|||||||
last = start;
|
last = start;
|
||||||
}
|
}
|
||||||
|
|
||||||
const shouldRender = config.fps >= 60 || now - last >= targetFrameTimeMilliseconds || config.once;
|
const shouldRender =
|
||||||
|
config.fps >= 60 || now - last >= targetFrameTimeMilliseconds || config.once;
|
||||||
if (shouldRender) {
|
if (shouldRender) {
|
||||||
while (now - targetFrameTimeMilliseconds > last) {
|
while (now - targetFrameTimeMilliseconds > last) {
|
||||||
last += targetFrameTimeMilliseconds;
|
last += targetFrameTimeMilliseconds;
|
||||||
@@ -125,10 +134,18 @@ export default async (canvas, config) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config.useCamera) {
|
if (config.useCamera) {
|
||||||
device.queue.copyExternalImageToTexture({ source: cameraCanvas }, { texture: cameraTex }, cameraSize);
|
device.queue.copyExternalImageToTexture(
|
||||||
|
{ source: cameraCanvas },
|
||||||
|
{ texture: cameraTex },
|
||||||
|
cameraSize,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
device.queue.writeBuffer(timeBuffer, 0, timeUniforms.toBuffer({ seconds: (now - start) / 1000, frames }));
|
device.queue.writeBuffer(
|
||||||
|
timeBuffer,
|
||||||
|
0,
|
||||||
|
timeUniforms.toBuffer({ seconds: (now - start) / 1000, frames }),
|
||||||
|
);
|
||||||
frames++;
|
frames++;
|
||||||
|
|
||||||
const encoder = device.createCommandEncoder();
|
const encoder = device.createCommandEncoder();
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
import { structs } from "../../lib/gpu-buffer.js";
|
import { structs } from "../../lib/gpu-buffer.js";
|
||||||
import { makeComputeTarget, makeUniformBuffer, loadShader, makeBindGroup, makePass } from "./utils.js";
|
import {
|
||||||
|
makeComputeTarget,
|
||||||
|
makeUniformBuffer,
|
||||||
|
loadShader,
|
||||||
|
makeBindGroup,
|
||||||
|
makePass,
|
||||||
|
} from "./utils.js";
|
||||||
|
|
||||||
let start;
|
let start;
|
||||||
const numTouches = 5;
|
const numTouches = 5;
|
||||||
@@ -77,7 +83,11 @@ export default ({ config, device, cameraTex, cameraAspectRatio, timeBuffer }) =>
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
const screenAspectRatio = size[0] / size[1];
|
const screenAspectRatio = size[0] / size[1];
|
||||||
device.queue.writeBuffer(sceneBuffer, 0, sceneUniforms.toBuffer({ screenAspectRatio, cameraAspectRatio }));
|
device.queue.writeBuffer(
|
||||||
|
sceneBuffer,
|
||||||
|
0,
|
||||||
|
sceneUniforms.toBuffer({ screenAspectRatio, cameraAspectRatio }),
|
||||||
|
);
|
||||||
|
|
||||||
return { primary: output };
|
return { primary: output };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
import colorToRGB from "../colorToRGB.js";
|
import colorToRGB from "../colorToRGB.js";
|
||||||
import { structs } from "../../lib/gpu-buffer.js";
|
import { structs } from "../../lib/gpu-buffer.js";
|
||||||
import { loadShader, makeUniformBuffer, makeBindGroup, makeComputeTarget, makePass } from "./utils.js";
|
import {
|
||||||
|
loadShader,
|
||||||
|
makeUniformBuffer,
|
||||||
|
makeBindGroup,
|
||||||
|
makeComputeTarget,
|
||||||
|
makePass,
|
||||||
|
} from "./utils.js";
|
||||||
|
|
||||||
// Maps the brightness of the rendered rain and bloom to colors
|
// Maps the brightness of the rendered rain and bloom to colors
|
||||||
// in a linear gradient buffer generated from the passed-in color sequence
|
// in a linear gradient buffer generated from the passed-in color sequence
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
import { structs } from "../../lib/gpu-buffer.js";
|
import { structs } from "../../lib/gpu-buffer.js";
|
||||||
import { makeRenderTarget, loadTexture, loadShader, makeUniformBuffer, makeBindGroup, makePass } from "./utils.js";
|
import {
|
||||||
|
makeRenderTarget,
|
||||||
|
loadTexture,
|
||||||
|
loadShader,
|
||||||
|
makeUniformBuffer,
|
||||||
|
makeBindGroup,
|
||||||
|
makePass,
|
||||||
|
} from "./utils.js";
|
||||||
|
|
||||||
const rippleTypes = {
|
const rippleTypes = {
|
||||||
box: 0,
|
box: 0,
|
||||||
@@ -46,7 +53,10 @@ export default ({ config, device, timeBuffer }) => {
|
|||||||
// rather than a single quad for our geometry
|
// rather than a single quad for our geometry
|
||||||
const numQuads = config.volumetric ? numCells : 1;
|
const numQuads = config.volumetric ? numCells : 1;
|
||||||
|
|
||||||
const glyphTransform = mat2.fromScaling(mat2.create(), vec2.fromValues(config.glyphFlip ? -1 : 1, 1));
|
const glyphTransform = mat2.fromScaling(
|
||||||
|
mat2.create(),
|
||||||
|
vec2.fromValues(config.glyphFlip ? -1 : 1, 1),
|
||||||
|
);
|
||||||
mat2.rotate(glyphTransform, glyphTransform, (config.glyphRotation * Math.PI) / 180);
|
mat2.rotate(glyphTransform, glyphTransform, (config.glyphRotation * Math.PI) / 180);
|
||||||
|
|
||||||
const transform = mat4.create();
|
const transform = mat4.create();
|
||||||
@@ -98,10 +108,18 @@ export default ({ config, device, timeBuffer }) => {
|
|||||||
let highPassOutput;
|
let highPassOutput;
|
||||||
|
|
||||||
const loaded = (async () => {
|
const loaded = (async () => {
|
||||||
const [glyphMSDFTexture, glintMSDFTexture, baseTexture, glintTexture, rainShader] = await Promise.all(assets);
|
const [glyphMSDFTexture, glintMSDFTexture, baseTexture, glintTexture, rainShader] =
|
||||||
|
await Promise.all(assets);
|
||||||
|
|
||||||
const rainShaderUniforms = structs.from(rainShader.code);
|
const rainShaderUniforms = structs.from(rainShader.code);
|
||||||
configBuffer = makeConfigBuffer(device, rainShaderUniforms.Config, config, density, gridSize, glyphTransform);
|
configBuffer = makeConfigBuffer(
|
||||||
|
device,
|
||||||
|
rainShaderUniforms.Config,
|
||||||
|
config,
|
||||||
|
density,
|
||||||
|
gridSize,
|
||||||
|
glyphTransform,
|
||||||
|
);
|
||||||
|
|
||||||
const introCellsBuffer = device.createBuffer({
|
const introCellsBuffer = device.createBuffer({
|
||||||
size: gridSize[0] * rainShaderUniforms.IntroCell.minSize,
|
size: gridSize[0] * rainShaderUniforms.IntroCell.minSize,
|
||||||
@@ -168,8 +186,17 @@ export default ({ config, device, timeBuffer }) => {
|
|||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
introBindGroup = makeBindGroup(device, introPipeline, 0, [configBuffer, timeBuffer, introCellsBuffer]);
|
introBindGroup = makeBindGroup(device, introPipeline, 0, [
|
||||||
computeBindGroup = makeBindGroup(device, computePipeline, 0, [configBuffer, timeBuffer, cellsBuffer, introCellsBuffer]);
|
configBuffer,
|
||||||
|
timeBuffer,
|
||||||
|
introCellsBuffer,
|
||||||
|
]);
|
||||||
|
computeBindGroup = makeBindGroup(device, computePipeline, 0, [
|
||||||
|
configBuffer,
|
||||||
|
timeBuffer,
|
||||||
|
cellsBuffer,
|
||||||
|
introCellsBuffer,
|
||||||
|
]);
|
||||||
renderBindGroup = makeBindGroup(device, renderPipeline, 0, [
|
renderBindGroup = makeBindGroup(device, renderPipeline, 0, [
|
||||||
configBuffer,
|
configBuffer,
|
||||||
timeBuffer,
|
timeBuffer,
|
||||||
@@ -196,7 +223,11 @@ export default ({ config, device, timeBuffer }) => {
|
|||||||
mat4.perspectiveZO(camera, (Math.PI / 180) * 90, aspectRatio, 0.0001, 1000);
|
mat4.perspectiveZO(camera, (Math.PI / 180) * 90, aspectRatio, 0.0001, 1000);
|
||||||
}
|
}
|
||||||
const screenSize = aspectRatio > 1 ? [1, aspectRatio] : [1 / aspectRatio, 1];
|
const screenSize = aspectRatio > 1 ? [1, aspectRatio] : [1 / aspectRatio, 1];
|
||||||
device.queue.writeBuffer(sceneBuffer, 0, sceneUniforms.toBuffer({ screenSize, camera, transform }));
|
device.queue.writeBuffer(
|
||||||
|
sceneBuffer,
|
||||||
|
0,
|
||||||
|
sceneUniforms.toBuffer({ screenSize, camera, transform }),
|
||||||
|
);
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
output?.destroy();
|
output?.destroy();
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
import colorToRGB from "../colorToRGB.js";
|
import colorToRGB from "../colorToRGB.js";
|
||||||
import { structs } from "../../lib/gpu-buffer.js";
|
import { structs } from "../../lib/gpu-buffer.js";
|
||||||
import { loadShader, make1DTexture, makeUniformBuffer, makeBindGroup, makeComputeTarget, makePass } from "./utils.js";
|
import {
|
||||||
|
loadShader,
|
||||||
|
make1DTexture,
|
||||||
|
makeUniformBuffer,
|
||||||
|
makeBindGroup,
|
||||||
|
makeComputeTarget,
|
||||||
|
makePass,
|
||||||
|
} from "./utils.js";
|
||||||
|
|
||||||
// Multiplies the rendered rain and bloom by a 1D gradient texture
|
// Multiplies the rendered rain and bloom by a 1D gradient texture
|
||||||
// generated from the passed-in color sequence
|
// generated from the passed-in color sequence
|
||||||
@@ -38,10 +45,15 @@ const numVerticesPerQuad = 2 * 3;
|
|||||||
|
|
||||||
export default ({ config, device, timeBuffer }) => {
|
export default ({ config, device, timeBuffer }) => {
|
||||||
// Expand and convert stripe colors into 1D texture data
|
// Expand and convert stripe colors into 1D texture data
|
||||||
const stripeColors = "stripeColors" in config ? config.stripeColors : config.effect === "pride" ? prideStripeColors : transPrideStripeColors;
|
const stripeColors =
|
||||||
|
"stripeColors" in config
|
||||||
|
? config.stripeColors
|
||||||
|
: config.effect === "pride"
|
||||||
|
? prideStripeColors
|
||||||
|
: transPrideStripeColors;
|
||||||
const stripeTex = make1DTexture(
|
const stripeTex = make1DTexture(
|
||||||
device,
|
device,
|
||||||
stripeColors.map((color) => [...colorToRGB(color), 1])
|
stripeColors.map((color) => [...colorToRGB(color), 1]),
|
||||||
);
|
);
|
||||||
|
|
||||||
const linearSampler = device.createSampler({
|
const linearSampler = device.createSampler({
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ const loadTexture = async (device, url) => {
|
|||||||
return device.createTexture({
|
return device.createTexture({
|
||||||
size: [1, 1, 1],
|
size: [1, 1, 1],
|
||||||
format: "rgba8unorm",
|
format: "rgba8unorm",
|
||||||
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
|
usage:
|
||||||
|
GPUTextureUsage.TEXTURE_BINDING |
|
||||||
|
GPUTextureUsage.COPY_DST |
|
||||||
|
GPUTextureUsage.RENDER_ATTACHMENT,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15,7 +18,10 @@ const loadTexture = async (device, url) => {
|
|||||||
const texture = device.createTexture({
|
const texture = device.createTexture({
|
||||||
size,
|
size,
|
||||||
format: "rgba8unorm",
|
format: "rgba8unorm",
|
||||||
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
|
usage:
|
||||||
|
GPUTextureUsage.TEXTURE_BINDING |
|
||||||
|
GPUTextureUsage.COPY_DST |
|
||||||
|
GPUTextureUsage.RENDER_ATTACHMENT,
|
||||||
});
|
});
|
||||||
|
|
||||||
device.queue.copyExternalImageToTexture({ source, flipY: true }, { texture }, size);
|
device.queue.copyExternalImageToTexture({ source, flipY: true }, { texture }, size);
|
||||||
@@ -28,7 +34,11 @@ const makeRenderTarget = (device, size, format, mipLevelCount = 1) =>
|
|||||||
size: [...size, 1],
|
size: [...size, 1],
|
||||||
mipLevelCount,
|
mipLevelCount,
|
||||||
format,
|
format,
|
||||||
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
|
usage:
|
||||||
|
GPUTextureUsage.TEXTURE_BINDING |
|
||||||
|
GPUTextureUsage.COPY_SRC |
|
||||||
|
GPUTextureUsage.COPY_DST |
|
||||||
|
GPUTextureUsage.RENDER_ATTACHMENT,
|
||||||
});
|
});
|
||||||
|
|
||||||
const makeComputeTarget = (device, size, mipLevelCount = 1) =>
|
const makeComputeTarget = (device, size, mipLevelCount = 1) =>
|
||||||
@@ -36,7 +46,11 @@ const makeComputeTarget = (device, size, mipLevelCount = 1) =>
|
|||||||
size: [...size, 1],
|
size: [...size, 1],
|
||||||
mipLevelCount,
|
mipLevelCount,
|
||||||
format: "rgba8unorm",
|
format: "rgba8unorm",
|
||||||
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST | GPUTextureUsage.STORAGE_BINDING,
|
usage:
|
||||||
|
GPUTextureUsage.TEXTURE_BINDING |
|
||||||
|
GPUTextureUsage.COPY_SRC |
|
||||||
|
GPUTextureUsage.COPY_DST |
|
||||||
|
GPUTextureUsage.STORAGE_BINDING,
|
||||||
});
|
});
|
||||||
|
|
||||||
const loadShader = async (device, url) => {
|
const loadShader = async (device, url) => {
|
||||||
@@ -105,4 +119,14 @@ const makePipeline = async (context, steps) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export { makeRenderTarget, makeComputeTarget, make1DTexture, loadTexture, loadShader, makeUniformBuffer, makePass, makePipeline, makeBindGroup };
|
export {
|
||||||
|
makeRenderTarget,
|
||||||
|
makeComputeTarget,
|
||||||
|
make1DTexture,
|
||||||
|
loadTexture,
|
||||||
|
loadShader,
|
||||||
|
makeUniformBuffer,
|
||||||
|
makePass,
|
||||||
|
makePipeline,
|
||||||
|
makeBindGroup,
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user