Adding "glint", the shapes that appear on top of the glyphs in the Resurrections opening titles.

This commit is contained in:
Rezmason
2022-09-17 01:24:23 -07:00
parent 6a3d38e965
commit 9c2d6d7ed8
17 changed files with 122 additions and 39 deletions

View File

@@ -17,14 +17,11 @@ Playdate version
Maybe crank sounds? Not sure yet Maybe crank sounds? Not sure yet
Support Resurrections anomaly streaks Support Resurrections anomaly streaks
Kind of like the cursor: new rain pass output channel, new config prop grit texture multiply
MSDF
They should line up in Photoshop without too much trouble, actually
Texture
Maybe give normal Matrix code a pixel grill texture
Lighting Lighting
Different parts of a streak glow at different intensities, at different times Different parts of a streak glow at different intensities, at different times
The streaks often dim slower, ie. are brighter, than the glyphs beneath them The streaks often dim slower, ie. are brighter, than the glyphs beneath them
Different brightness/contrast?
Imagine they're metallic or something Imagine they're metallic or something
Support Resurrections SDF bevel and "lights" Support Resurrections SDF bevel and "lights"

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

View File

@@ -26,6 +26,7 @@ const fonts = {
resurrections: { resurrections: {
// The glyphs seen in the film trilogy // The glyphs seen in the film trilogy
glyphTexURL: "assets/resurrections_msdf.png", glyphTexURL: "assets/resurrections_msdf.png",
glintTexURL: "assets/resurrections_glint_msdf.png",
glyphSequenceLength: 135, glyphSequenceLength: 135,
glyphTextureGridSize: [13, 12], glyphTextureGridSize: [13, 12],
}, },
@@ -57,6 +58,8 @@ const defaults = {
backgroundColor: [0, 0, 0], // The color "behind" the glyphs backgroundColor: [0, 0, 0], // The color "behind" the glyphs
isolateCursor: true, // Whether the "cursor"— the brightest glyph at the bottom of a raindrop— has its own color 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 cursorColor: [1.5, 2, 0.9], // The color of the cursor
isolateGlint: false, // Whether the "glint"— highlights on certain symbols in the font— should appear
glintColor: [1, 1, 1], // The color of the glint
volumetric: false, // A mode where the raindrops appear in perspective volumetric: false, // A mode where the raindrops appear in perspective
animationSpeed: 1, // The global rate that all animations progress animationSpeed: 1, // The global rate that all animations progress
forwardSpeed: 0.25, // The speed volumetric rain approaches the eye forwardSpeed: 0.25, // The speed volumetric rain approaches the eye
@@ -188,6 +191,28 @@ const versions = {
{ hsl: [0.375, 1.0, 1.0], at: 1.0 }, { hsl: [0.375, 1.0, 1.0], at: 1.0 },
], ],
}, },
trinity: {
font: "resurrections",
glyphEdgeCrop: 0.1,
cursorColor: [1.4, 2, 1.2],
isolateGlint: true,
glintColor: [2, 1.5, 0.5],
baseBrightness: -0.9,
baseContrast: 1.5,
highPassThreshold: 0,
numColumns: 50,
cycleSpeed: 0.03,
bloomStrength: 0.7,
fallSpeed: 0.3,
paletteEntries: [
{ hsl: [0.4, 0.9, 0.0], at: 0.0 },
{ hsl: [0.4, 1.0, 0.5], at: 1.0 },
],
volumetric: true,
forwardSpeed: 0.2,
raindropLength: 0.3,
density: 0.5,
},
palimpsest: { palimpsest: {
font: "huberfishA", font: "huberfishA",
isolateCursor: false, isolateCursor: false,
@@ -303,6 +328,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) },
cursorColor: { key: "cursorColor", parser: (s) => s.split(",").map(parseFloat) }, cursorColor: { key: "cursorColor", parser: (s) => s.split(",").map(parseFloat) },
glintColor: { key: "glintColor", 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") }, loops: { key: "loops", parser: (s) => s.toLowerCase().includes("true") },
renderer: { key: "renderer", parser: (s) => s }, renderer: { key: "renderer", parser: (s) => s },
@@ -321,8 +347,14 @@ export default (urlParams) => {
.filter(([_, value]) => value != null) .filter(([_, value]) => value != null)
); );
if (validParams.effect != null && validParams.cursorColor == null) { if (validParams.effect != null) {
validParams.cursorColor = [2, 2, 2]; if (validParams.cursorColor == null) {
validParams.cursorColor = [2, 2, 2];
}
if (validParams.glintColor == null) {
validParams.glintColor = [1, 1, 1];
}
} }
const version = validParams.version in versions ? versions[validParams.version] : versions.classic; const version = validParams.version in versions ? versions[validParams.version] : versions.classic;

