Code: Select all
bool enableWhiteBalance < string UIName = "EnableWhiteBalance"; > = {true}
float catType
<
string UIName = "ChromaticAdaptationTransformationType";
string UIWidget = "Spinner";
float UIMin = 0.0f;
float UIMax = 5.0f;
float UIStep = 1.0f;
> = {1.0f};
float catClampXMax
<
string UIName = "ChromaticAdaptationXMax";
string UIWidget = "Spinner";
float UIMin = 0.0f;
float UIMax = 5.0f;
float UIStep = 1.02f;
> = {0.01f};
float catClampXMin
<
string UIName = "ChromaticAdaptationXMin";
string UIWidget = "Spinner";
float UIMin = 0.0f;
float UIMax = 5.0f;
float UIStep = 0.85f;
> = {0.01f};
float catClampZMax
<
string UIName = "ChromaticAdaptationZMax";
string UIWidget = "Spinner";
float UIMin = 0.0f;
float UIMax = 5.0f;
float UIStep = 1.07f;
> = {0.01f};
float catClampZMin
<
string UIName = "ChromaticAdaptationZMin";
string UIWidget = "Spinner";
float UIMin = 0.0f;
float UIMax = 5.0f;
float UIStep = 0.95f;
> = {0.01f};
Code: Select all
//sRGB D65, RGB must be linear and in range [0,1]
//output cover whole value range[0,1], z may exceed 1
//http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
float3 RGB2XYZ(float3 color)
{
static const float3x3 mat = float3x3(
0.412453, 0.357580, 0.180423,
0.212671, 0.715160, 0.072169,
0.019334, 0.119193, 0.950227);
return mul(mat, color);
}
float3 XYZ2RGB(float3 color)
{
static const float3x3 mat = float3x3(
3.240479, -1.53715, -0.498535,
-0.969256, 1.875991, 0.041556,
0.055648, -0.204043, 1.057311);
return mul(mat, color);
}
float2 XYZ2xy(float3 i)
{
float2 o = i.xy;
float s = i.x + i.y + i.z;
return o/s;
}
float3 xyY2XYZ(float3 i)
{
float3 o;
o.y = i.z/i.y;
o.x = i.x*o.y;
o.z = (1.0-i.x-i.y)*o.y;
o.z = o.y-i.x*o.y-i.y*o.y;
o.y = i.z;
return o;
}
Code: Select all
//https://web.stanford.edu/~sujason/ColorBalancing/
float3x3 cbCAT(float3 xyz_est, float3 xyz_target, float type)
{
// the following are mostly taken from S. Bianco. "Two New von Kries Based
// Chromatic Adapatation Transforms Found by Numerical Optimization."
float3x3 xfm;
float3x3 xfm_inv;
[branch]if(type == 0)
{
//vonKries Hunt-Pointer-Estevez normalized to D65
xfm = float3x3(0.40024, 0.7076,-0.08081,
-0.2263, 1.16532, 0.0457,
0, 0, 0.91822);
xfm_inv = float3x3(1.85994, -1.12938, 0.2198974,
0.36119, 0.63881, -0.00000637,
0, 0, 1.089);
}
else if(type == 1.0)
{
//bradford
xfm = float3x3(0.8951, 0.2664, -0.1614,
-0.7502, 1.7135, 0.0367,
0.0389, -0.0685, 1.0296);
xfm_inv = float3x3(0.98699, -0.147054, 0.15996,
0.4323, 0.51836, 0.04929,
-0.00852866, 0.04004282, 0.9684867);
}
else if(type == 2.0)
{
//sharp
xfm = float3x3(1.2694, -0.0988, -0.1706,
-0.8364, 1.8006, 0.0357,
0.0297, -0.0315, 1.0018);
xfm_inv = float3x3(0.8156333, 0.0471547788, 0.137216627,
0.379114399, 0.5769424, 0.04400087,
-0.01226, 0.016743, 0.99552);
}
else if(type == 3.0)
{
//cmccat2000
xfm = float3x3(0.7982, 0.3389, -0.1371,
-0.5918, 1.5512, 0.0406,
0.0008, 0.239, 0.9753);
xfm_inv = float3x3(1.0623, -0.256743, 0.16,
0.40792, 0.55, 0.03443688,
-0.100833, -0.1346262, 1.01675543);
}
else if(type == 4.0)
{
//cat02
xfm = float3x3(0.7328, 0.4296, -0.1624,
-0.7036, 1.6975, 0.0061,
0.0030, 0.0136, 0.9834);
xfm_inv = float3x3(1.09612382, -0.278869, 0.1827452,
0.45436904, 0.4735331543, 0.0720978,
-0.0096276, -0.005698, 1.01532564);
}
else
{
//XYZ Scale
xfm = float3x3(1, 0, 0, 0, 1, 0, 0, 0, 1);
xfm_inv = float3x3(1, 0, 0, 0, 1, 0, 0, 0, 1);
}
float3 gain = mul(xfm, xyz_target)/mul(xfm, xyz_est);
gain.x = clamp(gain.x, catClampXMin, catClampXMax);
gain.z = clamp(gain.z, catClampZMin, catClampZMax);
float3x3 gainMat = float3x3(gain.x,0,0,0,gain.y,0,0,0,gain.z);
float3x3 outMat = mul(xfm_inv, mul(gainMat, xfm));
// outMat = inv(sRGBtoXYZ)*outMat*sRGBtoXYZ;
return outMat;
}
//@color linear rgb [0,1]
//@rgbEst image average rgb, linear, [0,1]
float3 grayWorld(float3 color, float3 rgbEst, float catType)
{
static const float3 xyz_D65 = float3(95.04, 100.0, 108.88);//http://en.wikipedia.org/wiki/D65, normalized Y = 100
float2 xyEst = XYZ2xy(RGB2XYZ(rgbEst));//calculate xy chromaticity
float3 xyzEst = xyY2XYZ(float3(xyEst,100.0));//normalize Y to 100 so D65 luminance comparable
return saturate(XYZ2RGB(mul(cbCAT(xyzEst,xyz_D65,catType), RGB2XYZ(color))));
}
how to use:
take oldrim for example
assume that enb adaptation output average rgb of the image(not work in SSE or FO4, only red channel, any work around?)
first set AdaptationSensitivity=0 in enbseries.ini
then in enbeffect
Code: Select all
// ......
//read enb adaptation in time
float4 Adaptation=tex2D(_s4, 0.5);
// ......
// do auto exposure
// ......
// do tonemap
// ......
[branch]if(enableWhiteBalance)
{
float avgPeak = max3(Adaptation);
float avgPeakN = avgPeak/(avgPeak+1.0);
float3 avgRgb = Adaptation.rgb * avgPeakN / avgPeak;
color.rgb = grayWorld(color.rgb, avgRgb, catType);
}