Fry3DX/engine/shaders/tonemap.frag
Nexoniarz f3e8eca87b Fry3DX 0.4: an easy 3D modeller
Shapes with live settings, shape editing, knife and hole tools, drawing
shapes onto other objects, combining objects (add / subtract / overlap),
copies, thickness, painting with stickers and layers, a Layout tab, a
Print tab with checks, packed .fry files with autosave, export to GLB,
glTF, FBX, OBJ, 3MF, STL and PLY, folders in Layers, its own crash
screen, and a website for GitHub Pages in docs/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NMSrd5oe1GpUD7E6d825KP
2026-10-19 21:18:35 +02:00

78 lines
3.5 KiB
GLSL
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#version 460
#define KEEL_POST // screen-space: render targets, sampled clamped
#include "backend.glsl"
#include "upsample.glsl"
// HDR scene → display: ambient occlusion, bloom, exposure, ACES filmic curve, a light grade
// (saturation, vignette), then sRGB encoding.
PUSH_BLOCK {
uint scene;
float exposure;
uint ao; // 0 = none
uint bloom; // 0 = none
float bloomStrength;
float saturation;
float vignette;
float sharpen; // after TAA: give back a little crispness (0 = none)
uint depth; // scene depth (1 = sky)
uint ssr; // reflections to add (when TAA didn't), 0 = none
uint adapt; // eye adaptation (1×1 exposure multiplier), 0 = none
uint pad2;
vec4 shafts; // sun shafts: the sun's uv, strength (0 = none)
vec4 sunColor;
} pc;
// Sun shafts (screen-space light scattering, GPU Gems 3 ch. 13): march towards the sun's spot
// on screen, adding up how much open sky lies on the way; air lit by the sun glows there,
// fading with distance from the sun. Started at a per-pixel offset so the steps don't band.
vec3 sunShafts(vec2 uv) {
const int N = 32;
vec2 toSun = pc.shafts.xy - uv;
vec2 stepUv = toSun * (0.85 / float(N));
float jitter = fract(52.9829189 * fract(dot(gl_FragCoord.xy, vec2(0.06711056, 0.00583715))));
vec2 p = uv + stepUv * jitter;
vec3 lit = vec3(0.0);
float w = 1.0, total = 0.0;
for (int i = 0; i < N; ++i, p += stepUv) {
bool inside = all(greaterThanEqual(p, vec2(0.0))) && all(lessThanEqual(p, vec2(1.0)));
if (inside && sampleTexLod(pc.depth, p, 0.0).r >= 1.0) // open sky: its light, the sun's brightest
lit += max(sampleTexLod(pc.scene, p, 0.0).rgb - 1.0, vec3(0.0)) * w;
total += w;
w *= 0.97;
}
vec2 aspect = vec2(float(texSize(pc.scene).x) / float(texSize(pc.scene).y), 1.0);
float fall = exp(-length(toSun * aspect) * 1.5);
return min(lit / total, vec3(8.0)) * fall * pc.shafts.z;
}
layout(location = 0) in vec2 v_uv;
layout(location = 0) out vec4 o_color;
vec3 aces(vec3 x) {
return clamp((x * (2.51 * x + 0.03)) / (x * (2.43 * x + 0.59) + 0.14), 0.0, 1.0);
}
vec3 toSrgb(vec3 c) {
return mix(c * 12.92, 1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055, step(0.0031308, c));
}
void main() {
vec3 hdr = sampleTex(pc.scene, v_uv).rgb;
const ivec2 px = ivec2(v_uv * vec2(texSize(pc.depth)));
if (pc.ssr != 0u) hdr += upsampleDepthAware(pc.ssr, pc.depth, px).rgb;
if (pc.sharpen > 0.0) { // unsharp mask against the 4 neighbours, limited so edges don't ring
vec2 t = 1.0 / vec2(texSize(pc.scene));
vec3 n = sampleTex(pc.scene, v_uv + vec2(t.x, 0)).rgb + sampleTex(pc.scene, v_uv - vec2(t.x, 0)).rgb
+ sampleTex(pc.scene, v_uv + vec2(0, t.y)).rgb + sampleTex(pc.scene, v_uv - vec2(0, t.y)).rgb;
hdr = max(hdr + clamp((hdr - n * 0.25) * pc.sharpen, -0.1 * (hdr + 0.05), 0.1 * (hdr + 0.05)), 0.0);
}
if (pc.ao != 0u) hdr *= upsampleDepthAware(pc.ao, pc.depth, px).r;
if (pc.bloom != 0u) hdr = mix(hdr, sampleTex(pc.bloom, v_uv).rgb, pc.bloomStrength);
if (pc.shafts.z > 0.0) hdr += sunShafts(v_uv);
float exposure = pc.exposure * (pc.adapt != 0u ? sampleTexLod(pc.adapt, vec2(0.5), 0.0).r : 1.0);
vec3 c = aces(hdr * exposure);
float l = dot(c, vec3(0.2126, 0.7152, 0.0722));
c = max(mix(vec3(l), c, pc.saturation), 0.0);
vec2 d = v_uv - 0.5;
c *= 1.0 - pc.vignette * dot(d, d) * 2.0;
o_color = vec4(toSrgb(c), 1.0);
}