mirror of
https://github.com/Rezmason/matrix.git
synced 2026-04-14 12:29:30 -07:00
Renaming shine to raindrop, which makes more sense
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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.
|
||||
);
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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.
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user