Removing brightness-based cycle style— I can no longer see any evidence that it occurs.

Updated the readme file
This commit is contained in:
Rezmason
2022-09-15 00:40:52 -07:00
parent 4c6e6fd662
commit b0613f9bc3
5 changed files with 42 additions and 58 deletions

View File

@@ -29,34 +29,35 @@
--- ---
### about ### about
This project is a WebGL implementation of the raining green code seen in _The Matrix Trilogy_. It's built right on top of the upcoming graphics API [WebGPU](https://github.com/gpuweb/gpuweb), but falls back to the functional WebGL wrapper, [REGL](https://regl.party); its previous Three.js version is maintained in a separate branch. This project is a web implementation of the raining green code seen in the _Matrix_ franchise. It's built right on top of the upcoming graphics API [WebGPU](https://github.com/gpuweb/gpuweb), but falls back to the functional WebGL wrapper, [REGL](https://regl.party); its previous Three.js version is maintained in a separate branch.
--- ---
### goals ### goals
The way I see it, there's four kinds of Matrix effects people call ["digital rain"](http://matrix.wikia.com/wiki/Matrix_code): The way I see it, there's four kinds of Matrix effects people call ["digital rain"](http://matrix.wikia.com/wiki/Matrix_code):
1. The green symbols that "rain down" operators' screens 1. The green symbols that "rain down" operators' screens endlessly
2. Scenes from within the simulation that depict green symbols streaking across everything 2. Scenes from within the simulation that depict green symbols streaking across everything
3. The opening title graphics from *The Matrix*, which combine effect #1 with a "dialing" visualization and some other 3D effects 3. The films' opening title graphics, which dazzle viewers and then draw them into the world of the franchise
3. The sequels' opening title graphics, which combine aspects of effects #1 and #2. 4. The "dialing" visualization at the opening of _The Matrix_ and _Resurrections_
While there have been a lot of attempts at #1 and #3, they're all missing important parts of #4 that make digital rain so iconic. Here are the requirements for my implementation: A fan project can attempt to tackle any of these. However, this project focuses specifically on #1 and #3— an endless effect, visually stunning and mystifying, that feels right at home on any screen.
The following the criteria that guided the development process:
- **Get the right glyphs**. Like the actual ones. By now everyone's heard how the Matrix glyphs are some treatment of [Katakana](https://en.wikipedia.org/wiki/Katakana), but they also include a few characters from [Susan Kare's Chicago typeface](https://en.wikipedia.org/wiki/Chicago_(typeface)). The Matrix glyphs in *this* project come from the source: cleaned up vectors [from an old SWF](https://web.archive.org/web/20070914173039/http://www.atari.com:80/thematrixpathofneo/) for an official Matrix product, archived back in 2007. That's how deep this rabbit hole goes, friends. - **Get the right glyphs**. Like the actual ones. By now everyone's heard how the Matrix glyphs are some treatment of [Katakana](https://en.wikipedia.org/wiki/Katakana), but they also include a few characters from [Susan Kare's Chicago typeface](https://en.wikipedia.org/wiki/Chicago_(typeface)). The Matrix glyphs in *this* project come from the source: cleaned up vectors [from an old SWF](https://web.archive.org/web/20070914173039/http://www.atari.com:80/thematrixpathofneo/) for an official Matrix product, archived back in 2007. That's how deep this rabbit hole goes, friends.
(Please support the [Internet Archive!](https://archive.org/about/)) (Please support the [Internet Archive!](https://archive.org/about/))
- **Get the new glyphs**. When *Resurrections* hit theaters, it debuted an expanded glyph set with a daunting *135 symbols*. Fortunately, in this age of higher resolution reference material and tie-in marketing, a decent sized sample of new glyphs were reverse-engineered from [a sparkly watch ad](https://www.hamiltonwatch.com/en-int/thematrixresurrections), and the rest were lovingly synthesized from frames of a [behind-the-scenes VFX video](https://buf.com/films/the-matrix-resurrections). - **Get the new glyphs**. When *Resurrections* hit theaters in December '21, it debuted an expanded glyph set with a daunting *135 symbols*. Virtually all of them were recovered from the movie trailers for this project and uploaded before the film's release! ...But they were of relatively poor quality. Fortunately, in this age of higher resolution reference material and tie-in marketing, a decent sized sample of new glyphs were eventually reverse-engineered from [a sparkly watch ad](https://www.hamiltonwatch.com/en-int/thematrixresurrections), and the rest were lovingly synthesized from frames of a [behind-the-scenes VFX video](https://buf.com/films/the-matrix-resurrections).
- **Make it look sweet in 2D.** This is not a cop-out. There is just no scene in the movies as iconic as the digital rain itself, and while depth effects are cool, they take away from these other details that make the difference between a goodtrix and a *greatrix*. - **Make it look sweet in 2D.** The most versatile, recognizable and mesmerizing manifestation of the code rain is when it seems to pour right down your screen like rain on a windowpane. While depth effects are cool, they can obscure the details that make the difference between a goodtrix and a *greatrix*.
- **Make it look sweet in 3D, too.** This is not me caving to pressure! To facilitate future support of stereoscopic and holographic displays, it makes sense to nail down a 3D variation. - **Make it look sweet in 3D, too.** To facilitate future support of stereoscopic and holographic displays, it made sense to nail down a 3D variation, but it looks pretty on any kind of display.
- **The 2D glyphs are in a *fixed grid* and *don't move*.** The "raindrops" we see in the 2D effect are changes in the brightness of symbols that occupy a column. To get a closer look at this, try setting the `fallSpeed` to a number close to 0. - **The 2D glyphs are in a *fixed grid* and *don't move*.** The "raindrops" we see in the effect are simply waves of illumination of stationary symbols that occupy a column. To get a better look at this, try setting the `fallSpeed` to a number close to 0.
- **Get the glow and color right.** Matrix symbols aren't just some shade of phosphorous green; they're first given a bloom effect, and then get tone-mapped to the green color palette. - **Get the glow and color right.** Matrix symbols aren't just some shade of phosphorous green; they're first given a bloom effect, and then get tone-mapped to the green color palette.
- **Symbols change shape faster as they dim.** When symbols light up, they almost never change shape, but their cycle speed increases the darker and darker they get. - **Multiple "raindrops" often occupy the same column.** This is complicated, because we can't allow them to collide. A useful approach to thinking about this is, each column's glyph brightness is a kind of [sawtooth wave](http://mathworld.wolfram.com/SawtoothWave.html), where the width of the teeth subtly fluctuate to keep things interesting.
- **Two "raindrops" can occupy the same column.** This is complicated, because we can't allow them to collide. A useful approach to thinking about this is, each column's glyph brightness is a kind of [sawtooth wave](http://mathworld.wolfram.com/SawtoothWave.html). - **Capture the glyph cycling sequence.** The symbols in the sequels' opening titles, which are arguably the highest quality versions of the 2D effect, change according to a repeating sequence (see `glyph order.txt`). This is only a technical detail, and only applies to *Reloaded* and *Revolutions*— everyplace else, the symbols change randomly.
- **Capture the glyph sequence.** Yes, the symbols in the sequels' opening titles, which are arguably the highest quality versions of the 2D effect, change according to a repeating sequence (see `glyph order.txt`). This is only a technical detail, and only applies to *Reloaded* and *Revolutions*— everyplace else, the symbols change randomly.
- **Make it free, open source and web based.** Because someone could probably improve on what I've done, and I'd like to see that, and maybe incorporate their improvements back into this project.
- **Support as many browsers and devices as possible.** This project used to rely on Three.js's GPUComputationRenderer, which only worked in browsers supporting WebGL's [oes_texture_float extension](https://caniuse.com/#search=OES_texture_float). The rewrite dropped this dependency, and gained support for a broader range of browsers and devices.
- **Whip up some artistic license and depict the *previous* Matrix versions.** The sequels describe [a paradisiacal predecessor](https://rezmason.github.io/matrix?version=paradise) to the Matrix that was too idyllic, [and another earlier, nightmarish Hobbesian version](https://rezmason.github.io/matrix?version=nightmare) that proved too campy. They depict some programs running older, differently colored code, so it's time someone tried rendering them. - **Whip up some artistic license and depict the *previous* Matrix versions.** The sequels describe [a paradisiacal predecessor](https://rezmason.github.io/matrix?version=paradise) to the Matrix that was too idyllic, [and another earlier, nightmarish Hobbesian version](https://rezmason.github.io/matrix?version=nightmare) that proved too campy. They depict some programs running older, differently colored code, so it's time someone tried rendering them.
- **Heck, try building some homemade varieties that have nothing to do with the franchise.** See the list of links above for the full set of available versions. - **Heck, try building some homemade varieties that have nothing to do with the franchise.** See the list of links above for the full set of available versions.
- **Promote a progressive interpretation of the film franchise.** *The Matrix* is an action film you can enjoy without critical analysis, but if you do read into it, you'll be rewarded. And let's be clear: **The Matrix is a story about transitioning, directed by two siblings who transitioned**. This is undeniable. Its franchise has plenty more themes, and plenty of room for interpretation, but the widely known community of misogynists who claim this imagery for their movement cannot be tolerated in any form. This is a chance to open minds, not shut them. - **Make it free, open source and web based.** Because someone could probably improve on or personalize what I've done, and I'd like to see that— and maybe incorporate their improvements back into this project.
- **Support as many browsers and devices as possible.** This project used to rely on Three.js's GPUComputationRenderer, which only worked in browsers supporting WebGL's [oes_texture_float extension](https://caniuse.com/#search=OES_texture_float). This dependency was dropped in later updates, and the project subsequently gained support for a broader range of browsers and devices.
- **Promote a progressive interpretation of the film franchise.** *The Matrix* is an action film you can enjoy without critical analysis, but if you do read into it, you'll be rewarded. And let's be clear: **The Matrix is a story about transitioning, directed by two siblings who transitioned**. This is undeniable. Its franchise has plenty more themes, and plenty of room for interpretation, but the communities of misogynists and bigots who claim this imagery for their movements cannot be tolerated in any form. This is a chance to open minds, not shut them.
--- ---
### side note: other people's Matrix effects ### side note: other people's Matrix effects
@@ -65,8 +66,6 @@ The number of implementations out there of this effect is a testament to the siz
Some of the [earliest](https://github.com/ppetr/xlockmore/blob/master/modes/matrix.c), [roughest](https://github.com/Zygo/xscreensaver/blob/d1f484cfa47f4a0862140421480bb536ad66ede9/hacks/xmatrix.c) versions were made after the film hit theaters in March, but before it was released on home media in October— people were recreating the effect purely from memory. Others probably used the official screensaver as a reference, which was made by the time-strappped developers of [the (excellent, defunct) official site](https://web.archive.org/web/*/http://whatisthematrix.com) from the images and multimedia tools they had available. Some of the [earliest](https://github.com/ppetr/xlockmore/blob/master/modes/matrix.c), [roughest](https://github.com/Zygo/xscreensaver/blob/d1f484cfa47f4a0862140421480bb536ad66ede9/hacks/xmatrix.c) versions were made after the film hit theaters in March, but before it was released on home media in October— people were recreating the effect purely from memory. Others probably used the official screensaver as a reference, which was made by the time-strappped developers of [the (excellent, defunct) official site](https://web.archive.org/web/*/http://whatisthematrix.com) from the images and multimedia tools they had available.
The fourth film in the franchise apparently comes out December 22, 2021. I'm anticipating new effects, and a flurry of new attempts at recreating them!
--- ---
### customization ### customization
@@ -76,11 +75,15 @@ You can customize the digital rain quite a bit by stapling "URL variables" to it
Now you know link fu. Here's a list of customization options: Now you know link fu. Here's a list of customization options:
- **version** - the version of the Matrix to simulate. Can be "paradise", "nightmare", "operator" or "classic" (default). - **version** - the version of the Matrix to simulate. Default is "classic".
- "classic" is the Matrix code everyone knows and loves, mostly based on the sequels' opening title graphics. - "classic" is the Matrix code everyone knows and loves, mostly based on the sequels' opening title graphics.
- "3d" is the classic code in 3D mode.
- "megacity" is a variation of the classic code that includes the Megacity as a glyph, as is seen in the opening titles of _Revolutions_.
- "operator" is more reminiscent of the matrix code as it appears in the first movie's opening titles, and on operators' screens: flatter, crowded, without a gradient, and with occasional effects (such as a square ripple). - "operator" is more reminiscent of the matrix code as it appears in the first movie's opening titles, and on operators' screens: flatter, crowded, without a gradient, and with occasional effects (such as a square ripple).
- "paradise" is how the Matrix's idyllic predecessor may have appeared: warm, simplistic, encompassing.
- "nightmare" is how the Matrix may have appeared in the Merovingian's heyday: flashy, foreboding, relentless. - "nightmare" is how the Matrix may have appeared in the Merovingian's heyday: flashy, foreboding, relentless.
- "paradise" is how the Matrix's idyllic predecessor may have appeared: warm, simplistic, encompassing.
- "resurrections" is the updated Matrix code
- "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).
- **font** - the set of glyphs to draw. Current options are "matrixcode", "resurrections", "gothic", "coptic", "huberfishA", and "huberfishD". - **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. - **width** - the number of columns (and rows) to draw. Default is 80.
- **volumetric** - when set to "true", this renders the glyphs with depth, slowly approaching the eye. Default is "false". - **volumetric** - when set to "true", this renders the glyphs with depth, slowly approaching the eye. Default is "false".
@@ -91,17 +94,23 @@ Now you know link fu. Here's a list of customization options:
- **bloomStrength** - the glow intensity, from 0 to 1. Default is 1. - **bloomStrength** - the glow intensity, from 0 to 1. Default is 1.
- **ditherMagnitude** - the amount to randomly darken pixels, to conceal [banding](https://en.wikipedia.org/wiki/Colour_banding). Default is 0.05. - **ditherMagnitude** - the amount to randomly darken pixels, to conceal [banding](https://en.wikipedia.org/wiki/Colour_banding). Default is 0.05.
- **resolution** - the image size, relative to the window size. Default is 1. Lowering this value may improve your performance, especially on high pixel density displays. - **resolution** - the image size, relative to the window size. Default is 1. Lowering this value may improve your performance, especially on high pixel density displays.
- **raindropLength** - the vertical scale of "raindrops" in the columns. Can be any number, even negative! Default is 1.0. - **raindropLength** - the vertical scale of "raindrops" in the columns. Can be any number.
- **animationSpeed** - the overall speed of the animation. Can be any number, even negative! Default is 1.0. - **animationSpeed** - the overall speed of the animation. Can be any number.
- **fallSpeed** - the speed of the rain. Can be any number, even negative! Default is 1.0. - **fallSpeed** - the speed of the rain's descent. Can be any number.
- **cycleSpeed** - the speed that the glyphs change their symbol. Can be any number, even negative! Default is 1.0. - **cycleSpeed** - the speed that the glyphs change their symbol. Can be any number.
- **effect** - alternatives to the default post-processing effect. Can be "plain", "pride", "customStripes", "none", "image" or "mirror". - **effect** - alternatives to the default post-processing effect. Can be "plain", "pride", "customStripes", "none", "image" or "mirror".
- ("none" displays the texture whose RGBA values represent the glyph shape and brightness data. _epilepsy warning_: lots of flickering) - ("none" displays the 'debug view', a behind-the-scenes look at the anatomy of the effect.)
- **camera** - some effects, ie. the mirror effect, optionally support webcam input. Can be "true" or "false". Default is false. - **camera** - some effects, ie. the mirror effect, optionally support webcam input. Can be "true" or "false". Default is false.
- **colors** - if you set the effect to "customStripes", you can specify the colors of vertical stripes as alternating *R,G,B* numeric values, like so: [https://rezmason.github.io/matrix/?effect=customStripes&colors=1,0,0,1,1,0,0,1,0](https://rezmason.github.io/matrix/?effect=customStripes&colors=1,0,0,1,1,0,0,1,0) - **colors** - if you set the effect to "customStripes", you can specify the colors of vertical stripes as alternating *R,G,B* numeric values, like so: [https://rezmason.github.io/matrix/?effect=customStripes&colors=1,0,0,1,1,0,0,1,0](https://rezmason.github.io/matrix/?effect=customStripes&colors=1,0,0,1,1,0,0,1,0)
- **url** - if you set the effect to "image", this is how you specify which image to load. It doesn't work with any URL; I suggest grabbing them from Wikipedia: [https://rezmason.github.io/matrix/?effect=image&url=https://upload.wikimedia.org/wikipedia/commons/f/f5/EagleRock.jpg](https://rezmason.github.io/matrix/?effect=image&url=https://upload.wikimedia.org/wikipedia/commons/f/f5/EagleRock.jpg) - **url** - if you set the effect to "image", this is how you specify which image to load. It doesn't work with any URL; I suggest grabbing them from Wikipedia: [https://rezmason.github.io/matrix/?effect=image&url=https://upload.wikimedia.org/wikipedia/commons/f/f5/EagleRock.jpg](https://rezmason.github.io/matrix/?effect=image&url=https://upload.wikimedia.org/wikipedia/commons/f/f5/EagleRock.jpg)
- **loops** - (WIP) if set to "true", this causes the effect to loop, so that it can be converted into a looping video. - **loops** - (WIP) if set to "true", this causes the effect to loop, so that it can be converted into a looping video.
---
### Future directions
- TODO: discuss audio
- TODO: discuss plans for a GUI
- TODO: discuss the practical challenges of "putting text in there" when the glyphs are a limited set of SDFs
--- ---
### Contributions ### Contributions
@@ -118,4 +127,4 @@ GitHub user 57r31 produced a proof of concept that led to the [interactive mirro
The glyphs are formatted as a multi-channel distance field (or MSDF) via Victor Chlumsky's [msdfgen](https://github.com/Chlumsky/msdfgen). This format preserves the crisp edges and corners of vector graphics when rendered as textures. Chlumsky's thesis paper, which is in English and is also easy to read, is [available to download here](https://dspace.cvut.cz/handle/10467/62770). The glyphs are formatted as a multi-channel distance field (or MSDF) via Victor Chlumsky's [msdfgen](https://github.com/Chlumsky/msdfgen). This format preserves the crisp edges and corners of vector graphics when rendered as textures. Chlumsky's thesis paper, which is in English and is also easy to read, is [available to download here](https://dspace.cvut.cz/handle/10467/62770).
The raindrops themselves are particles [computed on the GPU inside of a texture](https://threejs.org/examples/webgl_gpgpu_water.html), much smaller than the final render. The data sent from the CPU to the GPU every frame is negligible. That was a fun learning experience. The raindrops themselves are particles [computed on the GPU and stored in textures](https://threejs.org/examples/webgl_gpgpu_water.html), much smaller than the final render. The data sent from the CPU to the GPU every frame is negligible.

View File

@@ -16,6 +16,8 @@ Reformulate the basis
Find a way to support the old stuff? Find a way to support the old stuff?
Migrate to WebGPU Migrate to WebGPU
Update the README
Audio system Audio system
Toggle (or number representing frequency) Toggle (or number representing frequency)
Load the sound effect Load the sound effect
@@ -25,6 +27,7 @@ Audio system
Randomize pitch a little? Randomize pitch a little?
Playdate version Playdate version
Separate glyph cycling from brightness
Audio system Audio system
Falling sound Falling sound
Launch sound Launch sound

View File

@@ -62,9 +62,8 @@ const defaults = {
bloomStrength: 0.7, // The intensity of the bloom bloomStrength: 0.7, // The intensity of the bloom
bloomSize: 0.4, // The amount the bloom calculation is scaled bloomSize: 0.4, // The amount the bloom calculation is scaled
highPassThreshold: 0.1, // The minimum brightness that is still blurred highPassThreshold: 0.1, // The minimum brightness that is still blurred
cycleSpeed: 0.2, // The speed glyphs change cycleSpeed: 0.03, // The speed glyphs change
cycleFrameSkip: 1, // The global minimum number of frames between glyphs cycling cycleFrameSkip: 1, // The global minimum number of frames between glyphs cycling
cycleStyleName: "cycleFasterWhenDimmed", // The way glyphs cycle, either proportional to their brightness or randomly
baseBrightness: -0.5, // The brightness of the glyphs, before any effects are applied baseBrightness: -0.5, // The brightness of the glyphs, before any effects are applied
baseContrast: 1.1, // The contrast of the glyphs, before any effects are applied baseContrast: 1.1, // The contrast of the glyphs, before any effects are applied
brightnessOverride: 0.0, // A global override to the brightness of displayed glyphs. Only used if it is > 0. brightnessOverride: 0.0, // A global override to the brightness of displayed glyphs. Only used if it is > 0.
@@ -114,7 +113,6 @@ const versions = {
highPassThreshold: 0.0, highPassThreshold: 0.0,
cycleSpeed: 0.01, cycleSpeed: 0.01,
cycleFrameSkip: 8, cycleFrameSkip: 8,
cycleStyleName: "cycleRandomly",
brightnessOverride: 0.22, brightnessOverride: 0.22,
brightnessThreshold: 0, brightnessThreshold: 0,
fallSpeed: 0.6, fallSpeed: 0.6,
@@ -178,7 +176,6 @@ const versions = {
baseContrast: 1.17, baseContrast: 1.17,
highPassThreshold: 0, highPassThreshold: 0,
numColumns: 70, numColumns: 70,
cycleStyleName: "cycleRandomly",
cycleSpeed: 0.05, cycleSpeed: 0.05,
bloomStrength: 0.7, bloomStrength: 0.7,
fallSpeed: 0.3, fallSpeed: 0.3,
@@ -195,7 +192,6 @@ const versions = {
raindropLength: 1.2, raindropLength: 1.2,
cycleFrameSkip: 3, cycleFrameSkip: 3,
fallSpeed: 0.5, fallSpeed: 0.5,
cycleStyleName: "cycleRandomly",
slant: Math.PI * -0.0625, slant: Math.PI * -0.0625,
paletteEntries: [ paletteEntries: [
{ hsl: [0.15, 0.25, 0.9], at: 0.0 }, { hsl: [0.15, 0.25, 0.9], at: 0.0 },
@@ -208,7 +204,6 @@ const versions = {
numColumns: 50, numColumns: 50,
raindropLength: 0.9, raindropLength: 0.9,
fallSpeed: 0.1, fallSpeed: 0.1,
cycleStyleName: "cycleRandomly",
highPassThreshold: 0.0, highPassThreshold: 0.0,
paletteEntries: [ paletteEntries: [
{ hsl: [0.6, 1.0, 0.05], at: 0.0 }, { hsl: [0.6, 1.0, 0.05], at: 0.0 },
@@ -223,7 +218,6 @@ const versions = {
font: "resurrections", font: "resurrections",
numColumns: 20, numColumns: 20,
fallSpeed: 0.35, fallSpeed: 0.35,
cycleStyleName: "cycleRandomly",
cycleSpeed: 0.3, cycleSpeed: 0.3,
glyphEdgeCrop: 0.1, glyphEdgeCrop: 0.1,
ditherMagnitude: 0, ditherMagnitude: 0,

View File

@@ -7,11 +7,6 @@ const rippleTypes = {
circle: 1, circle: 1,
}; };
const cycleStyles = {
cycleFasterWhenDimmed: 0,
cycleRandomly: 1,
};
// These compute buffers are used to compute the properties of cells in the grid. // These compute buffers are used to compute the properties of cells in the grid.
// They take turns being the source and destination of a "compute" shader. // They take turns being the source and destination of a "compute" shader.
// The half float data type is crucial! It lets us store almost any real number, // The half float data type is crucial! It lets us store almost any real number,
@@ -49,7 +44,6 @@ export default ({ regl, config, lkg }) => {
// Various effect-related values // Various effect-related values
const rippleType = config.rippleTypeName in rippleTypes ? rippleTypes[config.rippleTypeName] : -1; const rippleType = config.rippleTypeName in rippleTypes ? rippleTypes[config.rippleTypeName] : -1;
const cycleStyle = config.cycleStyleName in cycleStyles ? cycleStyles[config.cycleStyleName] : 0;
const slantVec = [Math.cos(config.slant), Math.sin(config.slant)]; const slantVec = [Math.cos(config.slant), Math.sin(config.slant)];
const slantScale = 1 / (Math.abs(Math.sin(2 * config.slant)) * (Math.sqrt(2) - 1) + 1); const slantScale = 1 / (Math.abs(Math.sin(2 * config.slant)) * (Math.sqrt(2) - 1) + 1);
const showDebugView = config.effect === "none"; const showDebugView = config.effect === "none";
@@ -82,7 +76,6 @@ export default ({ regl, config, lkg }) => {
const symbolUniforms = { const symbolUniforms = {
...commonUniforms, ...commonUniforms,
...extractEntries(config, ["cycleSpeed", "cycleFrameSkip", "loops"]), ...extractEntries(config, ["cycleSpeed", "cycleFrameSkip", "loops"]),
cycleStyle,
}; };
const symbol = regl({ const symbol = regl({
frag: regl.prop("frag"), frag: regl.prop("frag"),

View File

@@ -15,7 +15,6 @@ uniform float time, tick, cycleFrameSkip;
uniform float animationSpeed, cycleSpeed; uniform float animationSpeed, cycleSpeed;
uniform bool loops, showDebugView; uniform bool loops, showDebugView;
uniform float glyphSequenceLength; uniform float glyphSequenceLength;
uniform int cycleStyle;
// Helper functions for generating randomness, borrowed from elsewhere // Helper functions for generating randomness, borrowed from elsewhere
@@ -25,44 +24,30 @@ highp float randomFloat( const in vec2 uv ) {
return fract(sin(sn) * c); return fract(sin(sn) * c);
} }
// Core functions
float getCycleSpeed(float brightness) {
float localCycleSpeed = 1.;
if (cycleStyle == 0 && brightness > 0.) {
localCycleSpeed = pow(1. - brightness, 4.);
}
return animationSpeed * cycleSpeed * localCycleSpeed;
}
// Main function // Main function
vec4 computeResult(float simTime, bool isFirstFrame, vec2 glyphPos, vec2 screenPos, vec4 previous, vec4 shine) { vec4 computeResult(float simTime, bool isFirstFrame, vec2 glyphPos, vec2 screenPos, vec4 previous, vec4 shine) {
float brightness = shine.r;
float previousSymbol = previous.r; float previousSymbol = previous.r;
float previousAge = previous.g; float previousAge = previous.g;
bool resetGlyph = isFirstFrame; bool resetGlyph = isFirstFrame;
if (loops) { if (loops) {
resetGlyph = resetGlyph || brightness <= 0.; resetGlyph = resetGlyph || shine.r <= 0.;
} }
if (resetGlyph) { if (resetGlyph) {
previousAge = randomFloat(screenPos + 0.5); previousAge = randomFloat(screenPos + 0.5);
previousSymbol = floor(glyphSequenceLength * randomFloat(screenPos)); previousSymbol = floor(glyphSequenceLength * randomFloat(screenPos));
} }
float cycleSpeed = getCycleSpeed(brightness); float cycleSpeed = animationSpeed * cycleSpeed;
float age = previousAge; float age = previousAge;
float symbol = previousSymbol; float symbol = previousSymbol;
if (mod(tick, cycleFrameSkip) == 0.) { if (mod(tick, cycleFrameSkip) == 0.) {
age += cycleSpeed * cycleFrameSkip; age += cycleSpeed * cycleFrameSkip;
float advance = floor(age); float advance = floor(age);
age = fract(age); if (advance > 0.) {
if (cycleStyle == 0) {
symbol = mod(symbol + advance, glyphSequenceLength);
} else if (cycleStyle == 1 && advance > 0.) {
symbol = floor(glyphSequenceLength * randomFloat(screenPos + simTime)); symbol = floor(glyphSequenceLength * randomFloat(screenPos + simTime));
} }
age = fract(age);
} }
vec4 result = vec4(symbol, age, 0., 0.); vec4 result = vec4(symbol, age, 0., 0.);