mirror of
https://github.com/Rezmason/matrix.git
synced 2026-04-21 07:19:30 -07:00
Cursors are now much more robustly detected, and the debug view— previously called the computation texture— now resembles BUF's behind-the-scenes VFX footage. Isolated the isometric camera option from the debug view
This commit is contained in:
10
TODO.txt
10
TODO.txt
@@ -1,9 +1,13 @@
|
|||||||
TODO:
|
TODO:
|
||||||
|
|
||||||
|
Create a Resurrections font
|
||||||
|
Icomoon
|
||||||
|
Unicode PUA
|
||||||
|
|
||||||
Reformulate the basis
|
Reformulate the basis
|
||||||
https://buf.com/films/the-matrix-resurrections
|
https://buf.com/films/the-matrix-resurrections
|
||||||
Base cursors and other colors on BUF clip
|
Base cursors and other colors on BUF clip
|
||||||
Show this stuff for showComputationTexture
|
Show this stuff for showDebugView
|
||||||
Pixel grill?
|
Pixel grill?
|
||||||
Tune the colors
|
Tune the colors
|
||||||
Maybe glow can be an SDF-derived effect instead, look into it
|
Maybe glow can be an SDF-derived effect instead, look into it
|
||||||
@@ -29,10 +33,6 @@ Playdate version
|
|||||||
https://sdk.play.date/1.12.3/Inside%20Playdate.html#pdxinfo
|
https://sdk.play.date/1.12.3/Inside%20Playdate.html#pdxinfo
|
||||||
Menu later?
|
Menu later?
|
||||||
|
|
||||||
Create a Resurrections font
|
|
||||||
Icomoon
|
|
||||||
Unicode PUA
|
|
||||||
|
|
||||||
Resurrections
|
Resurrections
|
||||||
Support anomaly streaks
|
Support anomaly streaks
|
||||||
MSDF
|
MSDF
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ const defaults = {
|
|||||||
resolution: 0.75, // An overall scale multiplier
|
resolution: 0.75, // An overall scale multiplier
|
||||||
useHalfFloat: false,
|
useHalfFloat: false,
|
||||||
renderer: "webgpu", // The preferred web graphics API
|
renderer: "webgpu", // The preferred web graphics API
|
||||||
|
isometric: false,
|
||||||
useHoloplay: false,
|
useHoloplay: false,
|
||||||
loops: false,
|
loops: false,
|
||||||
};
|
};
|
||||||
@@ -308,6 +309,7 @@ const paramMapping = {
|
|||||||
loops: { key: "loops", 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 },
|
||||||
once: { key: "once", parser: (s) => s.toLowerCase().includes("true") },
|
once: { key: "once", parser: (s) => s.toLowerCase().includes("true") },
|
||||||
|
isometric: { key: "isometric", parser: (s) => s.toLowerCase().includes("true") },
|
||||||
};
|
};
|
||||||
paramMapping.dropLength = paramMapping.raindropLength;
|
paramMapping.dropLength = paramMapping.raindropLength;
|
||||||
paramMapping.angle = paramMapping.slant;
|
paramMapping.angle = paramMapping.slant;
|
||||||
|
|||||||
@@ -37,13 +37,13 @@ export default ({ regl, config, lkg }) => {
|
|||||||
const cycleStyle = config.cycleStyleName in cycleStyles ? cycleStyles[config.cycleStyleName] : 0;
|
const cycleStyle = config.cycleStyleName in cycleStyles ? cycleStyles[config.cycleStyleName] : 0;
|
||||||
const slantVec = [Math.cos(config.slant), Math.sin(config.slant)];
|
const slantVec = [Math.cos(config.slant), Math.sin(config.slant)];
|
||||||
const slantScale = 1 / (Math.abs(Math.sin(2 * config.slant)) * (Math.sqrt(2) - 1) + 1);
|
const slantScale = 1 / (Math.abs(Math.sin(2 * config.slant)) * (Math.sqrt(2) - 1) + 1);
|
||||||
const showComputationTexture = config.effect === "none";
|
const showDebugView = config.effect === "none";
|
||||||
|
|
||||||
const commonUniforms = {
|
const commonUniforms = {
|
||||||
...extractEntries(config, ["animationSpeed", "glyphHeightToWidth", "glyphSequenceLength", "glyphTextureGridSize"]),
|
...extractEntries(config, ["animationSpeed", "glyphHeightToWidth", "glyphSequenceLength", "glyphTextureGridSize"]),
|
||||||
numColumns,
|
numColumns,
|
||||||
numRows,
|
numRows,
|
||||||
showComputationTexture,
|
showDebugView,
|
||||||
};
|
};
|
||||||
|
|
||||||
// These two framebuffers are used to compute the raining code.
|
// These two framebuffers are used to compute the raining code.
|
||||||
@@ -182,7 +182,7 @@ export default ({ regl, config, lkg }) => {
|
|||||||
const screenSize = [1, 1];
|
const screenSize = [1, 1];
|
||||||
const { mat4, vec3 } = glMatrix;
|
const { mat4, vec3 } = glMatrix;
|
||||||
const transform = mat4.create();
|
const transform = mat4.create();
|
||||||
if (config.effect === "none") {
|
if (volumetric && config.isometric) {
|
||||||
mat4.rotateX(transform, transform, (Math.PI * 1) / 8);
|
mat4.rotateX(transform, transform, (Math.PI * 1) / 8);
|
||||||
mat4.rotateY(transform, transform, (Math.PI * 1) / 4);
|
mat4.rotateY(transform, transform, (Math.PI * 1) / 4);
|
||||||
mat4.translate(transform, transform, vec3.fromValues(0, 0, -1));
|
mat4.translate(transform, transform, vec3.fromValues(0, 0, -1));
|
||||||
@@ -217,7 +217,7 @@ export default ({ regl, config, lkg }) => {
|
|||||||
const index = column + row * numTileColumns;
|
const index = column + row * numTileColumns;
|
||||||
const camera = mat4.create();
|
const camera = mat4.create();
|
||||||
|
|
||||||
if (config.effect === "none") {
|
if (volumetric && config.isometric) {
|
||||||
if (aspectRatio > 1) {
|
if (aspectRatio > 1) {
|
||||||
mat4.ortho(camera, -1.5 * aspectRatio, 1.5 * aspectRatio, -1.5, 1.5, -1000, 1000);
|
mat4.ortho(camera, -1.5 * aspectRatio, 1.5 * aspectRatio, -1.5, 1.5, -1000, 1000);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ const makeConfigBuffer = (device, configUniforms, config, density, gridSize) =>
|
|||||||
...config,
|
...config,
|
||||||
gridSize,
|
gridSize,
|
||||||
density,
|
density,
|
||||||
showComputationTexture: config.effect === "none",
|
showDebugView: config.effect === "none",
|
||||||
cycleStyle: config.cycleStyleName in cycleStyles ? cycleStyles[config.cycleStyleName] : 0,
|
cycleStyle: config.cycleStyleName in cycleStyles ? cycleStyles[config.cycleStyleName] : 0,
|
||||||
rippleType: config.rippleTypeName in rippleTypes ? rippleTypes[config.rippleTypeName] : -1,
|
rippleType: config.rippleTypeName in rippleTypes ? rippleTypes[config.rippleTypeName] : -1,
|
||||||
slantScale: 1 / (Math.abs(Math.sin(2 * config.slant)) * (Math.sqrt(2) - 1) + 1),
|
slantScale: 1 / (Math.abs(Math.sin(2 * config.slant)) * (Math.sqrt(2) - 1) + 1),
|
||||||
@@ -45,7 +45,7 @@ export default ({ config, device, timeBuffer }) => {
|
|||||||
const numQuads = config.volumetric ? numCells : 1;
|
const numQuads = config.volumetric ? numCells : 1;
|
||||||
|
|
||||||
const transform = mat4.create();
|
const transform = mat4.create();
|
||||||
if (config.effect === "none") {
|
if (config.volumetric && config.isometric) {
|
||||||
mat4.rotateX(transform, transform, (Math.PI * 1) / 8);
|
mat4.rotateX(transform, transform, (Math.PI * 1) / 8);
|
||||||
mat4.rotateY(transform, transform, (Math.PI * 1) / 4);
|
mat4.rotateY(transform, transform, (Math.PI * 1) / 4);
|
||||||
mat4.translate(transform, transform, vec3.fromValues(0, 0, -1));
|
mat4.translate(transform, transform, vec3.fromValues(0, 0, -1));
|
||||||
@@ -153,7 +153,7 @@ export default ({ config, device, timeBuffer }) => {
|
|||||||
const build = (size) => {
|
const build = (size) => {
|
||||||
// Update scene buffer: camera and transform math for the volumetric mode
|
// Update scene buffer: camera and transform math for the volumetric mode
|
||||||
const aspectRatio = size[0] / size[1];
|
const aspectRatio = size[0] / size[1];
|
||||||
if (config.effect === "none") {
|
if (config.volumetric && config.isometric) {
|
||||||
if (aspectRatio > 1) {
|
if (aspectRatio > 1) {
|
||||||
mat4.orthoZO(camera, -1.5 * aspectRatio, 1.5 * aspectRatio, -1.5, 1.5, -1000, 1000);
|
mat4.orthoZO(camera, -1.5 * aspectRatio, 1.5 * aspectRatio, -1.5, 1.5, -1000, 1000);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ uniform vec2 glyphTextureGridSize;
|
|||||||
uniform vec2 slantVec;
|
uniform vec2 slantVec;
|
||||||
uniform float slantScale;
|
uniform float slantScale;
|
||||||
uniform bool isPolar;
|
uniform bool isPolar;
|
||||||
uniform bool showComputationTexture;
|
uniform bool showDebugView;
|
||||||
uniform bool volumetric;
|
uniform bool volumetric;
|
||||||
|
|
||||||
varying vec2 vUV;
|
varying vec2 vUV;
|
||||||
@@ -76,7 +76,7 @@ void main() {
|
|||||||
brightness = max(shine.b * cursorBrightness, brightness);
|
brightness = max(shine.b * cursorBrightness, brightness);
|
||||||
brightness = max(shine.a, brightness);
|
brightness = max(shine.a, brightness);
|
||||||
// In volumetric mode, distant glyphs are dimmer
|
// In volumetric mode, distant glyphs are dimmer
|
||||||
if (volumetric) {
|
if (volumetric && !showDebugView) {
|
||||||
brightness = brightness * min(1., vDepth);
|
brightness = brightness * min(1., vDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,12 +92,18 @@ void main() {
|
|||||||
float sigDist = median3(dist) - 0.5;
|
float sigDist = median3(dist) - 0.5;
|
||||||
float alpha = clamp(sigDist/fwidth(sigDist) + 0.5, 0., 1.);
|
float alpha = clamp(sigDist/fwidth(sigDist) + 0.5, 0., 1.);
|
||||||
|
|
||||||
if (showComputationTexture) {
|
if (showDebugView) {
|
||||||
vec4 debugColor = vec4(shine.r - alpha, shine.g * alpha, shine.a - alpha, 1.);
|
brightness *= 2.;
|
||||||
if (volumetric) {
|
gl_FragColor = vec4(
|
||||||
debugColor.g = debugColor.g * 0.9 + 0.1;
|
vec3(
|
||||||
}
|
shine.b,
|
||||||
gl_FragColor = debugColor;
|
vec2(
|
||||||
|
brightness,
|
||||||
|
clamp(0., 1., pow(brightness * 0.9, 6.0))
|
||||||
|
) * (1.0 - shine.b)
|
||||||
|
) * alpha,
|
||||||
|
1.
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
gl_FragColor = vec4(vChannel * brightness * alpha, 1.);
|
gl_FragColor = vec4(vChannel * brightness * alpha, 1.);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,11 +55,11 @@ float getRainTime(float simTime, vec2 glyphPos) {
|
|||||||
columnSpeedOffset = 0.5;
|
columnSpeedOffset = 0.5;
|
||||||
}
|
}
|
||||||
float columnTime = columnTimeOffset + simTime * fallSpeed * columnSpeedOffset;
|
float columnTime = columnTimeOffset + simTime * fallSpeed * columnSpeedOffset;
|
||||||
return (glyphPos.y * 0.01 + columnTime) / raindropLength;
|
return wobble((glyphPos.y * 0.01 + columnTime) / raindropLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
float getBrightness(float rainTime) {
|
float getBrightness(float rainTime) {
|
||||||
float value = 1. - fract(wobble(rainTime));
|
float value = 1. - fract(rainTime);
|
||||||
if (loops) {
|
if (loops) {
|
||||||
value = 1. - fract(rainTime);
|
value = 1. - fract(rainTime);
|
||||||
}
|
}
|
||||||
@@ -122,10 +122,12 @@ float applyRippleEffect(float effect, float simTime, vec2 screenPos) {
|
|||||||
|
|
||||||
// Main function
|
// Main function
|
||||||
|
|
||||||
vec4 computeResult(float simTime, bool isFirstFrame, vec2 glyphPos, vec2 screenPos, vec4 previous, vec4 previousBelow) {
|
vec4 computeResult(float simTime, bool isFirstFrame, vec2 glyphPos, vec2 screenPos, vec4 previous) {
|
||||||
|
|
||||||
// Determine the glyph's local time.
|
// Determine the glyph's local time.
|
||||||
float rainTime = getRainTime(simTime, glyphPos);
|
float rainTime = getRainTime(simTime, glyphPos);
|
||||||
|
float rainTimeBelow = getRainTime(simTime, glyphPos + vec2(0., -1.));
|
||||||
|
float cursor = fract(rainTime) < fract(rainTimeBelow) ? 1.0 : 0.0;
|
||||||
|
|
||||||
// Rain time is the backbone of this effect.
|
// Rain time is the backbone of this effect.
|
||||||
|
|
||||||
@@ -139,9 +141,6 @@ vec4 computeResult(float simTime, bool isFirstFrame, vec2 glyphPos, vec2 screenP
|
|||||||
float effect = 0.;
|
float effect = 0.;
|
||||||
effect = applyRippleEffect(effect, simTime, screenPos); // Round or square ripples across the grid
|
effect = applyRippleEffect(effect, simTime, screenPos); // Round or square ripples across the grid
|
||||||
|
|
||||||
float previousBrightnessBelow = previousBelow.r;
|
|
||||||
float cursor = brightness > previousBrightnessBelow ? 1.0 : 0.0;
|
|
||||||
|
|
||||||
// Blend the glyph's brightness with its previous brightness, so it winks on and off organically
|
// Blend the glyph's brightness with its previous brightness, so it winks on and off organically
|
||||||
if (!isFirstFrame) {
|
if (!isFirstFrame) {
|
||||||
float previousBrightness = previous.r;
|
float previousBrightness = previous.r;
|
||||||
@@ -158,6 +157,5 @@ void main() {
|
|||||||
vec2 glyphPos = gl_FragCoord.xy;
|
vec2 glyphPos = gl_FragCoord.xy;
|
||||||
vec2 screenPos = glyphPos / vec2(numColumns, numRows);
|
vec2 screenPos = glyphPos / vec2(numColumns, numRows);
|
||||||
vec4 previous = texture2D( previousShineState, screenPos );
|
vec4 previous = texture2D( previousShineState, screenPos );
|
||||||
vec4 previousBelow = texture2D( previousShineState, screenPos + vec2(0., -1. / numRows));
|
gl_FragColor = computeResult(simTime, isFirstFrame, glyphPos, screenPos, previous);
|
||||||
gl_FragColor = computeResult(simTime, isFirstFrame, glyphPos, screenPos, previous, previousBelow);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ uniform sampler2D previousSymbolState, shineState;
|
|||||||
uniform float numColumns, numRows;
|
uniform float numColumns, numRows;
|
||||||
uniform float time, tick, cycleFrameSkip;
|
uniform float time, tick, cycleFrameSkip;
|
||||||
uniform float animationSpeed, cycleSpeed;
|
uniform float animationSpeed, cycleSpeed;
|
||||||
uniform bool loops, showComputationTexture;
|
uniform bool loops, showDebugView;
|
||||||
uniform float glyphSequenceLength;
|
uniform float glyphSequenceLength;
|
||||||
uniform int cycleStyle;
|
uniform int cycleStyle;
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ struct Config {
|
|||||||
glyphTextureGridSize : vec2<i32>,
|
glyphTextureGridSize : vec2<i32>,
|
||||||
glyphHeightToWidth : f32,
|
glyphHeightToWidth : f32,
|
||||||
gridSize : vec2<f32>,
|
gridSize : vec2<f32>,
|
||||||
showComputationTexture : i32,
|
showDebugView : i32,
|
||||||
|
|
||||||
// compute-specific properties
|
// compute-specific properties
|
||||||
brightnessThreshold : f32,
|
brightnessThreshold : f32,
|
||||||
@@ -138,11 +138,11 @@ fn getRainTime(simTime : f32, glyphPos : vec2<f32>) -> f32 {
|
|||||||
columnSpeedOffset = 0.5;
|
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 wobble((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(rainTime);
|
||||||
if (bool(config.loops)) {
|
if (bool(config.loops)) {
|
||||||
value = 1.0 - fract(rainTime);
|
value = 1.0 - fract(rainTime);
|
||||||
}
|
}
|
||||||
@@ -213,10 +213,12 @@ fn applyRippleEffect(effect : f32, simTime : f32, screenPos : vec2<f32>) -> f32
|
|||||||
|
|
||||||
// Compute shader main functions
|
// Compute shader main functions
|
||||||
|
|
||||||
fn computeShine (simTime : f32, isFirstFrame : bool, glyphPos : vec2<f32>, screenPos : vec2<f32>, previous : vec4<f32>, previousBelow : vec4<f32>) -> vec4<f32> {
|
fn computeShine (simTime : f32, isFirstFrame : bool, glyphPos : vec2<f32>, screenPos : vec2<f32>, previous : vec4<f32>) -> vec4<f32> {
|
||||||
|
|
||||||
// Determine the glyph's local time.
|
// Determine the glyph's local time.
|
||||||
var rainTime = getRainTime(simTime, glyphPos);
|
var rainTime = getRainTime(simTime, glyphPos);
|
||||||
|
var rainTimeBelow = getRainTime(simTime, glyphPos + vec2<f32>(0., -1.));
|
||||||
|
var cursor = select(0.0, 1.0, fract(rainTime) < fract(rainTimeBelow));
|
||||||
|
|
||||||
// Rain time is the backbone of this effect.
|
// Rain time is the backbone of this effect.
|
||||||
|
|
||||||
@@ -234,8 +236,6 @@ fn computeShine (simTime : f32, isFirstFrame : bool, glyphPos : vec2<f32>, scree
|
|||||||
var effect = 0.0;
|
var effect = 0.0;
|
||||||
effect = applyRippleEffect(effect, simTime, screenPos); // Round or square ripples across the grid
|
effect = applyRippleEffect(effect, simTime, screenPos); // Round or square ripples across the grid
|
||||||
|
|
||||||
var previousBrightnessBelow = previousBelow.r;
|
|
||||||
var cursor = select(0.0, 1.0, brightness > previousBrightnessBelow);
|
|
||||||
|
|
||||||
// Blend the glyph's brightness with its previous brightness, so it winks on and off organically
|
// Blend the glyph's brightness with its previous brightness, so it winks on and off organically
|
||||||
if (!isFirstFrame) {
|
if (!isFirstFrame) {
|
||||||
@@ -290,17 +290,16 @@ fn computeSymbol (simTime : f32, isFirstFrame : bool, glyphPos : vec2<f32>, scre
|
|||||||
}
|
}
|
||||||
|
|
||||||
var i = row * i32(config.gridSize.x) + column;
|
var i = row * i32(config.gridSize.x) + column;
|
||||||
var below = (row - 1) * i32(config.gridSize.x) + column;
|
|
||||||
|
|
||||||
var simTime = time.seconds * config.animationSpeed;
|
var simTime = time.seconds * config.animationSpeed;
|
||||||
|
var isFirstFrame = time.frames == 0;
|
||||||
|
|
||||||
// Update the cell
|
// Update the cell
|
||||||
var isFirstFrame = time.frames == 0;
|
|
||||||
var glyphPos = vec2<f32>(f32(column), f32(row));
|
var glyphPos = vec2<f32>(f32(column), f32(row));
|
||||||
var screenPos = glyphPos / config.gridSize;
|
var screenPos = glyphPos / config.gridSize;
|
||||||
|
|
||||||
var cell = cells_RW.cells[i];
|
var cell = cells_RW.cells[i];
|
||||||
cell.shine = computeShine(simTime, isFirstFrame, glyphPos, screenPos, cell.shine, cells_RW.cells[below].shine);
|
cell.shine = computeShine(simTime, isFirstFrame, glyphPos, screenPos, cell.shine);
|
||||||
cell.symbol = computeSymbol(simTime, isFirstFrame, glyphPos, screenPos, cell.symbol, cell.shine);
|
cell.symbol = computeSymbol(simTime, isFirstFrame, glyphPos, screenPos, cell.symbol, cell.shine);
|
||||||
cells_RW.cells[i] = cell;
|
cells_RW.cells[i] = cell;
|
||||||
}
|
}
|
||||||
@@ -442,11 +441,18 @@ fn getSymbolUV(symbol : i32) -> vec2<f32> {
|
|||||||
|
|
||||||
var output : FragOutput;
|
var output : FragOutput;
|
||||||
|
|
||||||
if (bool(config.showComputationTexture)) {
|
if (bool(config.showDebugView)) {
|
||||||
output.color = vec4<f32>(cell.shine.r - alpha, cell.shine.g * alpha, cell.shine.a - alpha, 1.0);
|
brightness *= 2.0;
|
||||||
if (volumetric) {
|
output.color = vec4<f32>(
|
||||||
output.color.g *= 0.9 + 0.1;
|
vec3<f32>(
|
||||||
}
|
cell.shine.b,
|
||||||
|
vec2<f32>(
|
||||||
|
brightness,
|
||||||
|
clamp(0.0, 1.0, pow(brightness * 0.9, 6.0))
|
||||||
|
) * (1.0 - cell.shine.b)
|
||||||
|
) * alpha,
|
||||||
|
1.0
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
output.color = vec4<f32>(input.channel * brightness * alpha, 1.0);
|
output.color = vec4<f32>(input.channel * brightness * alpha, 1.0);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user