diff --git a/TODO.txt b/TODO.txt index 9cebec1..01cfbb8 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,12 +1,6 @@ TODO: -Reformulate the basis - Separate cursor and non-cursor parts of the code into rain pass output channels - Downstream passes can add them or color them separately - Add cursorColor to config - Switch operator/resurrections/classic to this - Tune ALL the versions! - Migrate to WebGPU +Migrate recoded changes to WebGPU Update the README diff --git a/js/config.js b/js/config.js index 50fa0e9..4f0261d 100644 --- a/js/config.js +++ b/js/config.js @@ -55,7 +55,8 @@ const defaults = { font: "matrixcode", useCamera: false, backgroundColor: [0, 0, 0], // The color "behind" the glyphs - cursorBrightness: 0, // The brightness of the "cursor" at the bottom of a raindrop + isolateCursor: true, // Whether the "cursor"— the brightest glyph at the bottom of a raindrop— has its own color + cursorColor: [1.5, 2, 0.9], // The color of the cursor volumetric: false, // A mode where the raindrops appear in perspective animationSpeed: 1, // The global rate that all animations progress forwardSpeed: 0.25, // The speed volumetric rain approaches the eye @@ -107,7 +108,7 @@ const versions = { width: 40, }, operator: { - cursorBrightness: 1, + cursorColor: [1.0, 3, 1.5], bloomSize: 0.6, bloomStrength: 0.75, highPassThreshold: 0.0, @@ -129,6 +130,7 @@ const versions = { }, nightmare: { font: "gothic", + isolateCursor: false, highPassThreshold: 0.7, baseBrightness: -0.8, brightnessDecay: 0.75, @@ -148,6 +150,7 @@ const versions = { }, paradise: { font: "coptic", + isolateCursor: false, bloomStrength: 1, highPassThreshold: 0, cycleSpeed: 0.005, @@ -171,7 +174,7 @@ const versions = { resurrections: { font: "resurrections", glyphEdgeCrop: 0.1, - cursorBrightness: 1, + cursorColor: [1.4, 2, 1.2], baseBrightness: -0.7, baseContrast: 1.17, highPassThreshold: 0, @@ -180,13 +183,14 @@ const versions = { bloomStrength: 0.7, fallSpeed: 0.3, paletteEntries: [ - { hsl: [0.38, 0.9, 0.0], at: 0.0 }, - { hsl: [0.38, 1.0, 0.6], at: 0.92 }, - { hsl: [0.38, 1.0, 1.0], at: 1.0 }, + { hsl: [0.375, 0.9, 0.0], at: 0.0 }, + { hsl: [0.375, 1.0, 0.6], at: 0.92 }, + { hsl: [0.375, 1.0, 1.0], at: 1.0 }, ], }, palimpsest: { font: "huberfishA", + isolateCursor: false, bloomStrength: 0.2, numColumns: 40, raindropLength: 1.2, @@ -200,7 +204,8 @@ const versions = { }, twilight: { font: "huberfishD", - bloomStrength: 0.3, + cursorColor: [1.5, 1, 0.9], + bloomStrength: 0.1, numColumns: 50, raindropLength: 0.9, fallSpeed: 0.1, @@ -210,7 +215,7 @@ const versions = { { hsl: [0.6, 0.8, 0.1], at: 0.1 }, { hsl: [0.88, 0.8, 0.5], at: 0.5 }, { hsl: [0.15, 1.0, 0.6], at: 0.8 }, - { hsl: [0.1, 1.0, 0.9], at: 1.0 }, + // { hsl: [0.1, 1.0, 0.9], at: 1.0 }, ], }, @@ -297,6 +302,7 @@ const paramMapping = { url: { key: "bgURL", parser: (s) => s }, stripeColors: { key: "stripeColors", parser: (s) => s }, backgroundColor: { key: "backgroundColor", parser: (s) => s.split(",").map(parseFloat) }, + cursorColor: { key: "cursorColor", parser: (s) => s.split(",").map(parseFloat) }, volumetric: { key: "volumetric", parser: (s) => s.toLowerCase().includes("true") }, loops: { key: "loops", parser: (s) => s.toLowerCase().includes("true") }, renderer: { key: "renderer", parser: (s) => s }, diff --git a/js/regl/palettePass.js b/js/regl/palettePass.js index 591089b..065ee6e 100644 --- a/js/regl/palettePass.js +++ b/js/regl/palettePass.js @@ -65,7 +65,7 @@ const makePalette = (regl, entries) => { export default ({ regl, config }, inputs) => { const output = makePassFBO(regl, config.useHalfFloat); const palette = makePalette(regl, config.paletteEntries); - const { backgroundColor, ditherMagnitude, bloomStrength } = config; + const { backgroundColor, cursorColor, ditherMagnitude, bloomStrength } = config; const palettePassFrag = loadText("shaders/glsl/palettePass.frag.glsl"); @@ -74,6 +74,7 @@ export default ({ regl, config }, inputs) => { uniforms: { backgroundColor, + cursorColor, ditherMagnitude, bloomStrength, tex: inputs.primary, diff --git a/js/regl/rainPass.js b/js/regl/rainPass.js index 005a1a8..29a548b 100644 --- a/js/regl/rainPass.js +++ b/js/regl/rainPass.js @@ -130,7 +130,7 @@ export default ({ regl, config, lkg }) => { "baseContrast", "brightnessThreshold", "brightnessOverride", - "cursorBrightness", + "isolateCursor", "glyphEdgeCrop", "isPolar", ]), diff --git a/js/regl/stripePass.js b/js/regl/stripePass.js index 496519b..903a1ef 100644 --- a/js/regl/stripePass.js +++ b/js/regl/stripePass.js @@ -31,7 +31,7 @@ const prideStripeColors = [ export default ({ regl, config }, inputs) => { const output = makePassFBO(regl, config.useHalfFloat); - const { backgroundColor, ditherMagnitude, bloomStrength } = config; + const { backgroundColor, cursorColor, ditherMagnitude, bloomStrength } = config; // Expand and convert stripe colors into 1D texture data const stripeColors = @@ -49,6 +49,7 @@ export default ({ regl, config }, inputs) => { uniforms: { backgroundColor, + cursorColor, ditherMagnitude, bloomStrength, tex: inputs.primary, diff --git a/shaders/glsl/imagePass.frag.glsl b/shaders/glsl/imagePass.frag.glsl index e7b5986..397f94f 100644 --- a/shaders/glsl/imagePass.frag.glsl +++ b/shaders/glsl/imagePass.frag.glsl @@ -15,7 +15,7 @@ void main() { vec3 bgColor = texture2D(backgroundTex, vUV).rgb; // Combine the texture and bloom, then blow it out to reveal more of the image - float brightness = pow(getBrightness(vUV).r, 1.5); + vec4 brightness = getBrightness(vUV); - gl_FragColor = vec4(bgColor * brightness, 1.0); + gl_FragColor = vec4(bgColor * (brightness.r + brightness.g * 2.0), 1.0); } diff --git a/shaders/glsl/palettePass.frag.glsl b/shaders/glsl/palettePass.frag.glsl index 8e11512..e636e9d 100644 --- a/shaders/glsl/palettePass.frag.glsl +++ b/shaders/glsl/palettePass.frag.glsl @@ -7,7 +7,7 @@ uniform sampler2D palette; uniform float bloomStrength; uniform float ditherMagnitude; uniform float time; -uniform vec3 backgroundColor; +uniform vec3 backgroundColor, cursorColor; varying vec2 vUV; highp float rand( const in vec2 uv, const in float t ) { @@ -26,11 +26,16 @@ void main() { vec4 brightnessRGB = getBrightness(vUV); // Combine the texture and bloom - float brightness = brightnessRGB.r + brightnessRGB.g + brightnessRGB.b; + vec2 brightness = brightnessRGB.rg; // Dither: subtract a random value from the brightness brightness = brightness - rand( gl_FragCoord.xy, time ) * ditherMagnitude; // Map the brightness to a position in the palette texture - gl_FragColor = texture2D( palette, vec2(brightness, 0.0)) + vec4(backgroundColor, 0.0); + gl_FragColor = vec4( + texture2D( palette, vec2(brightness.r, 0.0)).rgb + + min(cursorColor * brightness.g, 1.0) + + backgroundColor, + 1.0 + ); } diff --git a/shaders/glsl/rainPass.frag.glsl b/shaders/glsl/rainPass.frag.glsl index 87e9abe..2f461a4 100644 --- a/shaders/glsl/rainPass.frag.glsl +++ b/shaders/glsl/rainPass.frag.glsl @@ -9,13 +9,14 @@ uniform float numColumns, numRows; uniform sampler2D glyphTex; uniform float glyphHeightToWidth, glyphSequenceLength, glyphEdgeCrop; uniform float baseContrast, baseBrightness; -uniform float brightnessOverride, brightnessThreshold, cursorBrightness; +uniform float brightnessOverride, brightnessThreshold; uniform vec2 glyphTextureGridSize; uniform vec2 slantVec; uniform float slantScale; uniform bool isPolar; uniform bool showDebugView; uniform bool volumetric; +uniform bool isolateCursor; varying vec2 vUV; varying vec4 vShine, vSymbol, vEffect; @@ -57,24 +58,26 @@ vec2 getUV(vec2 uv) { return uv; } -float getBrightness(float brightness, float cursor, float multipliedEffects, float addedEffects) { +vec2 getBrightness(float brightness, float cursor, float multipliedEffects, float addedEffects) { + if (!isolateCursor) { + cursor = 0.; + } brightness = (1.0 - brightness) * baseContrast + baseBrightness; // Modes that don't fade glyphs set their actual brightness here - if (brightnessOverride > 0. && brightness > brightnessThreshold) { + if (brightnessOverride > 0. && brightness > brightnessThreshold && cursor == 0.) { brightness = brightnessOverride; } brightness *= multipliedEffects; brightness += addedEffects; - brightness = max(cursor * cursorBrightness, brightness); // In volumetric mode, distant glyphs are dimmer if (volumetric && !showDebugView) { brightness = brightness * min(1., vDepth); } - return brightness; + return vec2(brightness * (1. - cursor), brightness * cursor); } vec2 getSymbolUV(float index) { @@ -107,7 +110,7 @@ void main() { vec4 symbolData = volumetric ? vSymbol : texture2D(symbolState, uv); vec4 effectData = volumetric ? vEffect : texture2D(effectState, uv); - float brightness = getBrightness(shineData.r, shineData.g, effectData.r, effectData.g); + vec2 brightness = getBrightness(shineData.r, shineData.g, effectData.r, effectData.g); float symbol = getSymbol(uv, symbolData.r); if (showDebugView) { @@ -122,6 +125,6 @@ void main() { 1. ); } else { - gl_FragColor = vec4(brightness * symbol, 0., 0., 0.); + gl_FragColor = vec4(brightness * symbol, 0., 0.); } } diff --git a/shaders/glsl/stripePass.frag.glsl b/shaders/glsl/stripePass.frag.glsl index 9f97b31..6290392 100644 --- a/shaders/glsl/stripePass.frag.glsl +++ b/shaders/glsl/stripePass.frag.glsl @@ -7,7 +7,7 @@ uniform float bloomStrength; uniform sampler2D stripes; uniform float ditherMagnitude; uniform float time; -uniform vec3 backgroundColor; +uniform vec3 backgroundColor, cursorColor; varying vec2 vUV; highp float rand( const in vec2 uv, const in float t ) { @@ -25,10 +25,15 @@ vec4 getBrightness(vec2 uv) { void main() { vec3 color = texture2D(stripes, vUV).rgb; // Combine the texture and bloom - float brightness = getBrightness(vUV).r; + vec4 brightness = getBrightness(vUV); // Dither: subtract a random value from the brightness brightness = brightness - rand( gl_FragCoord.xy, time ) * ditherMagnitude; - gl_FragColor = vec4(color * brightness + backgroundColor, 1.0); + gl_FragColor = vec4( + color * brightness.r + + min(cursorColor * brightness.g, 1.0) + + backgroundColor, + 1.0 + ); }