7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-03-10 00:25:22 +00:00

Raytracing: convert from linear RGB to sRGB in preview mode.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/17354
This commit is contained in:
Alex Shvartzkop 2025-01-19 23:43:13 +03:00
parent 87c42db898
commit 6b3396ea2d
3 changed files with 92 additions and 66 deletions

View File

@ -48,6 +48,12 @@ COLOR_RGBA::COLOR_RGBA( const SFVEC4F& aColor )
}
COLOR_RGBA::operator SFVEC4F() const
{
return SFVEC4F( r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f );
}
COLOR_RGBA BlendColor( const COLOR_RGBA& aC1, const COLOR_RGBA& aC2 )
{
const unsigned int r = aC1.r + aC2.r;

View File

@ -60,6 +60,8 @@ union COLOR_RGBA
b = aB;
a = aA;
}
operator SFVEC4F() const;
};

View File

@ -37,6 +37,53 @@
#include <wx/log.h>
#ifdef USE_SRGB_SPACE
/// @todo This should be removed in future when KiCad supports a greater version of glm lib.
#define SRGB_GAMA 2.4f
// This function implements the conversion from linear RGB to sRGB
// https://github.com/g-truc/glm/blob/master/glm/gtc/color_space.inl#L12
static SFVEC3F convertLinearToSRGB( const SFVEC3F& aRGBcolor )
{
const float gammaCorrection = 1.0f / SRGB_GAMA;
const SFVEC3F clampedColor = glm::clamp( aRGBcolor, SFVEC3F( 0.0f ), SFVEC3F( 1.0f ) );
return glm::mix( glm::pow( clampedColor, SFVEC3F(gammaCorrection) ) * 1.055f - 0.055f,
clampedColor * 12.92f,
glm::lessThan( clampedColor, SFVEC3F(0.0031308f) ) );
}
static SFVEC4F convertLinearToSRGBA( const SFVEC4F& aRGBAcolor )
{
return SFVEC4F( convertLinearToSRGB( SFVEC3F( aRGBAcolor ) ), aRGBAcolor.a );
}
// This function implements the conversion from sRGB to linear RGB
// https://github.com/g-truc/glm/blob/master/glm/gtc/color_space.inl#L35
SFVEC3F ConvertSRGBToLinear( const SFVEC3F& aSRGBcolor )
{
const float gammaCorrection = SRGB_GAMA;
return glm::mix( glm::pow( ( aSRGBcolor + SFVEC3F( 0.055f ) )
* SFVEC3F( 0.94786729857819905213270142180095f ),
SFVEC3F( gammaCorrection ) ),
aSRGBcolor * SFVEC3F( 0.07739938080495356037151702786378f ),
glm::lessThanEqual( aSRGBcolor, SFVEC3F( 0.04045f ) ) );
}
SFVEC4F ConvertSRGBAToLinear( const SFVEC4F& aSRGBAcolor )
{
return SFVEC4F( ConvertSRGBToLinear( SFVEC3F( aSRGBAcolor ) ), aSRGBAcolor.a );
}
#endif
RENDER_3D_RAYTRACE_BASE::RENDER_3D_RAYTRACE_BASE( BOARD_ADAPTER& aAdapter, CAMERA& aCamera ) :
RENDER_3D_BASE( aAdapter, aCamera ),
m_postShaderSsao( aCamera )
@ -116,6 +163,19 @@ static inline void SetPixel( uint8_t* p, const COLOR_RGBA& v )
}
static void SetPixelSRGBA( uint8_t* p, const COLOR_RGBA& v )
{
SFVEC4F color = v;
#ifdef USE_SRGB_SPACE
color = convertLinearToSRGB( color );
#endif
COLOR_RGBA rgba( color );
SetPixel( p, rgba );
}
SFVEC4F RENDER_3D_RAYTRACE_BASE::premultiplyAlpha( const SFVEC4F& aInput )
{
return SFVEC4F( aInput.r * aInput.a, aInput.g * aInput.a, aInput.b * aInput.a, aInput.a );
@ -238,53 +298,6 @@ void RENDER_3D_RAYTRACE_BASE::renderTracing( uint8_t* ptrPBO, REPORTER* aStatusR
}
#ifdef USE_SRGB_SPACE
/// @todo This should be removed in future when KiCad supports a greater version of glm lib.
#define SRGB_GAMA 2.4f
// This function implements the conversion from linear RGB to sRGB
// https://github.com/g-truc/glm/blob/master/glm/gtc/color_space.inl#L12
static SFVEC3F convertLinearToSRGB( const SFVEC3F& aRGBcolor )
{
const float gammaCorrection = 1.0f / SRGB_GAMA;
const SFVEC3F clampedColor = glm::clamp( aRGBcolor, SFVEC3F( 0.0f ), SFVEC3F( 1.0f ) );
return glm::mix( glm::pow( clampedColor, SFVEC3F(gammaCorrection) ) * 1.055f - 0.055f,
clampedColor * 12.92f,
glm::lessThan( clampedColor, SFVEC3F(0.0031308f) ) );
}
static SFVEC4F convertLinearToSRGBA( const SFVEC4F& aRGBAcolor )
{
return SFVEC4F( convertLinearToSRGB( SFVEC3F( aRGBAcolor ) ), aRGBAcolor.a );
}
// This function implements the conversion from sRGB to linear RGB
// https://github.com/g-truc/glm/blob/master/glm/gtc/color_space.inl#L35
SFVEC3F ConvertSRGBToLinear( const SFVEC3F& aSRGBcolor )
{
const float gammaCorrection = SRGB_GAMA;
return glm::mix( glm::pow( ( aSRGBcolor + SFVEC3F( 0.055f ) )
* SFVEC3F( 0.94786729857819905213270142180095f ),
SFVEC3F( gammaCorrection ) ),
aSRGBcolor * SFVEC3F( 0.07739938080495356037151702786378f ),
glm::lessThanEqual( aSRGBcolor, SFVEC3F( 0.04045f ) ) );
}
SFVEC4F ConvertSRGBAToLinear( const SFVEC4F& aSRGBAcolor )
{
return SFVEC4F( ConvertSRGBToLinear( SFVEC3F( aSRGBAcolor ) ), aSRGBAcolor.a );
}
#endif
void RENDER_3D_RAYTRACE_BASE::renderFinalColor( uint8_t* ptrPBO, const SFVEC4F& rgbColor,
bool applyColorSpaceConversion )
{
@ -791,6 +804,10 @@ void RENDER_3D_RAYTRACE_BASE::renderPreview( uint8_t* ptrPBO )
{
m_isPreview = true;
m_backgroundColorTop = ConvertSRGBAToLinear( premultiplyAlpha( m_boardAdapter.m_BgColorTop ) );
m_backgroundColorBottom =
ConvertSRGBAToLinear( premultiplyAlpha( m_boardAdapter.m_BgColorBot ) );
std::atomic<size_t> nextBlock( 0 );
std::atomic<size_t> threadsFinished( 0 );
@ -827,8 +844,8 @@ void RENDER_3D_RAYTRACE_BASE::renderPreview( uint8_t* ptrPBO )
// Calculate background gradient color
SFVEC4F bgColor[RAYPACKET_DIM];
SFVEC4F bgTopColor = premultiplyAlpha( m_boardAdapter.m_BgColorTop );
SFVEC4F bgBotColor = premultiplyAlpha( m_boardAdapter.m_BgColorBot );
SFVEC4F bgTopColor = m_backgroundColorTop;
SFVEC4F bgBotColor = m_backgroundColorBottom;
for( unsigned int y = 0; y < RAYPACKET_DIM; ++y )
{
@ -1350,28 +1367,29 @@ void RENDER_3D_RAYTRACE_BASE::renderPreview( uint8_t* ptrPBO )
&ptrPBO[( 4 * x + m_blockPositionsFast[iBlock].x
+ m_realBufferSize.x
* ( m_blockPositionsFast[iBlock].y + 4 * y ) ) * 4];
SetPixel( ptr + 0, cLT );
SetPixel( ptr + 4, BlendColor( cLT, cLRT, cLTC ) );
SetPixel( ptr + 8, cLRT );
SetPixel( ptr + 12, BlendColor( cLRT, cRT, cRTC ) );
SetPixelSRGBA( ptr + 0, cLT );
SetPixelSRGBA( ptr + 4, BlendColor( cLT, cLRT, cLTC ) );
SetPixelSRGBA( ptr + 8, cLRT );
SetPixelSRGBA( ptr + 12, BlendColor( cLRT, cRT, cRTC ) );
ptr += m_realBufferSize.x * 4;
SetPixel( ptr + 0, BlendColor( cLT , cLTB, cLTC ) );
SetPixel( ptr + 4, BlendColor( cLTC, BlendColor( cLT , cC ) ) );
SetPixel( ptr + 8, BlendColor( cC, BlendColor( cLRT, cLTC, cRTC ) ) );
SetPixel( ptr + 12, BlendColor( cRTC, BlendColor( cRT , cC ) ) );
SetPixelSRGBA( ptr + 0, BlendColor( cLT , cLTB, cLTC ) );
SetPixelSRGBA( ptr + 4, BlendColor( cLTC, BlendColor( cLT , cC ) ) );
SetPixelSRGBA( ptr + 8, BlendColor( cC, BlendColor( cLRT, cLTC, cRTC ) ) );
SetPixelSRGBA( ptr + 12, BlendColor( cRTC, BlendColor( cRT , cC ) ) );
ptr += m_realBufferSize.x * 4;
SetPixel( ptr + 0, cLTB );
SetPixel( ptr + 4, BlendColor( cC, BlendColor( cLTB, cLTC, cLBC ) ) );
SetPixel( ptr + 8, cC );
SetPixel( ptr + 12, BlendColor( cC, BlendColor( cRTB, cRTC, cRBC ) ) );
SetPixelSRGBA( ptr + 0, cLTB );
SetPixelSRGBA( ptr + 4, BlendColor( cC, BlendColor( cLTB, cLTC, cLBC ) ) );
SetPixelSRGBA( ptr + 8, cC );
SetPixelSRGBA( ptr + 12, BlendColor( cC, BlendColor( cRTB, cRTC, cRBC ) ) );
ptr += m_realBufferSize.x * 4;
SetPixel( ptr + 0, BlendColor( cLB , cLTB, cLBC ) );
SetPixel( ptr + 4, BlendColor( cLBC, BlendColor( cLB , cC ) ) );
SetPixel( ptr + 8, BlendColor( cC, BlendColor( cLRB, cLBC, cRBC ) ) );
SetPixel( ptr + 12, BlendColor( cRBC, BlendColor( cRB , cC ) ) );
SetPixelSRGBA( ptr + 0, BlendColor( cLB , cLTB, cLBC ) );
SetPixelSRGBA( ptr + 4, BlendColor( cLBC, BlendColor( cLB , cC ) ) );
SetPixelSRGBA( ptr + 8, BlendColor( cC, BlendColor( cLRB, cLBC, cRBC ) ) );
SetPixelSRGBA( ptr + 12, BlendColor( cRBC, BlendColor( cRB , cC ) ) );
}
}
}
@ -1497,7 +1515,7 @@ SFVEC4F RENDER_3D_RAYTRACE_BASE::shadeHit( const SFVEC4F& aBgColor, const RAY& a
1.0 );
}
// Only use the headlight for preview
// Only use the headlight (or whatever the first light is) for preview
if( m_isPreview )
break;
}