feat: add shadow coloring

This commit is contained in:
2026-09-18 11:01:29 +02:00
parent 7c347a5abf
commit 2cd06c4219
6 changed files with 129 additions and 35 deletions
+66 -14
View File
@@ -20,12 +20,15 @@ struct Uniforms {
bailout_sq: f32,
is_julia: u32,
palette_id: u32,
shadow_palette_id: u32,
aa_level: u32,
kind: u32,
power: u32,
dc_offset: vec2<f32>,
phoenix_p: vec2<f32>,
lambda_l: vec2<f32>,
de_coloring: u32,
shadow: u32,
};
@group(0) @binding(0) var<uniform> u: Uniforms;
@@ -34,18 +37,18 @@ struct Uniforms {
// Smooth cyclic palettes (Inigo Quilez cosine palettes). Must match the palette
// in mandelbrot.wgsl.
fn palette(id: u32, t: f32) -> vec3<f32> {
if (id == 4u) {
if id == 4u {
return vec3<f32>(t, t, t); // grayscale
}
let a = vec3<f32>(0.5, 0.5, 0.5);
let b = vec3<f32>(0.5, 0.5, 0.5);
var c = vec3<f32>(1.0, 1.0, 1.0);
var d = vec3<f32>(0.00, 0.10, 0.20); // 0: amber / blue
if (id == 1u) {
if id == 1u {
d = vec3<f32>(0.00, 0.33, 0.67); // rainbow
} else if (id == 2u) {
} else if id == 2u {
d = vec3<f32>(0.30, 0.20, 0.20); // warm ember
} else if (id == 3u) {
} else if id == 3u {
c = vec3<f32>(1.0, 1.0, 0.5);
d = vec3<f32>(0.80, 0.90, 0.30); // lime / magenta
}
@@ -62,17 +65,66 @@ fn vs_main(@builtin(vertex_index) idx: u32) -> @builtin(position) vec4<f32> {
return vec4<f32>(verts[idx], 0.0, 1.0);
}
fn load(x: i32, y: i32) -> vec3<f32> {
let dist = textureLoad(data_tex, vec2<i32>(x, y), 0).g;
return vec3<f32>(f32(x), f32(y), dist);
}
fn compute_light(normal: vec3<f32>, light: vec3<f32>) -> vec3<f32> {
return vec3<f32>((dot(normal, normalize(light)) + 0.2) / 1.2);
}
fn uncharted2tonemap(x: vec3<f32>) -> vec3<f32> {
// Paramètres de la courbe de Hable
let A = 0.15; // Shoulder strength
let B = 0.50; // Linear strength
let C = 0.10; // Linear angle
let D = 0.20; // Toe strength
let E = 0.02; // Toe numerator / shoarder angle/etc.
let F = 0.30; // Toe denominator
return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F;
}fn filmic(color: vec3<f32>) -> vec3<f32> {
let exposure_bias = 2.0;
let curr = uncharted2tonemap(color * exposure_bias);
// Valeur blanche maximale de référence
let white_scale = vec3(1.0) / uncharted2tonemap(vec3(4.2));
return curr * white_scale;
}
@fragment
fn fs_main(@builtin(position) pos: vec4<f32>) -> @location(0) vec4<f32> {
let d = textureLoad(data_tex, vec2<i32>(i32(pos.x), i32(pos.y)), 0);
let ci = d.r;
let de = d.g;
let interior_frac = d.b;
if u.shadow != 0u {
if textureLoad(data_tex, vec2<i32>(i32(pos.x), i32(pos.y)), 0).b != 0. {
return vec4<f32>(0., 0.11, 0.54, 1.0);
} else {
let d = array<vec3<f32>, 3>(load(i32(pos.x), i32(pos.y)), load(i32(pos.x + 1), i32(pos.y)), load(i32(pos.x), i32(pos.y + 1)));
let t = fract(ci * u.color_scale + u.color_offset);
var col = palette(u.palette_id, t) * de;
// Anti-alias the set boundary: fade toward black by the fraction of the
// pixel's sub-samples that landed in the interior.
col = col * (1.0 - interior_frac);
return vec4<f32>(col, 1.0);
let normal = normalize(cross(d[1] - d[0], d[2] - d[0]));
var color: vec3<f32>;
if u.shadow_palette_id == 0u {
color = compute_light(normal,vec3<f32>(.5, .5, .5));
} else {
color = compute_light(normal, vec3<f32>(0., .5, .5)) * vec3<f32>(1., 0.5, 0.5) + compute_light(normal, vec3<f32>(0.5, 0., .5)) * vec3<f32>(0.5, 1., 1.);
color = filmic(color);
}
return vec4<f32>(color, 1.0);
}
} else {
let d = textureLoad(data_tex, vec2<i32>(i32(pos.x), i32(pos.y)), 0);
let ci = d.r;
let de = d.g;
let interior_frac = d.b;
let t = fract(ci * u.color_scale + u.color_offset);
var col = palette(u.palette_id, t) * de;
// Anti-alias the set boundary: fade toward black by the fraction of the
// pixel's sub-samples that landed in the interior.
col = col * (1.0 - interior_frac);
return vec4<f32>(col, 1.0);
}
}