From ef41d9f672506e8895f5ea434892762b8e87908f Mon Sep 17 00:00:00 2001 From: Jeremy Selan Date: Tue, 28 Mar 2023 16:06:17 -0700 Subject: [PATCH] color_helpers: Update color math --- src/color_helpers.cpp | 64 ++++++++++++++++++++----------------------- src/color_helpers.h | 6 ++-- 2 files changed, 33 insertions(+), 37 deletions(-) diff --git a/src/color_helpers.cpp b/src/color_helpers.cpp index f41a0346b..2c13570fe 100644 --- a/src/color_helpers.cpp +++ b/src/color_helpers.cpp @@ -215,10 +215,11 @@ void calcColorTransform( uint16_t * pRgbxData1d, int nLutSize1d, glm::mat3 xyz_from_dest = normalised_primary_matrix( dest.primaries, dest.white, 1.f ); glm::mat3 dest_from_xyz = glm::inverse( xyz_from_dest ); glm::mat3 xyz_from_source = normalised_primary_matrix( source.primaries, source.white, 1.f ); - // TODO: include color adaptation matrix if white point conversion is needed - glm::mat3 dest_from_source = dest_from_xyz * xyz_from_source; + glm::mat3 dest_from_source = dest_from_xyz * xyz_from_source; // Absolute colorimetric mapping // Generate shaper lut (for now, identity) + // TODO: if source EOTF doest match dest EOTF, generate a proper shaper lut (and the inverse) + // and then compute a shaper-aware 3DLUT if ( pRgbxData1d ) { float flScale = 1.f / ( (float) nLutSize1d - 1.f ); @@ -236,13 +237,13 @@ void calcColorTransform( uint16_t * pRgbxData1d, int nLutSize1d, if ( pRgbxData3d ) { - int nOutOfGamut = 0; float flScale = 1.f / ( (float) nLutEdgeSize3d - 1.f ); + // Precalc night mode scalars // amount and saturation are overdetermined but we separate the two as they conceptually represent // different quantities, and this preserves forwards algorithmic compatibility glm::vec3 nightModeMultHSV( nightmode.hue, clamp01( nightmode.saturation * nightmode.amount ), 1.f ); - glm::vec3 vNightModeGammaMult = hsv_to_rgb( nightModeMultHSV ); + glm::vec3 vNightModeMultLinear = glm::pow( hsv_to_rgb( nightModeMultHSV ), glm::vec3( 2.2f ) ); for ( int nBlue=0; nBlue COLOR 0.5 // Generic wide gamut display --> COLOR 1.0 - displaycolorimetry_t narrowGamutGeneric; - narrowGamutGeneric.primaries = { { 0.64f, 0.33f }, { 0.30f, 0.60f }, { 0.15f, 0.06f } }; // BT.709 - narrowGamutGeneric.white = { 0.3127f, 0.3290f }; // D65 - narrowGamutGeneric.eotf = EOTF::Gamma22; - displaycolorimetry_t wideGamutGeneric; wideGamutGeneric.primaries = { { 0.6825f, 0.3165f }, { 0.241f, 0.719f }, { 0.138f, 0.050f } }; wideGamutGeneric.white = { 0.3127f, 0.3290f }; // D65 wideGamutGeneric.eotf = EOTF::Gamma22; - colormapping_t mappingWideGamut; - mappingWideGamut.blendEnableMinSat = 0.75f; - mappingWideGamut.blendEnableMaxSat = 1.0f; - mappingWideGamut.blendAmountMin = 0.0f; - mappingWideGamut.blendAmountMax = 0.5f; + // Assume linear saturation computation + colormapping_t mapSmoothToCubeLinearSat; + mapSmoothToCubeLinearSat.blendEnableMinSat = 0.7f; + mapSmoothToCubeLinearSat.blendEnableMaxSat = 1.0f; + mapSmoothToCubeLinearSat.blendAmountMin = 0.0f; + mapSmoothToCubeLinearSat.blendAmountMax = 1.f; - colormapping_t mappingNone; - mappingNone.blendEnableMinSat = 0.65f; - mappingNone.blendEnableMaxSat = 0.90f; - mappingNone.blendAmountMin = 0.0f; - mappingNone.blendAmountMax = 0.0f; + // Assume linear saturation computation + colormapping_t mapPartialToCubeLinearSat; + mapPartialToCubeLinearSat.blendEnableMinSat = 0.7f; + mapPartialToCubeLinearSat.blendEnableMaxSat = 1.0f; + mapPartialToCubeLinearSat.blendAmountMin = 0.0f; + mapPartialToCubeLinearSat.blendAmountMax = 0.25; if ( flSDRGamutWideness < 0.5f ) { float t = cfit( flSDRGamutWideness, 0.f, 0.5f, 0.0f, 1.0f ); - *pSynetheticInputColorimetry = lerp( nativeDisplayOutput, narrowGamutGeneric, t ); - *pSyntheticColorMapping = mappingNone; + *pSynetheticInputColorimetry = lerp( nativeDisplayOutput, wideGamutGeneric, t ); + *pSyntheticColorMapping = mapSmoothToCubeLinearSat; } else { float t = cfit( flSDRGamutWideness, 0.5f, 1.0f, 0.0f, 1.0f ); - *pSynetheticInputColorimetry = lerp( narrowGamutGeneric, wideGamutGeneric, t ); - *pSyntheticColorMapping = lerp( mappingNone, mappingWideGamut, t ); + *pSynetheticInputColorimetry = wideGamutGeneric; + *pSyntheticColorMapping = lerp( mapSmoothToCubeLinearSat, mapPartialToCubeLinearSat, t ); } } diff --git a/src/color_helpers.h b/src/color_helpers.h index 88f70bac0..acd8adee5 100644 --- a/src/color_helpers.h +++ b/src/color_helpers.h @@ -117,6 +117,8 @@ colormapping_t lerp( const colormapping_t & a, const colormapping_t & b, float t // I.e., for a shaper lut with 256 input colors nLutSize1d = 256, countof(pRgbxData1d) = 1024 // nLutEdgeSize3d is the number of color entries, per edge, in the 3d lut // I.e., for a 17x17x17 lut nLutEdgeSize3d = 17, countof(pRgbxData3d) = 19652 +// +// If the white points differ, this performs an absolute colorimetric match void calcColorTransform( uint16_t * pRgbxData1d, int nLutSize1d, uint16_t * pRgbxData3d, int nLutEdgeSize3d, @@ -177,14 +179,14 @@ nits_to_u16_dark(float nits) static constexpr displaycolorimetry_t displaycolorimetry_709_gamma22 { - .primaries = { { 0.64f, 0.33f }, { 0.30f, 0.60f }, { 0.15f, 0.06f } }, // BT.709 + .primaries = { { 0.64f, 0.33f }, { 0.30f, 0.60f }, { 0.15f, 0.06f } }, .white = { 0.3127f, 0.3290f }, // D65 .eotf = EOTF::Gamma22, }; static constexpr displaycolorimetry_t displaycolorimetry_2020_pq { - .primaries = { { 0.708f, 0.292f }, { 0.170f, 0.797f }, { 0.131f, 0.046f } }, // BT.709 + .primaries = { { 0.708f, 0.292f }, { 0.170f, 0.797f }, { 0.131f, 0.046f } }, .white = { 0.3127f, 0.3290f }, // D65 .eotf = EOTF::PQ, };