View File

@@ -65,7 +65,7 @@ const makePalette = (regl, entries) => {
export default ({ regl, config }, inputs) => { export default ({ regl, config }, inputs) => {
const output = makePassFBO(regl, config.useHalfFloat); const output = makePassFBO(regl, config.useHalfFloat);
const palette = makePalette(regl, config.paletteEntries); const palette = makePalette(regl, config.paletteEntries);
const { backgroundColor, cursorColor, ditherMagnitude, bloomStrength } = config; const { backgroundColor, cursorColor, glintColor, ditherMagnitude, bloomStrength } = config;
const palettePassFrag = loadText("shaders/glsl/palettePass.frag.glsl"); const palettePassFrag = loadText("shaders/glsl/palettePass.frag.glsl");
@@ -75,6 +75,7 @@ export default ({ regl, config }, inputs) => {
uniforms: { uniforms: {
backgroundColor, backgroundColor,
cursorColor, cursorColor,
glintColor,
ditherMagnitude, ditherMagnitude,
bloomStrength, bloomStrength,
tex: inputs.primary, tex: inputs.primary,

View File

@@ -116,6 +116,7 @@ export default ({ regl, config, lkg }) => {
// We render the code into an FBO using MSDFs: https://github.com/Chlumsky/msdfgen // We render the code into an FBO using MSDFs: https://github.com/Chlumsky/msdfgen
const msdf = loadImage(regl, config.glyphTexURL); const msdf = loadImage(regl, config.glyphTexURL);
const glintMSDF = loadImage(regl, config.glintTexURL);
const rainPassVert = loadText("shaders/glsl/rainPass.vert.glsl"); const rainPassVert = loadText("shaders/glsl/rainPass.vert.glsl");
const rainPassFrag = loadText("shaders/glsl/rainPass.frag.glsl"); const rainPassFrag = loadText("shaders/glsl/rainPass.frag.glsl");
const output = makePassFBO(regl, config.useHalfFloat); const output = makePassFBO(regl, config.useHalfFloat);
@@ -131,6 +132,7 @@ export default ({ regl, config, lkg }) => {
"brightnessThreshold", "brightnessThreshold",
"brightnessOverride", "brightnessOverride",
"isolateCursor", "isolateCursor",
"isolateGlint",
"glyphEdgeCrop", "glyphEdgeCrop",
"isPolar", "isPolar",
]), ]),
@@ -160,6 +162,7 @@ export default ({ regl, config, lkg }) => {
symbolState: symbolDoubleBuffer.front, symbolState: symbolDoubleBuffer.front,
effectState: effectDoubleBuffer.front, effectState: effectDoubleBuffer.front,
glyphTex: msdf.texture, glyphTex: msdf.texture,
glintTex: glintMSDF.texture,
camera: regl.prop("camera"), camera: regl.prop("camera"),
transform: regl.prop("transform"), transform: regl.prop("transform"),
@@ -201,7 +204,7 @@ export default ({ regl, config, lkg }) => {
{ {
primary: output, primary: output,
}, },
Promise.all([msdf.loaded, rainPassShine.loaded, rainPassSymbol.loaded, rainPassVert.loaded, rainPassFrag.loaded]), Promise.all([msdf.loaded, glintMSDF.loaded, rainPassShine.loaded, rainPassSymbol.loaded, rainPassVert.loaded, rainPassFrag.loaded]),
(w, h) => { (w, h) => {
output.resize(w, h); output.resize(w, h);
const aspectRatio = w / h; const aspectRatio = w / h;

View File

@@ -31,7 +31,7 @@ const prideStripeColors = [
export default ({ regl, config }, inputs) => { export default ({ regl, config }, inputs) => {
const output = makePassFBO(regl, config.useHalfFloat); const output = makePassFBO(regl, config.useHalfFloat);
const { backgroundColor, cursorColor, ditherMagnitude, bloomStrength } = config; const { backgroundColor, cursorColor, glintColor, ditherMagnitude, bloomStrength } = config;
// Expand and convert stripe colors into 1D texture data // Expand and convert stripe colors into 1D texture data
const stripeColors = const stripeColors =
@@ -50,6 +50,7 @@ export default ({ regl, config }, inputs) => {
uniforms: { uniforms: {
backgroundColor, backgroundColor,
cursorColor, cursorColor,
glintColor,
ditherMagnitude, ditherMagnitude,
bloomStrength, bloomStrength,
tex: inputs.primary, tex: inputs.primary,

View File

@@ -30,7 +30,7 @@ const loadImage = (regl, url) => {
let loaded = false; let loaded = false;
return { return {
texture: () => { texture: () => {
if (!loaded) { if (!loaded && url != null) {
console.warn(`texture still loading: ${url}`); console.warn(`texture still loading: ${url}`);
} }
return texture; return texture;

View File

@@ -108,6 +108,7 @@ export default ({ config, device, timeBuffer }) => {
ditherMagnitude: config.ditherMagnitude, ditherMagnitude: config.ditherMagnitude,
backgroundColor: config.backgroundColor, backgroundColor: config.backgroundColor,
cursorColor: config.cursorColor, cursorColor: config.cursorColor,
glintColor: config.glintColor,
}); });
const paletteUniforms = paletteShaderUniforms.Palette; const paletteUniforms = paletteShaderUniforms.Palette;

View File

@@ -26,7 +26,7 @@ const makeConfigBuffer = (device, configUniforms, config, density, gridSize) =>
export default ({ config, device, timeBuffer }) => { export default ({ config, device, timeBuffer }) => {
const { mat4, vec3 } = glMatrix; const { mat4, vec3 } = glMatrix;
const assets = [loadTexture(device, config.glyphTexURL), loadShader(device, "shaders/wgsl/rainPass.wgsl")]; const assets = [loadTexture(device, config.glyphTexURL), loadTexture(device, config.glintTexURL), loadShader(device, "shaders/wgsl/rainPass.wgsl")];
// The volumetric mode multiplies the number of columns // The volumetric mode multiplies the number of columns
// to reach the desired density, and then overlaps them // to reach the desired density, and then overlaps them
@@ -85,7 +85,7 @@ export default ({ config, device, timeBuffer }) => {
let highPassOutput; let highPassOutput;
const loaded = (async () => { const loaded = (async () => {
const [msdfTexture, rainShader] = await Promise.all(assets); const [msdfTexture, glintMSDFTexture, rainShader] = await Promise.all(assets);
const rainShaderUniforms = structs.from(rainShader.code); const rainShaderUniforms = structs.from(rainShader.code);
configBuffer = makeConfigBuffer(device, rainShaderUniforms.Config, config, density, gridSize); configBuffer = makeConfigBuffer(device, rainShaderUniforms.Config, config, density, gridSize);
@@ -143,7 +143,15 @@ export default ({ config, device, timeBuffer }) => {
]); ]);
computeBindGroup = makeBindGroup(device, computePipeline, 0, [configBuffer, timeBuffer, cellsBuffer]); computeBindGroup = makeBindGroup(device, computePipeline, 0, [configBuffer, timeBuffer, cellsBuffer]);
renderBindGroup = makeBindGroup(device, renderPipeline, 0, [configBuffer, timeBuffer, sceneBuffer, linearSampler, msdfTexture.createView(), cellsBuffer]); renderBindGroup = makeBindGroup(device, renderPipeline, 0, [
configBuffer,
timeBuffer,
sceneBuffer,
linearSampler,
msdfTexture.createView(),
glintMSDFTexture.createView(),
cellsBuffer,
]);
})(); })();
const build = (size) => { const build = (size) => {

View File

@@ -79,6 +79,7 @@ export default ({ config, device, timeBuffer }) => {
ditherMagnitude: config.ditherMagnitude, ditherMagnitude: config.ditherMagnitude,
backgroundColor: config.backgroundColor, backgroundColor: config.backgroundColor,
cursorColor: config.cursorColor, cursorColor: config.cursorColor,
glintColor: config.glintColor,
}); });
})(); })();

View File

@@ -20,6 +20,14 @@ const loadTexture = async (device, url) => {
*/ */
const loadTexture = async (device, url) => { const loadTexture = async (device, url) => {
if (url == null) {
return device.createTexture({
size: [1, 1, 1],
format: "rgba8unorm",
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
});
}
const image = new Image(); const image = new Image();
image.crossOrigin = "Anonymous"; image.crossOrigin = "Anonymous";
image.src = url; image.src = url;

View File

@@ -7,7 +7,7 @@ uniform sampler2D palette;
uniform float bloomStrength; uniform float bloomStrength;
uniform float ditherMagnitude; uniform float ditherMagnitude;
uniform float time; uniform float time;
uniform vec3 backgroundColor, cursorColor; uniform vec3 backgroundColor, cursorColor, glintColor;
varying vec2 vUV; varying vec2 vUV;
highp float rand( const in vec2 uv, const in float t ) { highp float rand( const in vec2 uv, const in float t ) {
@@ -26,12 +26,13 @@ void main() {
vec4 brightness = getBrightness(vUV); vec4 brightness = getBrightness(vUV);
// Dither: subtract a random value from the brightness // Dither: subtract a random value from the brightness
brightness -= rand( gl_FragCoord.xy, time ) * ditherMagnitude; brightness -= rand( gl_FragCoord.xy, time ) * ditherMagnitude / 3.0;
// Map the brightness to a position in the palette texture // Map the brightness to a position in the palette texture
gl_FragColor = vec4( gl_FragColor = vec4(
texture2D( palette, vec2(brightness.r, 0.0)).rgb texture2D( palette, vec2(brightness.r, 0.0)).rgb
+ min(cursorColor * brightness.g, vec3(1.0)) + min(cursorColor * brightness.g, vec3(1.0))
+ min(glintColor * brightness.b, vec3(1.0))
+ backgroundColor, + backgroundColor,
1.0 1.0
); );

View File

@@ -6,7 +6,7 @@ precision lowp float;
uniform sampler2D raindropState, symbolState, effectState; uniform sampler2D raindropState, symbolState, effectState;
uniform float numColumns, numRows; uniform float numColumns, numRows;
uniform sampler2D glyphTex; uniform sampler2D glyphTex, glintTex;
uniform float glyphHeightToWidth, glyphSequenceLength, glyphEdgeCrop; uniform float glyphHeightToWidth, glyphSequenceLength, glyphEdgeCrop;
uniform float baseContrast, baseBrightness; uniform float baseContrast, baseBrightness;
uniform float brightnessOverride, brightnessThreshold; uniform float brightnessOverride, brightnessThreshold;
@@ -16,7 +16,7 @@ uniform float slantScale;
uniform bool isPolar; uniform bool isPolar;
uniform bool showDebugView; uniform bool showDebugView;
uniform bool volumetric; uniform bool volumetric;
uniform bool isolateCursor; uniform bool isolateCursor, isolateGlint;
varying vec2 vUV; varying vec2 vUV;
varying vec4 vRaindrop, vSymbol, vEffect; varying vec4 vRaindrop, vSymbol, vEffect;
@@ -87,7 +87,7 @@ vec2 getSymbolUV(float index) {
return vec2(symbolX, symbolY); return vec2(symbolX, symbolY);
} }
float getSymbol(vec2 uv, float index) { vec2 getSymbol(vec2 uv, float index) {
// resolve UV to cropped position of glyph in MSDF texture // resolve UV to cropped position of glyph in MSDF texture
uv = fract(uv * vec2(numColumns, numRows)); uv = fract(uv * vec2(numColumns, numRows));
uv -= 0.5; uv -= 0.5;
@@ -96,9 +96,20 @@ float getSymbol(vec2 uv, float index) {
uv = (uv + getSymbolUV(index)) / glyphTextureGridSize; uv = (uv + getSymbolUV(index)) / glyphTextureGridSize;
// MSDF: calculate brightness of fragment based on distance to shape // MSDF: calculate brightness of fragment based on distance to shape
vec3 dist = texture2D(glyphTex, uv).rgb; vec2 symbol;
float sigDist = median3(dist) - 0.5; {
return clamp(sigDist / fwidth(sigDist) + 0.5, 0., 1.); vec3 dist = texture2D(glyphTex, uv).rgb;
float sigDist = median3(dist) - 0.5;
symbol.r = clamp(sigDist / fwidth(sigDist) + 0.5, 0., 1.);
}
if (isolateGlint) {
vec3 dist = texture2D(glintTex, uv).rgb;
float sigDist = median3(dist) - 0.5;
symbol.g = clamp(sigDist / fwidth(sigDist) + 0.5, 0., 1.);
}
return symbol;
} }
void main() { void main() {
@@ -111,7 +122,7 @@ void main() {
vec4 effectData = volumetric ? vEffect : texture2D( effectState, uv); vec4 effectData = volumetric ? vEffect : texture2D( effectState, uv);
vec2 brightness = getBrightness(raindropData.r, raindropData.g, effectData.r, effectData.g); vec2 brightness = getBrightness(raindropData.r, raindropData.g, effectData.r, effectData.g);
float symbol = getSymbol(uv, symbolData.r); vec2 symbol = getSymbol(uv, symbolData.r);
if (showDebugView) { if (showDebugView) {
gl_FragColor = vec4( gl_FragColor = vec4(
@@ -121,10 +132,10 @@ void main() {
1. - (raindropData.r * 3.), 1. - (raindropData.r * 3.),
1. - (raindropData.r * 8.) 1. - (raindropData.r * 8.)
) * (1. - raindropData.g) ) * (1. - raindropData.g)
) * symbol, ) * symbol.r,
1. 1.
); );
} else { } else {
gl_FragColor = vec4(brightness * symbol, 0., 0.); gl_FragColor = vec4(brightness * symbol.r, brightness.r * symbol.g, 0.);
} }
} }

View File

@@ -7,7 +7,7 @@ uniform float bloomStrength;
uniform sampler2D stripes; uniform sampler2D stripes;
uniform float ditherMagnitude; uniform float ditherMagnitude;
uniform float time; uniform float time;
uniform vec3 backgroundColor, cursorColor; uniform vec3 backgroundColor, cursorColor, glintColor;
varying vec2 vUV; varying vec2 vUV;
highp float rand( const in vec2 uv, const in float t ) { highp float rand( const in vec2 uv, const in float t ) {
@@ -28,11 +28,12 @@ void main() {
vec4 brightness = getBrightness(vUV); vec4 brightness = getBrightness(vUV);
// Dither: subtract a random value from the brightness // Dither: subtract a random value from the brightness
brightness -= rand( gl_FragCoord.xy, time ) * ditherMagnitude; brightness -= rand( gl_FragCoord.xy, time ) * ditherMagnitude / 3.0;
gl_FragColor = vec4( gl_FragColor = vec4(
color * brightness.r color * brightness.r
+ min(cursorColor * brightness.g, 1.0) + min(cursorColor * brightness.g, vec3(1.0))
+ min(glintColor * brightness.b, vec3(1.0))
+ backgroundColor, + backgroundColor,
1.0 1.0
); );

View File

@@ -2,7 +2,8 @@ struct Config {
bloomStrength : f32, bloomStrength : f32,
ditherMagnitude : f32, ditherMagnitude : f32,
backgroundColor : vec3<f32>, backgroundColor : vec3<f32>,
cursorColor : vec3<f32> cursorColor : vec3<f32>,
glintColor : vec3<f32>,
}; };
struct Palette { struct Palette {
@@ -58,7 +59,7 @@ fn getBrightness(uv : vec2<f32>) -> vec4<f32> {
var brightness = getBrightness(uv); var brightness = getBrightness(uv);
// Dither: subtract a random value from the brightness // Dither: subtract a random value from the brightness
brightness -= randomFloat( uv + vec2<f32>(time.seconds) ) * config.ditherMagnitude; brightness -= randomFloat( uv + vec2<f32>(time.seconds) ) * config.ditherMagnitude / 3.0;
// Map the brightness to a position in the palette texture // Map the brightness to a position in the palette texture
var paletteIndex = clamp(i32(brightness.r * 512.0), 0, 511); var paletteIndex = clamp(i32(brightness.r * 512.0), 0, 511);
@@ -66,6 +67,7 @@ fn getBrightness(uv : vec2<f32>) -> vec4<f32> {
textureStore(outputTex, coord, vec4<f32>( textureStore(outputTex, coord, vec4<f32>(
palette.colors[paletteIndex] palette.colors[paletteIndex]
+ min(config.cursorColor * brightness.g, vec3<f32>(1.0)) + min(config.cursorColor * brightness.g, vec3<f32>(1.0))
+ min(config.glintColor * brightness.b, vec3<f32>(1.0))
+ config.backgroundColor, + config.backgroundColor,
1.0 1.0
)); ));

View File

@@ -37,6 +37,7 @@ struct Config {
slantVec : vec2<f32>, slantVec : vec2<f32>,
volumetric : i32, volumetric : i32,
isolateCursor : i32, isolateCursor : i32,
isolateGlint : i32,
loops : i32, loops : i32,
highPassThreshold : f32, highPassThreshold : f32,
}; };
@@ -76,7 +77,8 @@ struct CellData {
@group(0) @binding(2) var<uniform> scene : Scene; @group(0) @binding(2) var<uniform> scene : Scene;
@group(0) @binding(3) var linearSampler : sampler; @group(0) @binding(3) var linearSampler : sampler;
@group(0) @binding(4) var msdfTexture : texture_2d<f32>; @group(0) @binding(4) var msdfTexture : texture_2d<f32>;
@group(0) @binding(5) var<storage, read> cells_RO : CellData; @group(0) @binding(5) var glintMSDFTexture : texture_2d<f32>;
@group(0) @binding(6) var<storage, read> cells_RO : CellData;
// Shader params // Shader params
@@ -401,7 +403,7 @@ fn getSymbolUV(symbol : i32) -> vec2<f32> {
return vec2<f32>(f32(symbolX), f32(symbolY)); return vec2<f32>(f32(symbolX), f32(symbolY));
} }
fn getSymbol(cellUV : vec2<f32>, index : i32) -> f32 { fn getSymbol(cellUV : vec2<f32>, index : i32) -> vec2<f32> {
// resolve UV to cropped position of glyph in MSDF texture // resolve UV to cropped position of glyph in MSDF texture
var uv = fract(cellUV * config.gridSize); var uv = fract(cellUV * config.gridSize);
uv.y = 1.0 - uv.y; // WebGL -> WebGPU y-flip uv.y = 1.0 - uv.y; // WebGL -> WebGPU y-flip
@@ -410,10 +412,22 @@ fn getSymbol(cellUV : vec2<f32>, index : i32) -> f32 {
uv += 0.5; uv += 0.5;
uv = (uv + getSymbolUV(index)) / vec2<f32>(config.glyphTextureGridSize); uv = (uv + getSymbolUV(index)) / vec2<f32>(config.glyphTextureGridSize);
var symbol = vec2<f32>();
// MSDF: calculate brightness of fragment based on distance to shape // MSDF: calculate brightness of fragment based on distance to shape
var dist = textureSample(msdfTexture, linearSampler, uv).rgb; {
var sigDist = median3(dist) - 0.5; var dist = textureSample(msdfTexture, linearSampler, uv).rgb;
return clamp(sigDist / fwidth(sigDist) + 0.5, 0.0, 1.0); var sigDist = median3(dist) - 0.5;
symbol.r = clamp(sigDist / fwidth(sigDist) + 0.5, 0.0, 1.0);
}
if (bool(config.isolateGlint)) {
var dist = textureSample(glintMSDFTexture, linearSampler, uv).rgb;
var sigDist = median3(dist) - 0.5;
symbol.g = clamp(sigDist / fwidth(sigDist) + 0.5, 0.0, 1.0);
}
return symbol;
} }
// Fragment shader // Fragment shader
@@ -446,11 +460,11 @@ fn getSymbol(cellUV : vec2<f32>, index : i32) -> f32 {
1.0 - (cell.raindrop.r * 3.0), 1.0 - (cell.raindrop.r * 3.0),
1.0 - (cell.raindrop.r * 8.0) 1.0 - (cell.raindrop.r * 8.0)
) * (1.0 - cell.raindrop.g) ) * (1.0 - cell.raindrop.g)
) * symbol, ) * symbol.r,
1.0 1.0
); );
} else { } else {
output.color = vec4(brightness * symbol, 0.0, 0.0); output.color = vec4(brightness * symbol.r, brightness.r * symbol.g, 0.0);
} }
var highPassColor = output.color; var highPassColor = output.color;

View File

@@ -2,7 +2,8 @@ struct Config {
bloomStrength : f32, bloomStrength : f32,
ditherMagnitude : f32, ditherMagnitude : f32,
backgroundColor : vec3<f32>, backgroundColor : vec3<f32>,
cursorColor : vec3<f32> cursorColor : vec3<f32>,
glintColor : vec3<f32>,
}; };
struct Time { struct Time {
@@ -56,11 +57,12 @@ fn getBrightness(uv : vec2<f32>) -> vec4<f32> {
var brightness = getBrightness(uv); var brightness = getBrightness(uv);
// Dither: subtract a random value from the brightness // Dither: subtract a random value from the brightness
brightness -= randomFloat( uv + vec2<f32>(time.seconds) ) * config.ditherMagnitude; brightness -= randomFloat( uv + vec2<f32>(time.seconds) ) * config.ditherMagnitude / 3.0;
textureStore(outputTex, coord, vec4<f32>( textureStore(outputTex, coord, vec4<f32>(
color * brightness.r color * brightness.r
+ min(config.cursorColor * brightness.g, vec3<f32>(1.0)) + min(config.cursorColor * brightness.g, vec3<f32>(1.0))
+ min(config.glintColor * brightness.b, vec3<f32>(1.0))
+ config.backgroundColor, + config.backgroundColor,
1.0 1.0
)); ));