From 4add0c3324cc094d6048e1ea811bb6bf3f906418 Mon Sep 17 00:00:00 2001 From: Rezmason Date: Sun, 5 Sep 2021 21:58:00 -0700 Subject: [PATCH] The renderer now accepts a density parameter, that multiplies the columns. Glyph depth now impacts brightness. Raindrops now move forward at a steady speed. --- js/config.js | 8 +++++++ js/renderer.js | 65 +++++++++++++++++++++++++++++--------------------- 2 files changed, 46 insertions(+), 27 deletions(-) diff --git a/js/config.js b/js/config.js index fcf7f8e..f67bc80 100644 --- a/js/config.js +++ b/js/config.js @@ -18,6 +18,7 @@ const fonts = { const defaults = { animationSpeed: 1, + forwardSpeed: 0.25, bloomStrength: 1, bloomSize: 1, highPassThreshold: 0.3, @@ -39,6 +40,7 @@ const defaults = { rippleScale: 30, rippleSpeed: 0.2, numColumns: 80, + density: 1, paletteEntries: [ { rgb: [0.0, 0.0, 0.0], at: 0.0 }, { rgb: [0.09, 0.33, 0.04], at: 0.25 }, @@ -131,11 +133,17 @@ const paramMapping = { version: { key: "version", parser: s => s }, effect: { key: "effect", parser: s => s }, 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)) }, animationSpeed: { key: "animationSpeed", parser: s => nullNaN(parseFloat(s)) }, + forwardSpeed: { + key: "forwardSpeed", + parser: s => nullNaN(parseFloat(s)) + }, cycleSpeed: { key: "cycleSpeed", parser: s => nullNaN(parseFloat(s)) }, fallSpeed: { key: "fallSpeed", parser: s => nullNaN(parseFloat(s)) }, raindropLength: { diff --git a/js/renderer.js b/js/renderer.js index 84059f7..907a040 100644 --- a/js/renderer.js +++ b/js/renderer.js @@ -18,10 +18,11 @@ const cycleStyles = { const numVerticesPerGlyph = 2 * 3; -const camera = glMatrix.mat4.create(); -const transform = glMatrix.mat4.create(); - export default (regl, config) => { + + const density = config.density; + const [numRows, numColumns] = [config.numColumns, config.numColumns * density]; + // These two framebuffers are used to compute the raining code. // they take turns being the source and destination of the "compute" shader. // The half float data type is crucial! It lets us store almost any real number, @@ -30,12 +31,12 @@ export default (regl, config) => { // This double buffer is smaller than the screen, because its pixels correspond // with glyphs in the final image, and the glyphs are much larger than a pixel. const doubleBuffer = makeDoubleBuffer(regl, { - radius: config.numColumns, + width: numColumns, + height: numRows, wrapT: "clamp", type: "half float" }); - const numColumns = config.numColumns; const output = makePassFBO(regl, config.useHalfFloat); @@ -43,7 +44,7 @@ export default (regl, config) => { // rain general "glyphHeightToWidth", "glyphTextureColumns", - "numColumns", + "density", // rain update "animationSpeed", "brightnessMinimum", @@ -60,11 +61,16 @@ export default (regl, config) => { "rippleScale", "rippleSpeed", "rippleThickness", + // rain vertex + "forwardSpeed", // rain render "glyphEdgeCrop", - "isPolar" + "isPolar", ]); + uniforms.numRows = numRows; + uniforms.numColumns = numColumns; + uniforms.rippleType = config.rippleTypeName in rippleTypes ? rippleTypes[config.rippleTypeName] @@ -95,7 +101,7 @@ export default (regl, config) => { #define SQRT_5 2.23606797749979 uniform float time; - uniform float numColumns; + uniform float numColumns, numRows; uniform sampler2D lastState; uniform bool hasSun; uniform bool hasThunder; @@ -197,7 +203,7 @@ export default (regl, config) => { void main() { vec2 glyphPos = gl_FragCoord.xy; - vec2 screenPos = glyphPos / numColumns; + vec2 screenPos = glyphPos / vec2(numColumns, numRows); float simTime = time * animationSpeed; // Read the current values of the glyph @@ -258,9 +264,9 @@ export default (regl, config) => { framebuffer: doubleBuffer.front }); - const numGlyphs = numColumns * numColumns; + const numGlyphs = numRows * numColumns; - const glyphPositions = Array(numColumns).fill().map((_, y) => + const glyphPositions = Array(numRows).fill().map((_, y) => Array(numColumns).fill().map((_, x) => Array(numVerticesPerGlyph).fill([x, y]) ) @@ -291,8 +297,9 @@ export default (regl, config) => { precision lowp float; attribute vec2 aPosition, aCorner; uniform float width, height; - uniform float numColumns; + uniform float numColumns, numRows, density; uniform sampler2D lastState; + uniform float forwardSpeed; varying vec2 vUV; varying vec4 vGlyph; uniform mat4 camera; @@ -300,11 +307,13 @@ export default (regl, config) => { uniform float time; uniform bool showComputationTexture; void main() { - vUV = (aPosition + aCorner) / numColumns; - vec2 position = (vUV - 0.5) * 2.0; - vGlyph = texture2D(lastState, vUV + (0.5 - aCorner) / numColumns); + vUV = (aPosition + aCorner) / vec2(numColumns, numRows); + vec2 position = (aPosition + aCorner * vec2(density, 1.)) / vec2(numColumns, numRows); + position = (position - 0.5) * 2.0; + vGlyph = texture2D(lastState, vUV + (0.5 - aCorner) / vec2(numColumns, numRows)); - float glyphDepth = showComputationTexture ? 0. : vGlyph.b; + float glyphDepth = showComputationTexture ? 0. : fract(vGlyph.b + time * forwardSpeed); + vGlyph.b = glyphDepth; vec4 pos = camera * transform * vec4(position, glyphDepth, 1.0); // Scale the geometry to cover the longest dimension of the viewport @@ -322,7 +331,7 @@ export default (regl, config) => { #endif precision lowp float; - uniform float numColumns; + uniform float numColumns, numRows; uniform sampler2D glyphTex; uniform float glyphHeightToWidth, glyphSequenceLength, glyphTextureColumns, glyphEdgeCrop; uniform vec2 slantVec; @@ -377,10 +386,12 @@ export default (regl, config) => { float effect = vGlyph.a; brightness = max(effect, brightness); float symbolIndex = getSymbolIndex(vGlyph.g); + float glyphDepth = vGlyph.b; + float depthFade = min(1.0, glyphDepth * 1.25); // resolve UV to MSDF texture coord vec2 symbolUV = vec2(mod(symbolIndex, glyphTextureColumns), floor(symbolIndex / glyphTextureColumns)); - vec2 glyphUV = fract(uv * numColumns); + vec2 glyphUV = fract(uv * vec2(numColumns, numRows)); glyphUV -= 0.5; glyphUV *= clamp(1.0 - glyphEdgeCrop, 0.0, 1.0); glyphUV += 0.5; @@ -391,7 +402,7 @@ export default (regl, config) => { float sigDist = median3(dist) - 0.5; float alpha = clamp(sigDist/fwidth(sigDist) + 0.5, 0.0, 1.0); - gl_FragColor = vec4(vec3(brightness * alpha), 1.0); + gl_FragColor = vec4(vec3(brightness * alpha * depthFade), 1.0); } `, @@ -410,8 +421,13 @@ export default (regl, config) => { framebuffer: output }); - const translation = glMatrix.vec3.set(glMatrix.vec3.create(), 0, 0, -1); - const scale = glMatrix.vec3.set(glMatrix.vec3.create(), 3, 3, 1); + const {mat4, vec3} = glMatrix; + const camera = mat4.create(); + const translation = vec3.set(vec3.create(), 0, 0.5 / numRows, -1); + const scale = vec3.set(vec3.create(), 1, 1, 1); + const transform = mat4.create(); + mat4.translate(transform, transform, translation); + mat4.scale(transform, transform, scale); return makePass( { @@ -421,11 +437,6 @@ export default (regl, config) => { const time = Date.now(); - glMatrix.mat4.identity(transform); - glMatrix.mat4.translate(transform, transform, translation); - glMatrix.mat4.scale(transform, transform, scale); - glMatrix.mat4.rotateY(transform, transform, Math.PI * 2 * Math.sin(time * 0.001) * 0.05); - update(); regl.clear({ depth: 1, @@ -437,7 +448,7 @@ export default (regl, config) => { (w, h) => { output.resize(w, h); const aspectRatio = w / h; - glMatrix.mat4.perspective(camera, (Math.PI / 180) * 150, aspectRatio, 0.0001, 1000); + glMatrix.mat4.perspective(camera, (Math.PI / 180) * 90, aspectRatio, 0.0001, 1000); }, msdfLoader.ready );