Renaming shine to raindrop, which makes more sense

This commit is contained in:
Rezmason
2022-09-16 16:02:06 -07:00
parent 6969514c9b
commit 3fc53f1bab
7 changed files with 41 additions and 41 deletions

View File

@@ -51,7 +51,7 @@ The following the criteria that guided the development process:
- **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 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.
- **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.
- **Multiple "raindrops" often occupy the same column.** This is complicated, because we can't allow them to collide. The solution in this project is to model 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. The tips of those teeth— the cells in the grid where the sawtooth dips— are where we put the "cursors" (or "tracers") at the bottom of each raindrop.
- **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.
- **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.

View File

@@ -55,20 +55,20 @@ export default ({ regl, config, lkg }) => {
showDebugView,
};
const shineDoubleBuffer = makeComputeDoubleBuffer(regl, numRows, numColumns);
const rainPassShine = loadText("shaders/glsl/rainPass.shine.frag.glsl");
const shineUniforms = {
const raindropDoubleBuffer = makeComputeDoubleBuffer(regl, numRows, numColumns);
const rainPassShine = loadText("shaders/glsl/rainPass.raindrop.frag.glsl");
const raindropUniforms = {
...commonUniforms,
...extractEntries(config, ["brightnessDecay", "fallSpeed", "raindropLength", "loops"]),
};
const shine = regl({
const raindrop = regl({
frag: regl.prop("frag"),
uniforms: {
...shineUniforms,
previousShineState: shineDoubleBuffer.back,
...raindropUniforms,
previousShineState: raindropDoubleBuffer.back,
},
framebuffer: shineDoubleBuffer.front,
framebuffer: raindropDoubleBuffer.front,
});
const symbolDoubleBuffer = makeComputeDoubleBuffer(regl, numRows, numColumns);
@@ -81,7 +81,7 @@ export default ({ regl, config, lkg }) => {
frag: regl.prop("frag"),
uniforms: {
...symbolUniforms,
shineState: shineDoubleBuffer.front,
raindropState: raindropDoubleBuffer.front,
previousSymbolState: symbolDoubleBuffer.back,
},
@@ -99,7 +99,7 @@ export default ({ regl, config, lkg }) => {
frag: regl.prop("frag"),
uniforms: {
...effectUniforms,
shineState: shineDoubleBuffer.front,
raindropState: raindropDoubleBuffer.front,
previousEffectState: effectDoubleBuffer.back,
},
@@ -156,7 +156,7 @@ export default ({ regl, config, lkg }) => {
uniforms: {
...renderUniforms,
shineState: shineDoubleBuffer.front,
raindropState: raindropDoubleBuffer.front,
symbolState: symbolDoubleBuffer.front,
effectState: effectDoubleBuffer.front,
glyphTex: msdf.texture,
@@ -251,7 +251,7 @@ export default ({ regl, config, lkg }) => {
[screenSize[0], screenSize[1]] = aspectRatio > 1 ? [1, aspectRatio] : [1 / aspectRatio, 1];
},
() => {
shine({ frag: rainPassShine.text() });
raindrop({ frag: rainPassShine.text() });
symbol({ frag: rainPassSymbol.text() });
effect({ frag: rainPassEffect.text() });
regl.clear({

View File

@@ -4,7 +4,7 @@
#endif
precision lowp float;
uniform sampler2D shineState, symbolState, effectState;
uniform sampler2D raindropState, symbolState, effectState;
uniform float numColumns, numRows;
uniform sampler2D glyphTex;
uniform float glyphHeightToWidth, glyphSequenceLength, glyphEdgeCrop;
@@ -106,21 +106,21 @@ void main() {
vec2 uv = getUV(vUV);
// Unpack the values from the data textures
vec4 shineData = volumetric ? vShine : texture2D( shineState, uv);
vec4 raindropData = volumetric ? vShine : texture2D( raindropState, uv);
vec4 symbolData = volumetric ? vSymbol : texture2D(symbolState, uv);
vec4 effectData = volumetric ? vEffect : texture2D(effectState, uv);
vec2 brightness = getBrightness(shineData.r, shineData.g, effectData.r, effectData.g);
vec2 brightness = getBrightness(raindropData.r, raindropData.g, effectData.r, effectData.g);
float symbol = getSymbol(uv, symbolData.r);
if (showDebugView) {
gl_FragColor = vec4(
vec3(
shineData.g,
raindropData.g,
vec2(
1.0 - (shineData.r * 3.0),
1.0 - (shineData.r * 8.0)
) * (1.0 - shineData.g)
1.0 - (raindropData.r * 3.0),
1.0 - (raindropData.r * 8.0)
) * (1.0 - raindropData.g)
) * symbol,
1.
);

View File

@@ -45,7 +45,7 @@ float wobble(float x) {
// This is the code rain's key underlying concept.
// It's why glyphs that share a column are lit simultaneously, and are brighter toward the bottom.
// It's also why those bright areas are truncated into raindrops.
float getBrightness(float simTime, vec2 glyphPos) {
float getRainBrightness(float simTime, vec2 glyphPos) {
float columnTimeOffset = randomFloat(vec2(glyphPos.x, 0.)) * 1000.;
float columnSpeedOffset = randomFloat(vec2(glyphPos.x + 0.1, 0.)) * 0.5 + 0.5;
if (loops) {
@@ -62,8 +62,8 @@ float getBrightness(float simTime, vec2 glyphPos) {
// Main function
vec4 computeResult(float simTime, bool isFirstFrame, vec2 glyphPos, vec2 screenPos, vec4 previous) {
float brightness = getBrightness(simTime, glyphPos);
float brightnessBelow = getBrightness(simTime, glyphPos + vec2(0., -1.));
float brightness = getRainBrightness(simTime, glyphPos);
float brightnessBelow = getRainBrightness(simTime, glyphPos + vec2(0., -1.));
float cursor = brightness < brightnessBelow ? 1.0 : 0.0;
// Blend the glyph's brightness with its previous brightness, so it winks on and off organically

View File

@@ -9,7 +9,7 @@ precision highp float;
#define PI 3.14159265359
uniform sampler2D previousSymbolState, shineState;
uniform sampler2D previousSymbolState, raindropState;
uniform float numColumns, numRows;
uniform float time, tick, cycleFrameSkip;
uniform float animationSpeed, cycleSpeed;
@@ -26,13 +26,13 @@ highp float randomFloat( const in vec2 uv ) {
// 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 raindrop) {
float previousSymbol = previous.r;
float previousAge = previous.g;
bool resetGlyph = isFirstFrame;
if (loops) {
resetGlyph = resetGlyph || shine.r <= 0.;
resetGlyph = resetGlyph || raindrop.r <= 0.;
}
if (resetGlyph) {
previousAge = randomFloat(screenPos + 0.5);
@@ -60,6 +60,6 @@ void main() {
vec2 glyphPos = gl_FragCoord.xy;
vec2 screenPos = glyphPos / vec2(numColumns, numRows);
vec4 previous = texture2D( previousSymbolState, screenPos );
vec4 shine = texture2D( shineState, screenPos );
gl_FragColor = computeResult(simTime, isFirstFrame, glyphPos, screenPos, previous, shine);
vec4 raindrop = texture2D( raindropState, screenPos );
gl_FragColor = computeResult(simTime, isFirstFrame, glyphPos, screenPos, previous, raindrop);
}

View File

@@ -1,7 +1,7 @@
#define PI 3.14159265359
precision lowp float;
attribute vec2 aPosition, aCorner;
uniform sampler2D shineState, symbolState, effectState;
uniform sampler2D raindropState, symbolState, effectState;
uniform float density;
uniform vec2 quadSize;
uniform float glyphHeightToWidth, glyphVerticalSpacing;
@@ -22,7 +22,7 @@ highp float rand( const in vec2 uv ) {
void main() {
vUV = (aPosition + aCorner) * quadSize;
vShine = texture2D(shineState, aPosition * quadSize);
vShine = texture2D(raindropState, aPosition * quadSize);
vSymbol = texture2D(symbolState, aPosition * quadSize);
vEffect = texture2D(effectState, aPosition * quadSize);

View File

@@ -56,7 +56,7 @@ struct Scene {
};
struct Cell {
shine : vec4<f32>,
raindrop : vec4<f32>,
symbol : vec4<f32>,
};
@@ -246,9 +246,9 @@ fn computeShine (simTime : f32, isFirstFrame : bool, glyphPos : vec2<f32>, scree
return result;
}
fn computeSymbol (simTime : f32, isFirstFrame : bool, glyphPos : vec2<f32>, screenPos : vec2<f32>, previous : vec4<f32>, shine : vec4<f32>) -> vec4<f32> {
fn computeSymbol (simTime : f32, isFirstFrame : bool, glyphPos : vec2<f32>, screenPos : vec2<f32>, previous : vec4<f32>, raindrop : vec4<f32>) -> vec4<f32> {
var brightness = shine.r;
var brightness = raindrop.r;
var previousSymbol = previous.r;
var previousAge = previous.g;
@@ -298,8 +298,8 @@ fn computeSymbol (simTime : f32, isFirstFrame : bool, glyphPos : vec2<f32>, scre
var screenPos = glyphPos / config.gridSize;
var cell = cells_RW.cells[i];
cell.shine = computeShine(simTime, isFirstFrame, glyphPos, screenPos, cell.shine);
cell.symbol = computeSymbol(simTime, isFirstFrame, glyphPos, screenPos, cell.symbol, cell.shine);
cell.raindrop = computeShine(simTime, isFirstFrame, glyphPos, screenPos, cell.raindrop);
cell.symbol = computeSymbol(simTime, isFirstFrame, glyphPos, screenPos, cell.symbol, cell.raindrop);
cells_RW.cells[i] = cell;
}
@@ -407,15 +407,15 @@ fn getSymbolUV(symbol : i32) -> vec2<f32> {
var cell = cells_RO.cells[gridIndex];
var symbolUV = getSymbolUV(i32(cell.symbol.r));
var brightness = cell.shine.r;
var brightness = cell.raindrop.r;
// Modes that don't fade glyphs set their actual brightness here
if (config.brightnessOverride > 0.0 && brightness > config.brightnessThreshold) {
brightness = config.brightnessOverride;
}
brightness = max(cell.shine.b * config.cursorBrightness, brightness);
brightness = max(cell.shine.a, brightness);
brightness = max(cell.raindrop.b * config.cursorBrightness, brightness);
brightness = max(cell.raindrop.a, brightness);
// In volumetric mode, distant glyphs are dimmer
if (volumetric) {
@@ -440,11 +440,11 @@ fn getSymbolUV(symbol : i32) -> vec2<f32> {
if (bool(config.showDebugView)) {
output.color = vec4<f32>(
vec3<f32>(
cell.shine.b,
cell.raindrop.b,
vec2<f32>(
1.0 - (cell.shine.g * 3.0),
1.0 - (cell.shine.g * 10.0)
) * (1.0 - cell.shine.b)
1.0 - (cell.raindrop.g * 3.0),
1.0 - (cell.raindrop.g * 10.0)
) * (1.0 - cell.raindrop.b)
) * alpha,
1.
);