mirror of
https://github.com/Rezmason/matrix.git
synced 2026-04-14 12:29:30 -07:00
You can now loop the effect. It's not super great, but it ought to make it easier to create repeating backgrounds or something.
This commit is contained in:
@@ -92,7 +92,7 @@ Now you know link fu. Here's a list of customization options:
|
|||||||
- ("none" displays the texture whose RGBA values represent the glyph shape and brightness data. _epilepsy warning_: lots of flickering)
|
- ("none" displays the texture whose RGBA values represent the glyph shape and brightness data. _epilepsy warning_: lots of flickering)
|
||||||
- **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.
|
||||||
|
|
||||||
---
|
---
|
||||||
### other details
|
### other details
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ const defaults = {
|
|||||||
useHalfFloat: false,
|
useHalfFloat: false,
|
||||||
renderer: "webgpu", // The preferred web graphics API
|
renderer: "webgpu", // The preferred web graphics API
|
||||||
useHoloplay: false,
|
useHoloplay: false,
|
||||||
|
loops: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const versions = {
|
const versions = {
|
||||||
@@ -274,6 +275,7 @@ const paramMapping = {
|
|||||||
stripeColors: { key: "stripeColors", parser: (s) => s },
|
stripeColors: { key: "stripeColors", parser: (s) => s },
|
||||||
backgroundColor: { key: "backgroundColor", parser: (s) => s.split(",").map(parseFloat) },
|
backgroundColor: { key: "backgroundColor", parser: (s) => s.split(",").map(parseFloat) },
|
||||||
volumetric: { key: "volumetric", parser: (s) => s.toLowerCase().includes("true") },
|
volumetric: { key: "volumetric", parser: (s) => s.toLowerCase().includes("true") },
|
||||||
|
loops: { key: "loops", parser: (s) => s.toLowerCase().includes("true") },
|
||||||
renderer: { key: "renderer", parser: (s) => s },
|
renderer: { key: "renderer", parser: (s) => s },
|
||||||
};
|
};
|
||||||
paramMapping.dropLength = paramMapping.raindropLength;
|
paramMapping.dropLength = paramMapping.raindropLength;
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ export default ({ regl, config, lkg }) => {
|
|||||||
"rippleScale",
|
"rippleScale",
|
||||||
"rippleSpeed",
|
"rippleSpeed",
|
||||||
"rippleThickness",
|
"rippleThickness",
|
||||||
|
"loops",
|
||||||
]),
|
]),
|
||||||
cycleStyle,
|
cycleStyle,
|
||||||
rippleType,
|
rippleType,
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ uniform float numColumns, numRows;
|
|||||||
uniform float time, tick, cycleFrameSkip;
|
uniform float time, tick, cycleFrameSkip;
|
||||||
uniform float animationSpeed, fallSpeed, cycleSpeed;
|
uniform float animationSpeed, fallSpeed, cycleSpeed;
|
||||||
|
|
||||||
uniform bool hasSun, hasThunder;
|
uniform bool hasSun, hasThunder, loops;
|
||||||
uniform bool showComputationTexture;
|
uniform bool showComputationTexture;
|
||||||
uniform float brightnessOverride, brightnessThreshold, brightnessDecay;
|
uniform float brightnessOverride, brightnessThreshold, brightnessDecay;
|
||||||
uniform float raindropLength, glyphHeightToWidth;
|
uniform float raindropLength, glyphHeightToWidth;
|
||||||
@@ -51,14 +51,18 @@ float wobble(float x) {
|
|||||||
float getRainTime(float simTime, vec2 glyphPos) {
|
float getRainTime(float simTime, vec2 glyphPos) {
|
||||||
float columnTimeOffset = randomFloat(vec2(glyphPos.x, 0.)) * 1000.;
|
float columnTimeOffset = randomFloat(vec2(glyphPos.x, 0.)) * 1000.;
|
||||||
float columnSpeedOffset = randomFloat(vec2(glyphPos.x + 0.1, 0.)) * 0.5 + 0.5;
|
float columnSpeedOffset = randomFloat(vec2(glyphPos.x + 0.1, 0.)) * 0.5 + 0.5;
|
||||||
// columnSpeedOffset = 0.; // TODO: loop
|
if (loops) {
|
||||||
|
columnSpeedOffset = 0.5;
|
||||||
|
}
|
||||||
float columnTime = columnTimeOffset + simTime * fallSpeed * columnSpeedOffset;
|
float columnTime = columnTimeOffset + simTime * fallSpeed * columnSpeedOffset;
|
||||||
return (glyphPos.y * 0.01 + columnTime) / raindropLength;
|
return (glyphPos.y * 0.01 + columnTime) / raindropLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
float getBrightness(float rainTime) {
|
float getBrightness(float rainTime) {
|
||||||
float value = 1. - fract(wobble(rainTime));
|
float value = 1. - fract(wobble(rainTime));
|
||||||
// value = 1. - fract(rainTime); // TODO: loop
|
if (loops) {
|
||||||
|
value = 1. - fract(rainTime);
|
||||||
|
}
|
||||||
return log(value * 1.25) * 3.;
|
return log(value * 1.25) * 3.;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +88,9 @@ float applySunShowerBrightness(float brightness, vec2 screenPos) {
|
|||||||
float applyThunderBrightness(float brightness, float simTime, vec2 screenPos) {
|
float applyThunderBrightness(float brightness, float simTime, vec2 screenPos) {
|
||||||
simTime *= 0.5;
|
simTime *= 0.5;
|
||||||
float thunder = 1. - fract(wobble(simTime));
|
float thunder = 1. - fract(wobble(simTime));
|
||||||
// thunder = 1. - fract(simTime + 0.3); // TODO: loop
|
if (loops) {
|
||||||
|
thunder = 1. - fract(simTime + 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
thunder = log(thunder * 1.5) * 4.;
|
thunder = log(thunder * 1.5) * 4.;
|
||||||
thunder = clamp(thunder, 0., 1.);
|
thunder = clamp(thunder, 0., 1.);
|
||||||
@@ -98,10 +104,14 @@ float applyRippleEffect(float effect, float simTime, vec2 screenPos) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float rippleTime = (simTime * 0.5 + sin(simTime) * 0.2) * rippleSpeed + 1.; // TODO: clarify
|
float rippleTime = (simTime * 0.5 + sin(simTime) * 0.2) * rippleSpeed + 1.; // TODO: clarify
|
||||||
// rippleTime = (simTime * 0.5) * rippleSpeed + 1.; // TODO: loop
|
if (loops) {
|
||||||
|
rippleTime = (simTime * 0.5) * rippleSpeed + 1.;
|
||||||
|
}
|
||||||
|
|
||||||
vec2 offset = randomVec2(vec2(floor(rippleTime), 0.)) - 0.5;
|
vec2 offset = randomVec2(vec2(floor(rippleTime), 0.)) - 0.5;
|
||||||
// offset = vec2(0.); // TODO: loop
|
if (loops) {
|
||||||
|
offset = vec2(0.);
|
||||||
|
}
|
||||||
vec2 ripplePos = screenPos * 2. - 1. + offset;
|
vec2 ripplePos = screenPos * 2. - 1. + offset;
|
||||||
float rippleDistance;
|
float rippleDistance;
|
||||||
if (rippleType == 0) {
|
if (rippleType == 0) {
|
||||||
@@ -149,7 +159,10 @@ vec4 computeResult(bool isFirstFrame, vec4 previousResult, vec2 glyphPos, vec2 s
|
|||||||
|
|
||||||
// Determine the glyph's cycle— the percent this glyph has progressed through the glyph sequence
|
// Determine the glyph's cycle— the percent this glyph has progressed through the glyph sequence
|
||||||
float previousCycle = previousResult.g;
|
float previousCycle = previousResult.g;
|
||||||
bool resetGlyph = isFirstFrame; // || previousBrightness <= 0.; // TODO: loop
|
bool resetGlyph = isFirstFrame;
|
||||||
|
if (loops) {
|
||||||
|
resetGlyph = resetGlyph || previousBrightness <= 0.;
|
||||||
|
}
|
||||||
if (resetGlyph) {
|
if (resetGlyph) {
|
||||||
previousCycle = showComputationTexture ? 0. : randomFloat(screenPos);
|
previousCycle = showComputationTexture ? 0. : randomFloat(screenPos);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ struct Config {
|
|||||||
slantScale : f32;
|
slantScale : f32;
|
||||||
slantVec : vec2<f32>;
|
slantVec : vec2<f32>;
|
||||||
volumetric : i32;
|
volumetric : i32;
|
||||||
|
loops : i32;
|
||||||
highPassThreshold : f32;
|
highPassThreshold : f32;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -127,14 +128,18 @@ fn wobble(x : f32) -> f32 {
|
|||||||
fn getRainTime(simTime : f32, glyphPos : vec2<f32>) -> f32 {
|
fn getRainTime(simTime : f32, glyphPos : vec2<f32>) -> f32 {
|
||||||
var columnTimeOffset = randomFloat(vec2<f32>(glyphPos.x, 0.0)) * 1000.0;
|
var columnTimeOffset = randomFloat(vec2<f32>(glyphPos.x, 0.0)) * 1000.0;
|
||||||
var columnSpeedOffset = randomFloat(vec2<f32>(glyphPos.x + 0.1, 0.0)) * 0.5 + 0.5;
|
var columnSpeedOffset = randomFloat(vec2<f32>(glyphPos.x + 0.1, 0.0)) * 0.5 + 0.5;
|
||||||
// columnSpeedOffset = 0.0; // TODO: loop
|
if (bool(config.loops)) {
|
||||||
|
columnSpeedOffset = 0.5;
|
||||||
|
}
|
||||||
var columnTime = columnTimeOffset + simTime * config.fallSpeed * columnSpeedOffset;
|
var columnTime = columnTimeOffset + simTime * config.fallSpeed * columnSpeedOffset;
|
||||||
return (glyphPos.y * 0.01 + columnTime) / config.raindropLength;
|
return (glyphPos.y * 0.01 + columnTime) / config.raindropLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getBrightness(rainTime : f32) -> f32 {
|
fn getBrightness(rainTime : f32) -> f32 {
|
||||||
var value = 1.0 - fract(wobble(rainTime));
|
var value = 1.0 - fract(wobble(rainTime));
|
||||||
// value = 1.0 - fract(rainTime); // TODO: loop
|
if (bool(config.loops)) {
|
||||||
|
value = 1.0 - fract(rainTime);
|
||||||
|
}
|
||||||
return log(value * 1.25) * 3.0;
|
return log(value * 1.25) * 3.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +165,9 @@ fn applySunShowerBrightness(brightness : f32, screenPos : vec2<f32>) -> f32 {
|
|||||||
fn applyThunderBrightness(brightness : f32, simTime : f32, screenPos : vec2<f32>) -> f32 {
|
fn applyThunderBrightness(brightness : f32, simTime : f32, screenPos : vec2<f32>) -> f32 {
|
||||||
var thunderTime = simTime * 0.5;
|
var thunderTime = simTime * 0.5;
|
||||||
var thunder = 1.0 - fract(wobble(thunderTime));
|
var thunder = 1.0 - fract(wobble(thunderTime));
|
||||||
// thunder = 1.0 - fract(thunderTime + 0.3); // TODO: loop
|
if (bool(config.loops)) {
|
||||||
|
thunder = 1.0 - fract(thunderTime + 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
thunder = log(thunder * 1.5) * 4.0;
|
thunder = log(thunder * 1.5) * 4.0;
|
||||||
thunder = clamp(thunder, 0.0, 1.0);
|
thunder = clamp(thunder, 0.0, 1.0);
|
||||||
@@ -174,10 +181,14 @@ fn applyRippleEffect(effect : f32, simTime : f32, screenPos : vec2<f32>) -> f32
|
|||||||
}
|
}
|
||||||
|
|
||||||
var rippleTime = (simTime * 0.5 + sin(simTime) * 0.2) * config.rippleSpeed + 1.0; // TODO: clarify
|
var rippleTime = (simTime * 0.5 + sin(simTime) * 0.2) * config.rippleSpeed + 1.0; // TODO: clarify
|
||||||
// rippleTime = (simTime * 0.5) * config.rippleSpeed + 1.0; // TODO: loop
|
if (bool(config.loops)) {
|
||||||
|
rippleTime = (simTime * 0.5) * config.rippleSpeed + 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
var offset = randomVec2(vec2<f32>(floor(rippleTime), 0.0)) - 0.5;
|
var offset = randomVec2(vec2<f32>(floor(rippleTime), 0.0)) - 0.5;
|
||||||
// offset = vec2<f32>(0.0); // TODO: loop
|
if (bool(config.loops)) {
|
||||||
|
offset = vec2<f32>(0.0);
|
||||||
|
}
|
||||||
var ripplePos = screenPos * 2.0 - 1.0 + offset;
|
var ripplePos = screenPos * 2.0 - 1.0 + offset;
|
||||||
var rippleDistance : f32;
|
var rippleDistance : f32;
|
||||||
if (config.rippleType == 0) {
|
if (config.rippleType == 0) {
|
||||||
@@ -225,7 +236,10 @@ fn computeResult (isFirstFrame : bool, previousResult : vec4<f32>, glyphPos : ve
|
|||||||
|
|
||||||
// Determine the glyph's cycle— the percent this glyph has progressed through the glyph sequence
|
// Determine the glyph's cycle— the percent this glyph has progressed through the glyph sequence
|
||||||
var previousCycle = previousResult.g;
|
var previousCycle = previousResult.g;
|
||||||
var resetGlyph = isFirstFrame; // || previousBrightness <= 0.0; // TODO: loop
|
var resetGlyph = isFirstFrame;
|
||||||
|
if (bool(config.loops)) {
|
||||||
|
resetGlyph = resetGlyph || previousBrightness < 0.0;
|
||||||
|
}
|
||||||
if (resetGlyph) {
|
if (resetGlyph) {
|
||||||
previousCycle = select(randomFloat(screenPos), 0.0, bool(config.showComputationTexture));
|
previousCycle = select(randomFloat(screenPos), 0.0, bool(config.showComputationTexture));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user