From 98e3404129814fb7fc8a1dbbc45123d33f56795c Mon Sep 17 00:00:00 2001 From: facelessuser Date: Fri, 29 Mar 2024 11:13:38 -0600 Subject: [PATCH] Do not optimize ray trace method for far away colors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It turns out, when testing far away _and_ near colors, that optimizing with the smallest angle from origin (achromatic) can yield better results for far color, but worse results for near colors. This is just due to how the perceptual spaces curve through the linear RGB space. But by leaving things as they were previously (tracing from achromatic to the sample and using 4 iterations instead of 3) results are more consistent near to far. Colors nearer to the gamut are often more accurate, but far colors are still below ∆h of 2. It is better to have more accurate near and far colors than gain some speed to converge far colors faster. --- apps/gamut-mapping/methods.js | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/gamut-mapping/methods.js b/apps/gamut-mapping/methods.js index 09d6c34e8..d0b70b137 100644 --- a/apps/gamut-mapping/methods.js +++ b/apps/gamut-mapping/methods.js @@ -199,24 +199,25 @@ const methods = { return methods.raytrace.trace(mapColor); }, trace: (mapColor) => { - let achroma = mapColor.set("c", 0).to("p3-linear").coords; - let gamutColor = mapColor.set("c", 1e-8).to("p3-linear"); + let [light, chroma, hue] = mapColor.coords; + mapColor.c = 0; + let achroma = mapColor.to("p3-linear").coords; + mapColor.c = chroma; + mapColor = mapColor.to("p3-linear"); let raytrace = methods.raytrace.raytrace_box; // Cast a ray from the zero chroma color to the target color. // Trace the line to the RGB cube edge and find where it intersects. // Correct L and h within the perceptual OkLCh after each attempt. - let light = mapColor.coords[0]; - let hue = mapColor.coords[2]; - for (let i = 0; i < 3; i++) { + for (let i = 0; i < 4; i++) { if (i) { - const oklch = gamutColor.oklch; + const oklch = mapColor.oklch; oklch.l = light; oklch.h = hue; } - const intersection = raytrace(achroma, gamutColor.coords); + const intersection = raytrace(achroma, mapColor.coords); if (intersection.length) { - gamutColor.setAll(gamutColor.space, intersection); + mapColor.setAll(mapColor.space, intersection); continue; } @@ -225,9 +226,9 @@ const methods = { } // Remove noise from floating point math by clipping - let coords = gamutColor.coords; - gamutColor.setAll( - gamutColor.space, + let coords = mapColor.coords; + mapColor.setAll( + mapColor.space, [ util.clamp(0.0, coords[0], 1.0), util.clamp(0.0, coords[1], 1.0), @@ -235,7 +236,7 @@ const methods = { ], ); - return gamutColor.to("p3"); + return mapColor.to("p3"); }, raytrace_box: (start, end, bmin = [0, 0, 0], bmax = [1, 1, 1]) => { // Use slab method to detect intersection of ray and box and return intersect.