187 lines
5.7 KiB
HLSL
187 lines
5.7 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
half3 LinearTo709Branchless(half3 lin)
|
|
{
|
|
return min(lin * 4.5, pow(max(lin, 0.018), 0.45) * 1.099 - 0.099);
|
|
}
|
|
|
|
half3 Rec709ToLinear(half3 Color)
|
|
{
|
|
// abs() added to silence compiler warning about computing pow() of negative number (both sides of the select are evaluated).
|
|
return select(Color > 0.081, pow((abs(Color) + 0.099) / 1.099, 1.0 / 0.45), Color / 4.5);
|
|
}
|
|
|
|
half3 LinearToSrgbBranchless(half3 lin)
|
|
{
|
|
return min(lin * 12.92, pow(max(lin, 0.00313067), 1.0/2.4) * 1.055 - 0.055);
|
|
// Possible that mobile GPUs might have native pow() function?
|
|
//return min(lin * 12.92, exp2(log2(max(lin, 0.00313067)) * (1.0/2.4) + log2(1.055)) - 0.055);
|
|
}
|
|
|
|
half LinearToSrgbBranchingChannel(half lin)
|
|
{
|
|
if(lin < 0.00313067) return lin * 12.92;
|
|
return pow(lin, (1.0/2.4)) * 1.055 - 0.055;
|
|
}
|
|
|
|
half3 LinearToSrgbBranching(half3 lin)
|
|
{
|
|
return half3(
|
|
LinearToSrgbBranchingChannel(lin.r),
|
|
LinearToSrgbBranchingChannel(lin.g),
|
|
LinearToSrgbBranchingChannel(lin.b));
|
|
}
|
|
|
|
half3 LinearToSrgb(half3 lin)
|
|
{
|
|
#if FEATURE_LEVEL > FEATURE_LEVEL_ES3_1
|
|
// Branching is faster than branchless on AMD on PC.
|
|
return LinearToSrgbBranching(lin);
|
|
#else
|
|
// Adreno devices(Nexus5) with Android 4.4.2 do not handle branching version well, so always use branchless on Mobile
|
|
return LinearToSrgbBranchless(lin);
|
|
#endif
|
|
}
|
|
|
|
half3 sRGBToLinear( half3 Color )
|
|
{
|
|
// abs() added to silence compiler warning about computing pow() of negative number (both sides of the select are evaluated).
|
|
return select(Color > 0.04045, pow( abs(Color) * (1.0 / 1.055) + 0.0521327, 2.4 ), Color * (1.0 / 12.92));
|
|
}
|
|
|
|
/**
|
|
* @param GammaCurveRatio The curve ratio compared to a 2.2 standard gamma, e.g. 2.2 / DisplayGamma. So normally the value is 1.
|
|
*/
|
|
half3 ApplyGammaCorrection(half3 LinearColor, half GammaCurveRatio)
|
|
{
|
|
// Apply "gamma" curve adjustment.
|
|
half3 CorrectedColor = pow(LinearColor, GammaCurveRatio);
|
|
|
|
#if MAC
|
|
// Note, MacOSX native output is raw gamma 2.2 not sRGB!
|
|
CorrectedColor = pow(CorrectedColor, 1.0/2.2);
|
|
#else
|
|
#if USE_709
|
|
// Didn't profile yet if the branching version would be faster (different linear segment).
|
|
CorrectedColor = LinearTo709Branchless(CorrectedColor);
|
|
#else
|
|
CorrectedColor = LinearToSrgb(CorrectedColor);
|
|
#endif
|
|
#endif
|
|
|
|
return CorrectedColor;
|
|
}
|
|
|
|
//
|
|
// Generic log lin transforms
|
|
//
|
|
float3 LogToLin( float3 LogColor )
|
|
{
|
|
const float LinearRange = 14;
|
|
const float LinearGrey = 0.18;
|
|
const float ExposureGrey = 444;
|
|
|
|
// Using stripped down, 'pure log', formula. Parameterized by grey points and dynamic range covered.
|
|
float3 LinearColor = exp2( ( LogColor - ExposureGrey / 1023.0 ) * LinearRange ) * LinearGrey;
|
|
//float3 LinearColor = 2 * ( pow(10.0, ((LogColor - 0.616596 - 0.03) / 0.432699)) - 0.037584 ); // SLog
|
|
//float3 LinearColor = ( pow( 10, ( 1023 * LogColor - 685 ) / 300) - .0108 ) / (1 - .0108); // Cineon
|
|
//LinearColor = max( 0, LinearColor );
|
|
|
|
return LinearColor;
|
|
}
|
|
|
|
float3 LinToLog( float3 LinearColor )
|
|
{
|
|
const float LinearRange = 14;
|
|
const float LinearGrey = 0.18;
|
|
const float ExposureGrey = 444;
|
|
|
|
// Using stripped down, 'pure log', formula. Parameterized by grey points and dynamic range covered.
|
|
float3 LogColor = log2(LinearColor) / LinearRange - log2(LinearGrey) / LinearRange + ExposureGrey / 1023.0; // scalar: 3log2 3mad
|
|
//float3 LogColor = (log2(LinearColor) - log2(LinearGrey)) / LinearRange + ExposureGrey / 1023.0;
|
|
//float3 LogColor = log2( LinearColor / LinearGrey ) / LinearRange + ExposureGrey / 1023.0;
|
|
//float3 LogColor = (0.432699 * log10(0.5 * LinearColor + 0.037584) + 0.616596) + 0.03; // SLog
|
|
//float3 LogColor = ( 300 * log10( LinearColor * (1 - .0108) + .0108 ) + 685 ) / 1023; // Cineon
|
|
LogColor = saturate( LogColor );
|
|
|
|
return LogColor;
|
|
}
|
|
|
|
//
|
|
// Pseudo-ACES 100 nit transforms
|
|
//
|
|
float
|
|
aces100nitFitInverseFloat(float x)
|
|
{
|
|
x = max(0.f, min(0.99f, x));
|
|
//float c = ((-6.32456e-8*pow((-21510484096000.0*x*x + 26714646293200.0*x + 27735750507.0), 0.5) -0.146704*x + 0.0083284)) * rcp( x - 1.01654);
|
|
float c = ( -0.632456 * sqrt( -0.21510484096 *x*x + 0.267146462932 * x + 0.00027735750507 ) - 0.146704 * x + 0.0083284 ) / ( x - 1.01654 );
|
|
|
|
// Clamp to half float range
|
|
return max(0.f, min(65504.f, c));
|
|
}
|
|
|
|
float3
|
|
aces100nitFitInverse(float3 FilmColor)
|
|
{
|
|
float3 inverse;
|
|
inverse.r = aces100nitFitInverseFloat(FilmColor.r);
|
|
inverse.g = aces100nitFitInverseFloat(FilmColor.g);
|
|
inverse.b = aces100nitFitInverseFloat(FilmColor.b);
|
|
return inverse;
|
|
}
|
|
|
|
//
|
|
// Dolby PQ transforms
|
|
//
|
|
float3
|
|
ST2084ToLinear(float3 pq)
|
|
{
|
|
const float m1 = 0.1593017578125; // = 2610. / 4096. * .25;
|
|
const float m2 = 78.84375; // = 2523. / 4096. * 128;
|
|
const float c1 = 0.8359375; // = 2392. / 4096. * 32 - 2413./4096.*32 + 1;
|
|
const float c2 = 18.8515625; // = 2413. / 4096. * 32;
|
|
const float c3 = 18.6875; // = 2392. / 4096. * 32;
|
|
const float C = 10000.;
|
|
|
|
float3 Np = pow( pq, 1./m2 );
|
|
float3 L = Np - c1;
|
|
L = max(0., L);
|
|
L = L / (c2 - c3 * Np);
|
|
L = pow( L, 1./m1 );
|
|
float3 P = L * C;
|
|
|
|
return P;
|
|
}
|
|
|
|
float3
|
|
LinearToST2084(float3 lin)
|
|
{
|
|
const float m1 = 0.1593017578125; // = 2610. / 4096. * .25;
|
|
const float m2 = 78.84375; // = 2523. / 4096. * 128;
|
|
const float c1 = 0.8359375; // = 2392. / 4096. * 32 - 2413./4096.*32 + 1;
|
|
const float c2 = 18.8515625; // = 2413. / 4096. * 32;
|
|
const float c3 = 18.6875; // = 2392. / 4096. * 32;
|
|
const float C = 10000.;
|
|
|
|
float3 L = lin/C;
|
|
float3 Lm = pow(L, m1);
|
|
float3 N1 = ( c1 + c2 * Lm );
|
|
float3 N2 = ( 1.0 + c3 * Lm );
|
|
float3 N = N1 * rcp(N2);
|
|
float3 P = pow( N, m2 );
|
|
|
|
return P;
|
|
}
|
|
|
|
//
|
|
// Sony S-Log3
|
|
//
|
|
float3
|
|
SLog3ToLinear(float3 Value)
|
|
{
|
|
return select((Value >= 171.2102946929f / 1023.0f), (pow(10.0f, (Value * 1023.0f - 420.f) / 261.5f)) * 0.19f - 0.01f, (Value * 1023.0f - 95.0f) * 0.01125000f / (171.2102946929f - 95.0f));
|
|
}
|