This commit is contained in:
Andras Schmelczer 2026-05-16 15:05:35 +01:00
parent 70423851ba
commit 1fe5015056
55 changed files with 2077 additions and 726 deletions

View file

@ -7,24 +7,28 @@ struct Settings {
@group(1) @binding(0) var<uniform> settings: Settings;
@group(1) @binding(1) var Sampler: sampler;
@group(1) @binding(2) var trailMap: texture_2d<f32>;
@fragment
fn fragment(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
var current = textureSample(trailMap, Sampler, uv);
fn fragment(@builtin(position) position: vec4<f32>) -> @location(0) vec4<f32> {
let textureSize = vec2<i32>(textureDimensions(trailMap, 0));
let pixel = clamp(vec2<i32>(position.xy), vec2<i32>(0), textureSize - vec2<i32>(1));
var current = textureLoad(trailMap, pixel, 0);
let random = random_from_pixel(pixel);
let trailWeight = diffusion_weight(random, settings.inverseDiffusionRateTrails);
let brushWeight = diffusion_weight(random, settings.inverseDiffusionRateBrush);
current += (
propagate(uv, vec2(-1.0, -1.0), current)
+ propagate(uv, vec2(-1.0, 1.0), current)
+ propagate(uv, vec2(1.0, -1.0), current)
+ propagate(uv, vec2(1.0, 1.0), current)
propagate(pixel, textureSize, vec2<i32>(-1, -1), current, trailWeight, brushWeight)
+ propagate(pixel, textureSize, vec2<i32>(-1, 1), current, trailWeight, brushWeight)
+ propagate(pixel, textureSize, vec2<i32>(1, -1), current, trailWeight, brushWeight)
+ propagate(pixel, textureSize, vec2<i32>(1, 1), current, trailWeight, brushWeight)
+ propagate(uv, vec2(-1.0, 0.0), current)
+ propagate(uv, vec2(0.0, -1.0), current)
+ propagate(uv, vec2(1.0, 0.0), current)
+ propagate(uv, vec2(0.0, 1.0), current)
+ propagate(pixel, textureSize, vec2<i32>(-1, 0), current, trailWeight, brushWeight)
+ propagate(pixel, textureSize, vec2<i32>(0, -1), current, trailWeight, brushWeight)
+ propagate(pixel, textureSize, vec2<i32>(1, 0), current, trailWeight, brushWeight)
+ propagate(pixel, textureSize, vec2<i32>(0, 1), current, trailWeight, brushWeight)
) / 8;
let decayed = clamp(vec4(
@ -36,13 +40,64 @@ fn fragment(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
}
fn propagate(uv: vec2<f32>, offset: vec2<f32>, currentColor: vec4<f32>) -> vec4<f32> {
let neighbour = textureSample(trailMap, Sampler, uv + offset / state.size);
var random = textureSample(noise, noiseSampler, uv + offset / state.size * 0.5).r;
fn propagate(
pixel: vec2<i32>,
textureSize: vec2<i32>,
offset: vec2<i32>,
currentColor: vec4<f32>,
trailWeight: f32,
brushWeight: f32
) -> vec4<f32> {
let neighbour = textureLoad(
trailMap,
clamp(pixel + offset, vec2<i32>(0), textureSize - vec2<i32>(1)),
0
);
let difference = clamp(neighbour - currentColor, vec4(0), vec4(1));
return vec4(
vec3(length(neighbour.rgb) * pow(random, settings.inverseDiffusionRateTrails)),
length(neighbour.a) * pow(random, settings.inverseDiffusionRateBrush)
vec3(length(neighbour.rgb) * trailWeight),
neighbour.a * brushWeight
) * difference;
}
fn random_from_pixel(pixel: vec2<i32>) -> f32 {
let p = vec2<u32>(pixel);
var hash = p.x * 1664525u + p.y * 1013904223u + 374761393u;
hash = (hash ^ (hash >> 16u)) * 2246822519u;
hash = (hash ^ (hash >> 13u)) * 3266489917u;
hash = hash ^ (hash >> 16u);
return f32(hash) * 2.3283064365386963e-10;
}
fn diffusion_weight(random: f32, inverseRate: f32) -> f32 {
let r = clamp(random, 0.0, 1.0);
let r2 = r * r;
let r4 = r2 * r2;
let r8 = r4 * r4;
if inverseRate < 1.0 {
let rootApproximation = r / max(0.5 + r * 0.5, 0.0001);
return mix(
rootApproximation,
r,
clamp((inverseRate - 0.5) * 2.0, 0.0, 1.0)
);
}
if inverseRate < 2.0 {
return mix(r, r2, inverseRate - 1.0);
}
if inverseRate < 4.0 {
return mix(r2, r4, (inverseRate - 2.0) * 0.5);
}
if inverseRate < 8.0 {
return mix(r4, r8, (inverseRate - 4.0) * 0.25);
}
let r16 = r8 * r8;
return mix(r8, r16, clamp((inverseRate - 8.0) * 0.125, 0.0, 1.0))
* min(1.0, 16.0 / inverseRate);
}