Skip to content

Commit

Permalink
Adding glyphFlip and glyphRotation parameters.
Browse files Browse the repository at this point in the history
  • Loading branch information
Rezmason committed Sep 11, 2024
1 parent f14651c commit cee10bb
Show file tree
Hide file tree
Showing 7 changed files with 37 additions and 14 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ Some of the [earliest](https://github.com/ppetr/xlockmore/blob/master/modes/matr

You can customize the digital rain quite a bit by stapling "URL variables" to its URL— by putting a '?' at the end of the link above, and then chaining together words, like this:

[https://rezmason.github.io/matrix/?width=100&fallSpeed=-0.1&effect=none](https://rezmason.github.io/matrix/?width=100&fallSpeed=-0.1&effect=none)
[https://rezmason.github.io/matrix/?numColumns=100&fallSpeed=-0.1&slant=200&glyphRotation=180](https://rezmason.github.io/matrix/?numColumns=100&fallSpeed=-0.1&slant=200&glyphRotation=180)

Now you know link fu. Here's a list of customization options:

Expand All @@ -116,7 +116,9 @@ Now you know link fu. Here's a list of customization options:
- "palimpsest" is a custom version inspired by the art and sound of [Rob Dougan](https://en.wikipedia.org/wiki/Rob_Dougan)'s [Furious Angels](https://en.wikipedia.org/wiki/Furious_Angels).
- `skipIntro` - whether or not to start from a blank screen. Can be "true" or "false", default is *true*.
- `font` - the set of glyphs to draw. Current options are "matrixcode", "resurrections", "gothic", "coptic", "huberfishA", and "huberfishD".
- `width` - the number of columns (and rows) to draw. Default is 80.
- `numColumns` - the number of columns (and rows) to draw. Default is 80.
- `glyphFlip` - when set to "true", this flips the glyphs. Default is "false".
- `glyphRotation` - the angle to rotate the glyphs in-place, in degrees. Default is 0. I suggest angles that are multiples of 90°.
- `volumetric` - when set to "true", this renders the glyphs with depth, slowly approaching the eye. Default is "false".
- `density` - the number of 3D raindrops to draw, proportional to the default. Default is 1.0.
- `forwardSpeed` - the rate that the 3D raindrops approach. Default is 1.0.
Expand Down
6 changes: 3 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<!DOCTYPE html>
<!doctype html>
<html>
<head>
<title>Matrix digital rain</title>
<meta charset="utf-8" />
<meta name="apple-mobile-web-app-capable" content="yes" /></meta>
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" /></meta>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0, viewport-fit=cover" />
<style>
@supports (padding-top: env(safe-area-inset-top)) {
Expand Down
17 changes: 12 additions & 5 deletions js/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ const defaults = {
glyphEdgeCrop: 0.0, // The border around a glyph in a font texture that should be cropped out
glyphHeightToWidth: 1, // The aspect ratio of glyphs
glyphVerticalSpacing: 1, // The ratio of the vertical distance between glyphs to their height
glyphFlip: false, // Whether to horizontally reflect the glyphs
glyphRotation: 0, // An angle to rotate the glyphs. Currently limited to 90° increments
hasThunder: false, // An effect that adds dramatic lightning flashes
isPolar: false, // Whether the glyphs arc across the screen or sit in a standard grid
rippleTypeName: null, // The variety of the ripple effect
Expand Down Expand Up @@ -134,12 +136,12 @@ const versions = {
megacity: {
font: "megacity",
animationSpeed: 0.5,
width: 40,
numColumns: 40,
},
neomatrixology: {
font: "neomatrixology",
animationSpeed: 0.8,
width: 40,
numColumns: 40,
palette: [
{ color: hsl(0.15, 0.9, 0.0), at: 0.0 },
{ color: hsl(0.15, 0.9, 0.2), at: 0.2 },
Expand Down Expand Up @@ -443,7 +445,6 @@ const paramMapping = {
font: { key: "font", parser: (s) => s },
effect: { key: "effect", parser: (s) => s },
camera: { key: "useCamera", parser: isTrue },
width: { key: "numColumns", parser: (s) => nullNaN(parseInt(s)) },
numColumns: { key: "numColumns", parser: (s) => nullNaN(parseInt(s)) },
density: { key: "density", parser: (s) => nullNaN(range(parseFloat(s), 0)) },
resolution: { key: "resolution", parser: (s) => nullNaN(parseFloat(s)) },
Expand Down Expand Up @@ -501,6 +502,11 @@ const paramMapping = {
},

volumetric: { key: "volumetric", parser: isTrue },
glyphFlip: { key: "glyphFlip", parser: isTrue },
glyphRotation: {
key: "glyphRotation",
parser: (s) => nullNaN(range(parseFloat(s), 0, Infinity)),
},
loops: { key: "loops", parser: isTrue },
fps: { key: "fps", parser: (s) => nullNaN(range(parseFloat(s), 0, 60)) },
skipIntro: { key: "skipIntro", parser: isTrue },
Expand All @@ -516,16 +522,17 @@ paramMapping.backgroundRGB = paramMapping.backgroundColor;
paramMapping.cursorRGB = paramMapping.cursorColor;
paramMapping.glintRGB = paramMapping.glintColor;

paramMapping.width = paramMapping.numColumns;
paramMapping.dropLength = paramMapping.raindropLength;
paramMapping.angle = paramMapping.slant;
paramMapping.colors = paramMapping.stripeColors;

export default (urlParams) => {
const validParams = Object.fromEntries(
Array.from(Object.entries(urlParams))
Object.entries(urlParams)
.filter(([key]) => key in paramMapping)
.map(([key, value]) => [paramMapping[key].key, paramMapping[key].parser(value)])
.filter(([_, value]) => value != null)
.filter(([_, value]) => value != null),
);

if (validParams.effect != null) {
Expand Down
7 changes: 6 additions & 1 deletion js/regl/rainPass.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ const brVert = [1, 1];
const quadVertices = [tlVert, trVert, brVert, tlVert, brVert, blVert];

export default ({ regl, config, lkg }) => {
const { mat2, mat4, vec2, vec3 } = glMatrix;

// The volumetric mode multiplies the number of columns
// to reach the desired density, and then overlaps them
const volumetric = config.volumetric;
Expand All @@ -49,6 +51,9 @@ export default ({ regl, config, lkg }) => {
const slantScale = 1 / (Math.abs(Math.sin(2 * config.slant)) * (Math.sqrt(2) - 1) + 1);
const showDebugView = config.effect === "none";

const glyphTransform = mat2.fromScaling(mat2.create(), vec2.fromValues(config.glyphFlip ? -1 : 1, 1));
mat2.rotate(glyphTransform, glyphTransform, (config.glyphRotation * Math.PI) / 180);

const commonUniforms = {
...extractEntries(config, ["animationSpeed", "glyphHeightToWidth", "glyphSequenceLength", "glyphTextureGridSize"]),
numColumns,
Expand Down Expand Up @@ -160,6 +165,7 @@ export default ({ regl, config, lkg }) => {
"glyphEdgeCrop",
"isPolar",
]),
glyphTransform,
density,
numQuadColumns,
numQuadRows,
Expand Down Expand Up @@ -212,7 +218,6 @@ export default ({ regl, config, lkg }) => {

// Camera and transform math for the volumetric mode
const screenSize = [1, 1];
const { mat4, vec3 } = glMatrix;
const transform = mat4.create();
if (volumetric && config.isometric) {
mat4.rotateX(transform, transform, (Math.PI * 1) / 8);
Expand Down
10 changes: 7 additions & 3 deletions js/webgpu/rainPass.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const rippleTypes = {

const numVerticesPerQuad = 2 * 3;

const makeConfigBuffer = (device, configUniforms, config, density, gridSize) => {
const makeConfigBuffer = (device, configUniforms, config, density, gridSize, glyphTransform) => {
const configData = {
...config,
gridSize,
Expand All @@ -18,14 +18,15 @@ const makeConfigBuffer = (device, configUniforms, config, density, gridSize) =>
slantScale: 1 / (Math.abs(Math.sin(2 * config.slant)) * (Math.sqrt(2) - 1) + 1),
slantVec: [Math.cos(config.slant), Math.sin(config.slant)],
msdfPxRange: 4,
glyphTransform,
};
// console.table(configData);

return makeUniformBuffer(device, configUniforms, configData);
};

export default ({ config, device, timeBuffer }) => {
const { mat4, vec3 } = glMatrix;
const { mat2, mat4, vec2, vec3 } = glMatrix;

const assets = [
loadTexture(device, config.glyphMSDFURL),
Expand All @@ -45,6 +46,9 @@ export default ({ config, device, timeBuffer }) => {
// rather than a single quad for our geometry
const numQuads = config.volumetric ? numCells : 1;

const glyphTransform = mat2.fromScaling(mat2.create(), vec2.fromValues(config.glyphFlip ? -1 : 1, 1));
mat2.rotate(glyphTransform, glyphTransform, (config.glyphRotation * Math.PI) / 180);

const transform = mat4.create();
if (config.volumetric && config.isometric) {
mat4.rotateX(transform, transform, (Math.PI * 1) / 8);
Expand Down Expand Up @@ -97,7 +101,7 @@ export default ({ config, device, timeBuffer }) => {
const [glyphMSDFTexture, glintMSDFTexture, baseTexture, glintTexture, rainShader] = await Promise.all(assets);

const rainShaderUniforms = structs.from(rainShader.code);
configBuffer = makeConfigBuffer(device, rainShaderUniforms.Config, config, density, gridSize);
configBuffer = makeConfigBuffer(device, rainShaderUniforms.Config, config, density, gridSize, glyphTransform);

const introCellsBuffer = device.createBuffer({
size: gridSize[0] * rainShaderUniforms.IntroCell.minSize,
Expand Down
3 changes: 3 additions & 0 deletions shaders/glsl/rainPass.frag.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ uniform bool showDebugView;
uniform bool volumetric;
uniform bool isolateCursor, isolateGlint;

uniform mat2 glyphTransform;

varying vec2 vUV;
varying vec4 vRaindrop, vSymbol, vEffect;
varying float vDepth;
Expand Down Expand Up @@ -110,6 +112,7 @@ vec2 getSymbol(vec2 uv, float index) {
// resolve UV to cropped position of glyph in MSDF texture
uv = fract(uv * vec2(numColumns, numRows));
uv -= 0.5;
uv = glyphTransform * uv;
uv *= clamp(1. - glyphEdgeCrop, 0., 1.);
uv += 0.5;
uv = (uv + getSymbolUV(index)) / glyphTextureGridSize;
Expand Down
2 changes: 2 additions & 0 deletions shaders/wgsl/rainPass.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ struct Config {
glyphSequenceLength : f32,
glyphTextureGridSize : vec2<i32>,
glyphHeightToWidth : f32,
glyphTransform : mat2x2<f32>,
gridSize : vec2<f32>,
showDebugView : i32,

Expand Down Expand Up @@ -493,6 +494,7 @@ fn getSymbol(cellUV : vec2<f32>, index : i32) -> vec2<f32> {
// resolve UV to cropped position of glyph in MSDF texture
var uv = fract(cellUV * config.gridSize);
uv -= 0.5;
uv = config.glyphTransform * uv;
uv *= clamp(1.0 - config.glyphEdgeCrop, 0.0, 1.0);
uv += 0.5;
uv = (uv + getSymbolUV(index)) / vec2<f32>(config.glyphTextureGridSize);
Expand Down

0 comments on commit cee10bb

Please sign in to comment.