gpu-curtains
    Preparing search index...
    toneMappingUtils: "\n// linear <-> sRGB conversions\nfn linearTosRGB(linear: vec3f) -> vec3f {\n return vec3( mix( pow( linear.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), linear.rgb * 12.92, vec3( lessThan3( linear.rgb, vec3( 0.0031308 ) ) ) ) );\n}\n\nfn linearTosRGB_4(linear: vec4f) -> vec4f {\n return vec4( linearTosRGB(linear.rgb), linear.a );\n}\n\nfn sRGBToLinear(srgb: vec3f) -> vec3f {\n if (all(srgb <= vec3(0.04045))) {\n return srgb / vec3(12.92);\n }\n return pow((srgb + vec3(0.055)) / vec3(1.055), vec3(2.4));\n}\n\nfn sRGBToLinear_4(srgb: vec4f) -> vec4f {\n return vec4( sRGBToLinear(srgb.rgb), srgb.a );\n}\n\n// forward: color / (1 + color)\nfn inverseReinhardToneMapping(color: vec3f) -> vec3f {\n return color / max(vec3(1e-5), vec3(1.0) - color);\n}\n\n// source: https://www.cs.utah.edu/docs/techreports/2002/pdf/UUCS-02-001.pdf\nfn ReinhardToneMapping( color: vec3f ) -> vec3f {\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\n\nfn inverseCineonToneMapping(color: vec3f) -> vec3f {\n // Step 1: undo gamma\n let T = pow(color, vec3f(1.0 / 2.2));\n\n // Invert the rational polynomial per channel\n var x = vec3f(0.0);\n for (var i = 0; i < 3; i = i + 1) {\n let t = T[i];\n\n // If t >= 1 → clipped → cannot recover, return max guess\n if (t >= 1.0) {\n x[i] = 1e6; // just put a very large HDR value\n continue;\n }\n\n let A = 6.2 * (t - 1.0);\n let B = 1.7 * t - 0.5;\n let C = 0.06 * t;\n\n let disc = B * B - 4.0 * A * C;\n\n // Solve quadratic (positive root)\n let xval = (-B + sqrt(max(disc, 0.0))) / (2.0 * A);\n\n x[i] = xval;\n }\n\n // Step 3: undo the initial offset clamp\n return x + vec3f(0.004);\n}\n\n// source: http://filmicworlds.com/blog/filmic-tonemapping-operators/\nfn CineonToneMapping( color: vec3f ) -> vec3f {\n\t// filmic operator by Jim Hejl and Richard Burgess-Dawson\n\tlet maxColor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( maxColor * ( 6.2 * maxColor + 0.5 ) ) / ( maxColor * ( 6.2 * maxColor + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\n\nfn inverseKhronosToneMapping(color: vec3f) -> vec3f {\n // iterative solve: approximate original HDR color\n var c = color; // initial guess: LDR\n\n // Do 4–6 iterations (cheap and stable)\n for (var i = 0; i < 5; i = i + 1) {\n let f = KhronosToneMapping(c);\n let error = color - f;\n\n // Step factor (empirically tuned)\n let step = 0.75;\n\n c = c + error * step;\n }\n\n return max(c, vec3f(0.0));\n}\n\n// https://modelviewer.dev/examples/tone-mapping\nfn KhronosToneMapping( color: vec3f ) -> vec3f {\n var toneMapColor = color; \n const startCompression: f32 = 0.8 - 0.04;\n const desaturation: f32 = 0.15;\n var x: f32 = min(toneMapColor.r, min(toneMapColor.g, toneMapColor.b));\n var offset: f32 = select(0.04, x - 6.25 * x * x, x < 0.08);\n toneMapColor = toneMapColor - offset;\n var peak: f32 = max(toneMapColor.r, max(toneMapColor.g, toneMapColor.b));\n if (peak < startCompression) {\n return toneMapColor;\n }\n const d: f32 = 1. - startCompression;\n let newPeak: f32 = 1. - d * d / (peak + d - startCompression);\n toneMapColor *= newPeak / peak;\n let g: f32 = 1. - 1. / (desaturation * (peak - newPeak) + 1.);\n return mix(toneMapColor, newPeak * vec3(1, 1, 1), g);\n}\n" = ...

    Tone mapping utils chunks.